Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Text implementation #18590

Merged
merged 33 commits into from
Jul 2, 2021
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
1b8191b
Regenerate package
andrefcdias Jun 15, 2021
ce22d98
Change files
andrefcdias Jun 15, 2021
617dc75
Migrate package to new converged DX
andrefcdias Jun 15, 2021
21b7d69
Make package private
andrefcdias Jun 16, 2021
2da22fc
Add Text component
andrefcdias Jun 16, 2021
9f91bd0
Merge branch 'master' into text-implementation
andrefcdias Jun 18, 2021
9f35426
Add as, wrap and truncate tests
andrefcdias Jun 18, 2021
d97b9e8
Added block styling prop
tringakrasniqi Jun 21, 2021
f415622
Added italic style prop
tringakrasniqi Jun 21, 2021
c0a327d
Added underline style prop
tringakrasniqi Jun 21, 2021
19fd891
Added strikethrough style prop
tringakrasniqi Jun 21, 2021
c4fe9d9
Added test for multiple style props
tringakrasniqi Jun 21, 2021
817d4ee
Add strikethrough + underline styling
andrefcdias Jun 22, 2021
01a372a
Add size prop
andrefcdias Jun 22, 2021
89d134a
Add font prop
andrefcdias Jun 22, 2021
ac4226a
Add font prop
andrefcdias Jun 22, 2021
d2d9d91
Add align prop
andrefcdias Jun 22, 2021
80e440b
Update types
andrefcdias Jun 22, 2021
d57740d
Fix base story
andrefcdias Jun 22, 2021
79c469d
Added storybook stories for Text props
tringakrasniqi Jun 26, 2021
1c85eba
Changed storybook story with arg controls
tringakrasniqi Jun 27, 2021
f73f6c0
Add documentation for props
andrefcdias Jun 29, 2021
31b5d3c
Limit as prop to specific semantic elements
andrefcdias Jun 29, 2021
27f7cb5
Update API doc
andrefcdias Jun 29, 2021
30b790e
Move default of as prop to the hook
andrefcdias Jul 1, 2021
549cd3a
Remove as prop test
andrefcdias Jul 1, 2021
0d871f0
Update packages/react-text/src/components/Text/useTextStyles.ts
andrefcdias Jul 1, 2021
d1db833
Merge branch 'master' into text-implementation
andrefcdias Jul 1, 2021
f059503
Update API docs
andrefcdias Jul 1, 2021
e6d24b0
Remove as prop test
andrefcdias Jul 1, 2021
94c2c1c
Remove useless comments
andrefcdias Jul 1, 2021
85dac23
Fix API docs (again)
andrefcdias Jul 2, 2021
2f5cd4e
Merge branch 'master' into text-implementation
andrefcdias Jul 2, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/react-text/config/tests.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/** Jest test setup file. */

require('@testing-library/jest-dom');

const { configure } = require('enzyme');
const Adapter = require('enzyme-adapter-react-16');

Expand Down
11 changes: 11 additions & 0 deletions packages/react-text/etc/react-text.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ export type TextDefaultedProps = never;

// @public
export interface TextProps extends ComponentProps, React_2.HTMLAttributes<HTMLElement> {
align?: 'start' | 'center' | 'end' | 'justify';
as?: 'span' | 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'pre';
block?: boolean;
font?: 'base' | 'monospace' | 'numeric';
italic?: boolean;
size?: 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 1000;
strikethrough?: boolean;
truncate?: boolean;
underline?: boolean;
weight?: 'regular' | 'medium' | 'semibold';
wrap?: boolean;
}

// @public
Expand Down
83 changes: 83 additions & 0 deletions packages/react-text/src/components/Text/Text.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { makeStyles } from '@fluentui/react-make-styles';
import * as React from 'react';
import { Text } from './Text';
import { TextProps } from './Text.types';

const useStyles = makeStyles({
container: {
width: '100px',
},
});

export const TextStory = (props: TextProps) => {
const styles = useStyles();
return (
<div className={styles.container}>
<Text {...props}>This is an example of the Text component's usage.</Text>
</div>
);
};

TextStory.argTypes = {
wrap: {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the controls should be generated from types, or did I not understand smth @Hotell ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK this needs to be duplicated for compatibility reasons.

defaultValue: true,
control: 'boolean',
},
truncate: {
defaultValue: false,
control: 'boolean',
},
underline: {
defaultValue: false,
control: 'boolean',
},
block: {
defaultValue: false,
control: 'boolean',
},
italic: {
defaultValue: false,
control: 'boolean',
},
strikethrough: {
defaultValue: false,
control: 'boolean',
},
size: {
defaultValue: 300,
type: { name: 'number', required: false },
control: {
type: 'select',
options: [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000],
},
},
font: {
defaultValue: 'base',
type: { name: 'string', required: false },
control: {
type: 'select',
options: ['base', 'monospace', 'numeric'],
},
},
weight: {
defaultValue: 'regular',
type: { name: 'string', required: false },
control: {
type: 'select',
options: ['regular', 'medium', 'semibold'],
},
},
align: {
defaultValue: 'start',
type: { name: 'string', required: false },
control: {
type: 'select',
options: ['start', 'center', 'end', 'justify'],
},
},
};

export default {
title: 'Components/Text',
component: Text,
};
160 changes: 160 additions & 0 deletions packages/react-text/src/components/Text/Text.test.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// For non-exported types
/* eslint-disable @typescript-eslint/no-explicit-any */
import * as React from 'react';
import { render } from '@testing-library/react';
import { Text } from './Text';
import { isConformant } from '../../common/isConformant';

Expand All @@ -6,4 +10,160 @@ describe('Text', () => {
Component: Text,
displayName: 'Text',
});

it('renders a default state', () => {
andrefcdias marked this conversation as resolved.
Show resolved Hide resolved
const { container, getByText } = render(<Text>Test</Text>);

expect(container).toMatchSnapshot();

const textElement = getByText('Test');
expect(textElement.nodeName).toBe('SPAN');
expect(textElement).toHaveStyle(`
font-family: var(--global-type-fontFamilies-base);
font-size: var(--global-type-fontSizes-base-300);
line-height: var(--global-type-lineHeights-base-300);
font-weight: var(--global-type-fontWeights-regular);
display: inline;
text-align: start;
white-space: normal;
overflow: visible;
text-overflow: clip;
`);
});

it('applies the no wrap styles', () => {
const { getByText } = render(<Text wrap={false}>Test</Text>);

const textElement = getByText('Test');
expect(textElement).toHaveStyle(`
white-space: nowrap;
overflow: hidden;
`);
});

it('applies the truncate style', () => {
const { getByText } = render(<Text truncate>Test</Text>);

const textElement = getByText('Test');
expect(textElement).toHaveStyle(`
text-overflow: ellipsis;
`);
});

it('applies the block style', () => {
const { getByText } = render(<Text block>Test</Text>);

const textElement = getByText('Test');
expect(textElement).toHaveStyle(`
display: block;
`);
});

it('applies the italic style', () => {
const { getByText } = render(<Text italic>Test</Text>);

const textElement = getByText('Test');
expect(textElement).toHaveStyle(`
font-style: italic;
`);
});

it('applies the underline style', () => {
const { getByText } = render(<Text underline>Test</Text>);

const textElement = getByText('Test');
expect(textElement).toHaveStyle(`
text-decoration: underline;
`);
});

it('applies the strikethrough style', () => {
const { getByText } = render(<Text strikethrough>Test</Text>);

const textElement = getByText('Test');
expect(textElement).toHaveStyle(`
text-decoration: line-through;
`);
});

it('applies both strikethrough and underline styles', () => {
const { getByText } = render(
<Text strikethrough underline>
Test
</Text>,
);

const textElement = getByText('Test');
expect(textElement).toHaveStyle(`
text-decoration: line-through underline;
`);
});

it.each([
[100, 'base', '100'],
[200, 'base', '200'],
[300, 'base', '300'],
[400, 'base', '400'],
[500, 'base', '500'],
[600, 'base', '600'],
[700, 'hero', '700'],
[800, 'hero', '800'],
[900, 'hero', '900'],
[1000, 'hero', '1000'],
])('applies the %s token sizing styles', (sizeToken: any, expectedPrefix, expectedValue) => {
const { getByText } = render(<Text size={sizeToken}>Test</Text>);

const textElement = getByText('Test');
expect(textElement).toHaveStyle(`
font-size: var(--global-type-fontSizes-${expectedPrefix}-${expectedValue});
line-height: var(--global-type-lineHeights-${expectedPrefix}-${expectedValue});
`);
});

it.each([
['base', 'base'],
['monospace', 'monospace'],
['numeric', 'numeric'],
])('applies %s font', (input: any, expectedValue) => {
const { getByText } = render(<Text font={input}>Test</Text>);

const textElement = getByText('Test');
expect(textElement).toHaveStyle(`
font-family: var(--global-type-fontFamilies-${expectedValue});
`);
});

it.each([
['regular', 'regular'],
['medium', 'medium'],
['semibold', 'semibold'],
])('applies %s weight', (input: any, expectedValue) => {
const { getByText } = render(<Text weight={input}>Test</Text>);

const textElement = getByText('Test');
expect(textElement).toHaveStyle(`
font-weight: var(--global-type-fontWeights-${expectedValue});
`);
});

it.each([
['start', 'start'],
['center', 'center'],
['end', 'end'],
['justify', 'justify'],
])('applies a %s alignment', (input: any, expectedValue) => {
const { getByText } = render(<Text align={input}>Test</Text>);

const textElement = getByText('Test');
expect(textElement).toHaveStyle(`
text-align: ${expectedValue};
`);
});

it('allows overriding the component being rendered', () => {
const { getByText } = render(<Text as="p">Test</Text>);

const textElement = getByText('Test');
expect(textElement.nodeName).toBe('P');
});
andrefcdias marked this conversation as resolved.
Show resolved Hide resolved
});
2 changes: 1 addition & 1 deletion packages/react-text/src/components/Text/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { useTextStyles } from './useTextStyles';
* Typography and styling abstraction component used to ensure consistency of text.
*/
export const Text = React.forwardRef<HTMLElement, TextProps>((props, ref) => {
const state = useText(props, ref);
const state = useText(props, ref, { as: 'span' });
andrefcdias marked this conversation as resolved.
Show resolved Hide resolved

useTextStyles(state);
return renderText(state);
Expand Down
79 changes: 75 additions & 4 deletions packages/react-text/src/components/Text/Text.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,82 @@ import { ComponentProps, ComponentState } from '@fluentui/react-utilities';
* Text Props
*/
export interface TextProps extends ComponentProps, React.HTMLAttributes<HTMLElement> {
/*
* TODO Add props and slots here
* Any slot property should be listed in the textShorthandProps array below
* Any property that has a default value should be listed in TextDefaultedProps as e.g. 'size' | 'icon'
/**
* Wraps the text content on white spaces.
*
* @defaultvalue true
andrefcdias marked this conversation as resolved.
Show resolved Hide resolved
*/
wrap?: boolean;

/**
* Truncate overflowing text for block displays.
*
* @defaultvalue false
*/
truncate?: boolean;

/**
* Applies a block display for the content.
*
* @defaultvalue false
*/
block?: boolean;

/**
* Applies the italic font style to the content.
*
* @defaultvalue false
*/
italic?: boolean;

/**
* Applies the underline text decoration to the content.
*
* @defaultvalue false
*/
underline?: boolean;

/**
* Applies the strikethrough text decoration to the content.
*
* @defaultvalue false
*/
strikethrough?: boolean;

/**
* Applies font size and line height based on the theme tokens.
*
* @defaultvalue 300
*/
size?: 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 1000;

/**
* Applies the font family to the content.
*
* @defaultvalue base
*/
font?: 'base' | 'monospace' | 'numeric';

/**
* Applies font weight to the content.
*
* @defaultvalue regular
*/
weight?: 'regular' | 'medium' | 'semibold';

/**
* Aligns text based on the parent container.
*
* @defaultvalue start
*/
align?: 'start' | 'center' | 'end' | 'justify';

/**
* Component to be rendered as.
*
* @defaultvalue span
*/
as?: 'span' | 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'pre';
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Text renders a default state 1`] = `
<div>
<span
class=""
>
Test
</span>
</div>
`;
Loading