1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

convert text component to TS (#18329)

* convert text component to TS

* invisible character fix

* storybook fix

* fix types export

* update ButtonBase

* add typeof to objects in TextProps

* fix linting issues

* fix implicit conversion

* lint fix

* add deprecated Text back

* change box ref to any

* fix classnames issue

* account details to use deprecated text reference

* ref update

* make RefObject

* remove RefObject and go back to Ref

* react.ref change to box
This commit is contained in:
Garrett Bear 2023-04-03 10:42:37 -07:00 committed by GitHub
parent 8603a4b067
commit 01057f9824
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 556 additions and 137 deletions

View File

@ -177,7 +177,7 @@ For RTL language support use the `textDirection` prop.
</Canvas> </Canvas>
```jsx ```jsx
import { ButtonBase, ICON_NAMES } from '../../component-library'; import { ButtonBase, ICON_NAMES, TextDirection } from '../../component-library';
<> <>
<ButtonBase <ButtonBase
@ -189,7 +189,7 @@ import { ButtonBase, ICON_NAMES } from '../../component-library';
<ButtonBase <ButtonBase
startIconName={ICON_NAMES.ADD_SQUARE} startIconName={ICON_NAMES.ADD_SQUARE}
endIconName={ICON_NAMES.ARROW_2_RIGHT} endIconName={ICON_NAMES.ARROW_2_RIGHT}
textDirection={TEXT_DIRECTIONS.RIGHT_TO_LEFT} textDirection={TextDirection.RightToLeft}
> >
Button Demo Button Demo
</ButtonBase> </ButtonBase>

View File

@ -7,7 +7,7 @@ import {
Size, Size,
} from '../../../helpers/constants/design-system'; } from '../../../helpers/constants/design-system';
import Box from '../../ui/box/box'; import Box from '../../ui/box/box';
import { ICON_NAMES, TEXT_DIRECTIONS } from '..'; import { ICON_NAMES, TextDirection } from '..';
import { BUTTON_BASE_SIZES } from './button-base.constants'; import { BUTTON_BASE_SIZES } from './button-base.constants';
import { ButtonBase } from './button-base'; import { ButtonBase } from './button-base';
import README from './README.mdx'; import README from './README.mdx';
@ -200,7 +200,7 @@ export const Rtl = (args) => (
{...args} {...args}
startIconName={ICON_NAMES.ADD_SQUARE} startIconName={ICON_NAMES.ADD_SQUARE}
endIconName={ICON_NAMES.ARROW_2_RIGHT} endIconName={ICON_NAMES.ARROW_2_RIGHT}
textDirection={TEXT_DIRECTIONS.RIGHT_TO_LEFT} textDirection={TextDirection.RightToLeft}
> >
Button Demo Button Demo
</ButtonBase> </ButtonBase>

View File

@ -28,7 +28,7 @@ export { Label } from './label';
export { PickerNetwork } from './picker-network'; export { PickerNetwork } from './picker-network';
export { Tag } from './tag'; export { Tag } from './tag';
export { TagUrl } from './tag-url'; export { TagUrl } from './tag-url';
export { Text, TEXT_DIRECTIONS, INVISIBLE_CHARACTER } from './text'; export { Text, ValidTag, TextDirection, InvisibleCharacter } from './text';
export { Input, INPUT_TYPES } from './input'; export { Input, INPUT_TYPES } from './input';
export { TextField, TEXT_FIELD_TYPES, TEXT_FIELD_SIZES } from './text-field'; export { TextField, TEXT_FIELD_TYPES, TEXT_FIELD_SIZES } from './text-field';
export { TextFieldSearch } from './text-field-search'; export { TextFieldSearch } from './text-field-search';

View File

@ -59,7 +59,7 @@ import { TextVariant } from '../../../helpers/constants/design-system';
### Color ### Color
Use the `color` prop and the `TextColor` object from `./ui/helpers/constants/design-system.js` to change the color of the `Text` component. Use the `color` prop and the `TextColor` enum from `./ui/helpers/constants/design-system.js` to change the color of the `Text` component.
<Canvas> <Canvas>
<Story id="components-componentlibrary-text--color-story" /> <Story id="components-componentlibrary-text--color-story" />
@ -267,6 +267,8 @@ import { Text } from '../../component-library';
Use the `as` prop to change the root html element of the `Text` component Use the `as` prop to change the root html element of the `Text` component
You can also utilize the `ValidTag` enum from `./text.types` to ensure that you are using a valid html element
<Canvas> <Canvas>
<Story id="components-componentlibrary-text--as" /> <Story id="components-componentlibrary-text--as" />
</Canvas> </Canvas>
@ -313,22 +315,22 @@ Renders the html:
### Text Direction ### Text Direction
Use the `textDirection` prop and the `TEXT_DIRECTIONS` object from `./text.constants.js` to change the text direction of `Text` Use the `textDirection` prop and the `TextDirection` enum from `./text.types` to change the text direction of `Text`
<Canvas> <Canvas>
<Story id="components-componentlibrary-text--text-direction" /> <Story id="components-componentlibrary-text--text-direction-story" />
</Canvas> </Canvas>
```jsx ```jsx
import { Text, TEXT_DIRECTIONS } from '../../component-library'; import { Text, TextDirection } from '../../component-library';
<Text textDirection={TEXT_DIRECTIONS.LEFT_TO_RIGHT}> <Text textDirection={TextDirection.LeftToRight}>
This is left to right (ltr) for English and most languages This is left to right (ltr) for English and most languages
</Text> </Text>
<Text textDirection={TEXT_DIRECTIONS.RIGHT_TO_LEFT}> <Text textDirection={TextDirection.RightToLeft}>
This is right to left (rtl) for use with other laguanges such as Arabic. This Enlgish example is incorrect usage. This is right to left (rtl) for use with other laguanges such as Arabic. This Enlgish example is incorrect usage.
</Text> </Text>
<Text textDirection={TEXT_DIRECTIONS.AUTO}> <Text textDirection={TextDirection.Auto}>
Let the user agent decide with the auto option Let the user agent decide with the auto option
</Text> </Text>
``` ```

View File

@ -0,0 +1,56 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Text should render the Text with proper variant class name 1`] = `
<div>
<h1
class="box mm-text mm-text--display-md box--flex-direction-row box--color-text-default"
>
display-md
</h1>
<h2
class="box mm-text mm-text--heading-lg box--flex-direction-row box--color-text-default"
>
heading-lg
</h2>
<h3
class="box mm-text mm-text--heading-md box--flex-direction-row box--color-text-default"
>
heading-md
</h3>
<h4
class="box mm-text mm-text--heading-sm box--flex-direction-row box--color-text-default"
>
heading-sm
</h4>
<p
class="box mm-text mm-text--body-lg-medium box--flex-direction-row box--color-text-default"
>
body-lg-medium
</p>
<p
class="box mm-text mm-text--body-md box--flex-direction-row box--color-text-default"
>
body-md
</p>
<p
class="box mm-text mm-text--body-md-bold box--flex-direction-row box--color-text-default"
>
body-md-bold
</p>
<p
class="box mm-text mm-text--body-sm box--flex-direction-row box--color-text-default"
>
body-sm
</p>
<p
class="box mm-text mm-text--body-sm-bold box--flex-direction-row box--color-text-default"
>
body-sm-bold
</p>
<p
class="box mm-text mm-text--body-xs box--flex-direction-row box--color-text-default"
>
body-xs
</p>
</div>
`;

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import classnames from 'classnames'; import classnames from 'classnames';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Box from '../../ui/box'; import Box from '../../../ui/box';
import { import {
FONT_WEIGHT, FONT_WEIGHT,
FONT_STYLE, FONT_STYLE,
@ -10,7 +10,7 @@ import {
TEXT_TRANSFORM, TEXT_TRANSFORM,
OVERFLOW_WRAP, OVERFLOW_WRAP,
TextColor, TextColor,
} from '../../../helpers/constants/design-system'; } from '../../../../helpers/constants/design-system';
import { TEXT_DIRECTIONS } from './text.constants'; import { TEXT_DIRECTIONS } from './text.constants';
export const ValidTags = [ export const ValidTags = [

View File

@ -9,7 +9,7 @@ import {
TEXT_TRANSFORM, TEXT_TRANSFORM,
TextVariant, TextVariant,
Color, Color,
} from '../../../helpers/constants/design-system'; } from '../../../../helpers/constants/design-system';
import { Text, TEXT_DIRECTIONS } from '.'; import { Text, TEXT_DIRECTIONS } from '.';
describe('Text', () => { describe('Text', () => {

View File

@ -0,0 +1,3 @@
export { Text } from './text';
export { ValidTag, TextDirection, InvisibleCharacter } from './text.types';
export type { TextProps } from './text.types';

View File

@ -1,4 +1,5 @@
import React from 'react'; import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { import {
DISPLAY, DISPLAY,
BackgroundColor, BackgroundColor,
@ -16,115 +17,20 @@ import {
} from '../../../helpers/constants/design-system'; } from '../../../helpers/constants/design-system';
import Box from '../../ui/box'; import Box from '../../ui/box';
import { ValidTags, Text } from './text';
import { TEXT_DIRECTIONS } from './text.constants';
import README from './README.mdx'; import README from './README.mdx';
import { Text } from './text';
const sizeKnobOptions = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; import { ValidTag, TextDirection } from './text.types';
const marginSizeKnobOptions = [...sizeKnobOptions, 'auto'];
export default { export default {
title: 'Components/ComponentLibrary/Text', title: 'Components/ComponentLibrary/Text',
component: Text,
parameters: { parameters: {
docs: { docs: {
page: README, page: README,
}, },
}, },
argTypes: { } as ComponentMeta<typeof Text>;
variant: {
control: { type: 'select' },
options: Object.values(TextVariant),
},
color: {
control: { type: 'select' },
options: Object.values(TextColor),
},
fontWeight: {
control: { type: 'select' },
options: Object.values(FONT_WEIGHT),
},
fontStyle: {
control: { type: 'select' },
options: Object.values(FONT_STYLE),
},
textTransform: {
control: { type: 'select' },
options: Object.values(TEXT_TRANSFORM),
},
align: {
control: { type: 'select' },
options: Object.values(TEXT_ALIGN),
},
overflowWrap: {
control: { type: 'select' },
options: Object.values(OVERFLOW_WRAP),
},
ellipsis: {
control: { type: 'boolean' },
},
as: {
control: { type: 'select' },
options: ValidTags,
},
textDirection: {
control: { type: 'select' },
options: Object.values(TEXT_DIRECTIONS),
},
className: {
control: { type: 'text' },
},
children: {
control: { type: 'text' },
},
display: {
options: Object.values(DISPLAY),
control: 'select',
table: { category: 'box props' },
},
backgroundColor: {
options: Object.values(BackgroundColor),
control: 'select',
table: { category: 'box props' },
},
borderColor: {
options: Object.values(BorderColor),
control: 'select',
table: { category: 'box props' },
},
padding: {
options: sizeKnobOptions,
control: 'select',
table: { category: 'box props' },
},
margin: {
options: marginSizeKnobOptions,
control: 'select',
table: { category: 'box props' },
},
marginTop: {
options: marginSizeKnobOptions,
control: 'select',
table: { category: 'box props' },
},
marginRight: {
options: marginSizeKnobOptions,
control: 'select',
table: { category: 'box props' },
},
marginBottom: {
options: marginSizeKnobOptions,
control: 'select',
table: { category: 'box props' },
},
marginLeft: {
options: marginSizeKnobOptions,
control: 'select',
table: { category: 'box props' },
},
},
};
function renderBackgroundColor(color) { function renderBackgroundColor(color) {
let bgColor; let bgColor;
@ -164,14 +70,18 @@ function renderBackgroundColor(color) {
return bgColor; return bgColor;
} }
export const DefaultStory = (args) => <Text {...args}>{args.children}</Text>; const Template: ComponentStory<typeof Text> = (args) => (
<Text {...args}>{args.children}</Text>
);
DefaultStory.storyName = 'Default'; export const DefaultStory = Template.bind({});
DefaultStory.args = { DefaultStory.args = {
children: 'The quick orange fox jumped over the lazy dog.', children: 'The quick orange fox jumped over the lazy dog.',
}; };
DefaultStory.storyName = 'Default';
export const Variant = (args) => ( export const Variant = (args) => (
<> <>
{Object.values(TextVariant).map((variant) => ( {Object.values(TextVariant).map((variant) => (
@ -182,7 +92,7 @@ export const Variant = (args) => (
</> </>
); );
export const ColorStory = (args) => { export const ColorStory: ComponentStory<typeof Text> = (args) => {
// Index of last valid color in TextColor array // Index of last valid color in TextColor array
return ( return (
<> <>
@ -203,7 +113,7 @@ export const ColorStory = (args) => {
}; };
ColorStory.storyName = 'Color'; ColorStory.storyName = 'Color';
export const FontWeight = (args) => ( export const FontWeight: ComponentStory<typeof Text> = (args) => (
<> <>
{Object.values(FONT_WEIGHT).map((weight) => ( {Object.values(FONT_WEIGHT).map((weight) => (
<Text {...args} fontWeight={weight} key={weight}> <Text {...args} fontWeight={weight} key={weight}>
@ -213,7 +123,7 @@ export const FontWeight = (args) => (
</> </>
); );
export const FontStyle = (args) => ( export const FontStyle: ComponentStory<typeof Text> = (args) => (
<> <>
{Object.values(FONT_STYLE).map((style) => ( {Object.values(FONT_STYLE).map((style) => (
<Text {...args} fontStyle={style} key={style}> <Text {...args} fontStyle={style} key={style}>
@ -223,7 +133,7 @@ export const FontStyle = (args) => (
</> </>
); );
export const TextTransform = (args) => ( export const TextTransform: ComponentStory<typeof Text> = (args) => (
<> <>
{Object.values(TEXT_TRANSFORM).map((transform) => ( {Object.values(TEXT_TRANSFORM).map((transform) => (
<Text {...args} textTransform={transform} key={transform}> <Text {...args} textTransform={transform} key={transform}>
@ -233,7 +143,7 @@ export const TextTransform = (args) => (
</> </>
); );
export const TextAlign = (args) => ( export const TextAlign: ComponentStory<typeof Text> = (args) => (
<> <>
{Object.values(TEXT_ALIGN).map((align) => ( {Object.values(TEXT_ALIGN).map((align) => (
<Text {...args} textAlign={align} key={align}> <Text {...args} textAlign={align} key={align}>
@ -243,11 +153,11 @@ export const TextAlign = (args) => (
</> </>
); );
export const OverflowWrap = (args) => ( export const OverflowWrap: ComponentStory<typeof Text> = (args) => (
<Box <Box
borderColor={BorderColor.warningDefault} borderColor={BorderColor.warningDefault}
display={DISPLAY.BLOCK} display={DISPLAY.BLOCK}
width={FRACTIONS.ONE_THIRD} style={{ width: 200 }}
> >
<Text {...args} overflowWrap={OVERFLOW_WRAP.NORMAL}> <Text {...args} overflowWrap={OVERFLOW_WRAP.NORMAL}>
{OVERFLOW_WRAP.NORMAL}: 0x39013f961c378f02c2b82a6e1d31e9812786fd9d {OVERFLOW_WRAP.NORMAL}: 0x39013f961c378f02c2b82a6e1d31e9812786fd9d
@ -258,7 +168,7 @@ export const OverflowWrap = (args) => (
</Box> </Box>
); );
export const Ellipsis = (args) => ( export const Ellipsis: ComponentStory<typeof Text> = (args) => (
<Box <Box
borderColor={BorderColor.primaryDefault} borderColor={BorderColor.primaryDefault}
display={DISPLAY.BLOCK} display={DISPLAY.BLOCK}
@ -273,16 +183,23 @@ export const Ellipsis = (args) => (
</Box> </Box>
); );
export const As = (args) => ( export const As: ComponentStory<typeof Text> = (args) => (
<> <>
{ValidTags.map((tag) => { {Object.keys(ValidTag).map((tag) => {
if (tag === 'input') { if (ValidTag[tag] === ValidTag.Input) {
return <Text key={tag} {...args} as={tag} placeholder={tag} />; return (
<Text
key={ValidTag[tag]}
{...args}
as={ValidTag[tag]}
placeholder={ValidTag[tag]}
/>
);
} }
return ( return (
<div key={tag}> <div key={ValidTag[tag]}>
<Text {...args} as={tag}> <Text {...args} as={ValidTag[tag]}>
{tag} {ValidTag[tag]}
</Text> </Text>
</div> </div>
); );
@ -290,21 +207,21 @@ export const As = (args) => (
</> </>
); );
export const TextDirection = (args) => ( export const TextDirectionStory: ComponentStory<typeof Text> = (args) => (
<Box <Box
style={{ maxWidth: 300 }} style={{ maxWidth: 300 }}
display={DISPLAY.FLEX} display={DISPLAY.FLEX}
flexDirection={FLEX_DIRECTION.COLUMN} flexDirection={FLEX_DIRECTION.COLUMN}
gap={4} gap={4}
> >
<Text {...args} textDirection={TEXT_DIRECTIONS.LEFT_TO_RIGHT}> <Text {...args} textDirection={TextDirection.LeftToRight}>
This is left to right (ltr) for English and most languages This is left to right (ltr) for English and most languages
</Text> </Text>
<Text {...args} textDirection={TEXT_DIRECTIONS.RIGHT_TO_LEFT}> <Text {...args} textDirection={TextDirection.RightToLeft}>
This is right to left (rtl) for use with other laguanges such as Arabic. This is right to left (rtl) for use with other laguanges such as Arabic.
This Enlgish example is incorrect usage. This Enlgish example is incorrect usage.
</Text> </Text>
<Text {...args} textDirection={TEXT_DIRECTIONS.AUTO}> <Text {...args} textDirection={TextDirection.Auto}>
Let the user agent decide with the auto option Let the user agent decide with the auto option
</Text> </Text>
</Box> </Box>

View File

@ -0,0 +1,243 @@
import * as React from 'react';
import { render } from '@testing-library/react';
import {
FONT_STYLE,
FONT_WEIGHT,
OVERFLOW_WRAP,
TEXT_ALIGN,
TextColor,
TEXT_TRANSFORM,
TextVariant,
Color,
} from '../../../helpers/constants/design-system';
import { TextDirection, ValidTag } from './text.types';
import { Text } from '.';
describe('Text', () => {
it('should render the Text without crashing', () => {
const { getByText } = render(<Text>Test type</Text>);
expect(getByText('Test type')).toBeDefined();
});
it('should render the Text with correct html elements', () => {
const { getByText, container } = render(
<>
<Text as={ValidTag.P}>p</Text>
<Text as={ValidTag.H1}>h1</Text>
<Text as={ValidTag.H2}>h2</Text>
<Text as={ValidTag.H3}>h3</Text>
<Text as={ValidTag.H4}>h4</Text>
<Text as={ValidTag.H5}>h5</Text>
<Text as={ValidTag.H6}>h6</Text>
<Text as={ValidTag.Span}>span</Text>
<Text as={ValidTag.Strong}>strong</Text>
<Text as={ValidTag.Em}>em</Text>
<Text as={ValidTag.Li}>li</Text>
<Text as={ValidTag.Div}>div</Text>
<Text as={ValidTag.Dt}>dt</Text>
<Text as={ValidTag.Dd}>dd</Text>
</>,
);
expect(container.querySelector('p')).toBeDefined();
expect(getByText('p')).toBeDefined();
expect(container.querySelector('h1')).toBeDefined();
expect(getByText('h1')).toBeDefined();
expect(container.querySelector('h2')).toBeDefined();
expect(getByText('h2')).toBeDefined();
expect(container.querySelector('h3')).toBeDefined();
expect(getByText('h3')).toBeDefined();
expect(container.querySelector('h4')).toBeDefined();
expect(getByText('h4')).toBeDefined();
expect(container.querySelector('h5')).toBeDefined();
expect(getByText('h5')).toBeDefined();
expect(container.querySelector('h6')).toBeDefined();
expect(getByText('h6')).toBeDefined();
expect(container.querySelector('span')).toBeDefined();
expect(getByText('span')).toBeDefined();
expect(container.querySelector('strong')).toBeDefined();
expect(getByText('strong')).toBeDefined();
expect(container.querySelector('em')).toBeDefined();
expect(getByText('em')).toBeDefined();
expect(container.querySelector('li')).toBeDefined();
expect(getByText('li')).toBeDefined();
expect(container.querySelector('div')).toBeDefined();
expect(getByText('div')).toBeDefined();
expect(container.querySelector('dt')).toBeDefined();
expect(getByText('dt')).toBeDefined();
expect(container.querySelector('dd')).toBeDefined();
expect(getByText('dd')).toBeDefined();
});
it('should render the Text with proper variant class name', () => {
const { getByText, container } = render(
<>
<Text variant={TextVariant.displayMd}>display-md</Text>
<Text variant={TextVariant.headingLg}>heading-lg</Text>
<Text variant={TextVariant.headingMd}>heading-md</Text>
<Text variant={TextVariant.headingSm}>heading-sm</Text>
<Text variant={TextVariant.bodyLgMedium}>body-lg-medium</Text>
<Text variant={TextVariant.bodyMd}>body-md</Text>
<Text variant={TextVariant.bodyMdBold}>body-md-bold</Text>
<Text variant={TextVariant.bodySm}>body-sm</Text>
<Text variant={TextVariant.bodySmBold}>body-sm-bold</Text>
<Text variant={TextVariant.bodyXs}>body-xs</Text>
</>,
);
expect(getByText('display-md')).toHaveClass('mm-text--display-md');
expect(getByText('heading-lg')).toHaveClass('mm-text--heading-lg');
expect(getByText('heading-md')).toHaveClass('mm-text--heading-md');
expect(getByText('heading-sm')).toHaveClass('mm-text--heading-sm');
expect(getByText('body-lg-medium')).toHaveClass('mm-text--body-lg-medium');
expect(getByText('body-md')).toHaveClass('mm-text--body-md');
expect(getByText('body-md-bold')).toHaveClass('mm-text--body-md-bold');
expect(getByText('body-sm')).toHaveClass('mm-text--body-sm');
expect(getByText('body-sm-bold')).toHaveClass('mm-text--body-sm-bold');
expect(getByText('body-xs')).toHaveClass('mm-text--body-xs');
expect(container).toMatchSnapshot();
});
it('should render the Text with proper font weight class name', () => {
const { getByText } = render(
<>
<Text fontWeight={FONT_WEIGHT.BOLD}>bold</Text>
<Text fontWeight={FONT_WEIGHT.MEDIUM}>medium</Text>
<Text fontWeight={FONT_WEIGHT.NORMAL}>normal</Text>
</>,
);
expect(getByText('bold')).toHaveClass('mm-text--font-weight-bold');
expect(getByText('medium')).toHaveClass('mm-text--font-weight-medium');
expect(getByText('normal')).toHaveClass('mm-text--font-weight-normal');
});
it('should render the Text with proper text color class name', () => {
const { getByText } = render(
<>
<Text color={TextColor.textDefault}>text-default</Text>
<Text color={TextColor.textAlternative}>text-alternative</Text>
<Text color={TextColor.textMuted}>text-muted</Text>
<Text color={Color.overlayInverse}>overlay-inverse</Text>
<Text color={TextColor.primaryDefault}>primary-default</Text>
<Text color={TextColor.primaryInverse}>primary-inverse</Text>
<Text color={TextColor.errorDefault}>error-default</Text>
<Text color={TextColor.errorInverse}>error-inverse</Text>
<Text color={TextColor.successDefault}>success-default</Text>
<Text color={TextColor.successInverse}>success-inverse</Text>
<Text color={TextColor.warningInverse}>warning-inverse</Text>
<Text color={TextColor.infoDefault}>info-default</Text>
<Text color={TextColor.infoInverse}>info-inverse</Text>
</>,
);
expect(getByText('text-default')).toHaveClass('box--color-text-default');
expect(getByText('text-alternative')).toHaveClass(
'box--color-text-alternative',
);
expect(getByText('text-muted')).toHaveClass('box--color-text-muted');
expect(getByText('primary-default')).toHaveClass(
'box--color-primary-default',
);
expect(getByText('primary-inverse')).toHaveClass(
'box--color-primary-inverse',
);
expect(getByText('error-default')).toHaveClass('box--color-error-default');
expect(getByText('error-inverse')).toHaveClass('box--color-error-inverse');
expect(getByText('success-default')).toHaveClass(
'box--color-success-default',
);
expect(getByText('success-inverse')).toHaveClass(
'box--color-success-inverse',
);
expect(getByText('warning-inverse')).toHaveClass(
'box--color-warning-inverse',
);
expect(getByText('info-default')).toHaveClass('box--color-info-default');
expect(getByText('info-inverse')).toHaveClass('box--color-info-inverse');
});
it('should render the Text with proper font style class name', () => {
const { getByText } = render(
<>
<Text fontStyle={FONT_STYLE.ITALIC}>italic</Text>
<Text fontStyle={FONT_STYLE.NORMAL}>normal</Text>
</>,
);
expect(getByText('italic')).toHaveClass('mm-text--font-style-italic');
expect(getByText('normal')).toHaveClass('mm-text--font-style-normal');
});
it('should render the Text with proper text align class name', () => {
const { getByText } = render(
<>
<Text textAlign={TEXT_ALIGN.LEFT}>left</Text>
<Text textAlign={TEXT_ALIGN.CENTER}>center</Text>
<Text textAlign={TEXT_ALIGN.RIGHT}>right</Text>
<Text textAlign={TEXT_ALIGN.JUSTIFY}>justify</Text>
<Text textAlign={TEXT_ALIGN.END}>end</Text>
</>,
);
expect(getByText('left')).toHaveClass('mm-text--text-align-left');
expect(getByText('center')).toHaveClass('mm-text--text-align-center');
expect(getByText('right')).toHaveClass('mm-text--text-align-right');
expect(getByText('justify')).toHaveClass('mm-text--text-align-justify');
expect(getByText('end')).toHaveClass('mm-text--text-align-end');
});
it('should render the Text with proper overflow wrap class name', () => {
const { getByText } = render(
<>
<Text overflowWrap={OVERFLOW_WRAP.BREAK_WORD}>break-word</Text>
<Text overflowWrap={OVERFLOW_WRAP.NORMAL}>normal</Text>
</>,
);
expect(getByText('break-word')).toHaveClass(
'mm-text--overflow-wrap-break-word',
);
expect(getByText('normal')).toHaveClass('mm-text--overflow-wrap-normal');
});
it('should render the Text with proper ellipsis class name', () => {
const { getByText } = render(
<>
<Text ellipsis>ellipsis</Text>
</>,
);
expect(getByText('ellipsis')).toHaveClass('mm-text--ellipsis');
});
it('should render the Text with proper text transform class name', () => {
const { getByText } = render(
<>
<Text textTransform={TEXT_TRANSFORM.UPPERCASE}>uppercase</Text>
<Text textTransform={TEXT_TRANSFORM.LOWERCASE}>lowercase</Text>
<Text textTransform={TEXT_TRANSFORM.CAPITALIZE}>capitalize</Text>
</>,
);
expect(getByText('uppercase')).toHaveClass(
'mm-text--text-transform-uppercase',
);
expect(getByText('lowercase')).toHaveClass(
'mm-text--text-transform-lowercase',
);
expect(getByText('capitalize')).toHaveClass(
'mm-text--text-transform-capitalize',
);
});
it('should accept a ref prop that is passed down to the html element', () => {
const mockRef = jest.fn();
render(<Text ref={mockRef} />);
expect(mockRef).toHaveBeenCalledTimes(1);
});
it('should render the Text with proper direction', () => {
const { getByText } = render(
<>
<Text textDirection={TextDirection.Auto}>auto</Text>
<Text textDirection={TextDirection.LeftToRight}>ltr</Text>
<Text textDirection={TextDirection.RightToLeft}>rtl</Text>
</>,
);
expect(getByText('auto')).toHaveAttribute('dir', 'auto');
expect(getByText('ltr')).toHaveAttribute('dir', 'ltr');
expect(getByText('rtl')).toHaveAttribute('dir', 'rtl');
});
});

View File

@ -0,0 +1,84 @@
import React, { forwardRef, Ref } from 'react';
import classnames from 'classnames';
import Box from '../../ui/box';
import {
FONT_WEIGHT,
TextVariant,
TextColor,
} from '../../../helpers/constants/design-system';
import { TextProps, ValidTag } from './text.types';
const getTextElementDefault = (variant: TextVariant) => {
switch (variant) {
case TextVariant.displayMd:
return ValidTag.H1;
case TextVariant.headingLg:
return ValidTag.H2;
case TextVariant.headingMd:
return ValidTag.H3;
case TextVariant.headingSm:
return ValidTag.H4;
case TextVariant.inherit:
return ValidTag.Span;
// TextVariant.bodyLgMedium, TextVariant.bodyMd, TextVariant.bodyMdBold, TextVariant.bodySm, TextVariant.bodySmBold, TextVariant.bodyXs use default 'p' tag
default:
return ValidTag.P;
}
};
export const Text = forwardRef(function Text(
{
variant = TextVariant.bodyMd,
color = TextColor.textDefault,
fontWeight,
fontStyle,
textTransform,
textAlign,
textDirection,
overflowWrap,
ellipsis,
as,
className = '',
children,
...props
}: TextProps,
ref: Ref<HTMLElement>,
) {
// Check if as is set otherwise set a default tag based on variant
const Tag = as ?? getTextElementDefault(variant);
let strongTagFontWeight;
if (Tag === 'strong') {
strongTagFontWeight = FONT_WEIGHT.BOLD;
}
const computedClassName = classnames(
'mm-text',
className,
`mm-text--${variant}`,
{
[`mm-text--font-weight-${strongTagFontWeight || fontWeight}`]: Boolean(
strongTagFontWeight || fontWeight,
),
[`mm-text--font-style-${String(fontStyle)}`]: Boolean(fontStyle),
[`mm-text--ellipsis`]: Boolean(ellipsis),
[`mm-text--text-transform-${String(textTransform)}`]:
Boolean(textTransform),
[`mm-text--text-align-${String(textAlign)}`]: Boolean(textAlign),
[`mm-text--overflow-wrap-${String(overflowWrap)}`]: Boolean(overflowWrap),
},
);
return (
<Box
className={classnames(computedClassName)}
as={Tag}
dir={textDirection}
color={color}
ref={ref}
{...props}
>
{children}
</Box>
);
});

View File

@ -0,0 +1,114 @@
import React from 'react';
import type { BoxProps } from '../../ui/box/box.d';
import {
FONT_WEIGHT,
FONT_STYLE,
TextVariant,
TEXT_ALIGN,
TEXT_TRANSFORM,
OVERFLOW_WRAP,
TextColor,
Color,
} from '../../../helpers/constants/design-system';
export enum TextDirection {
LeftToRight = 'ltr',
RightToLeft = 'rtl',
Auto = 'auto',
}
/**
* The InvisibleCharacter is a very useful tool if you want to make sure a line of text
* takes up vertical space even if it's empty.
*/
export const InvisibleCharacter = '\u200B';
export enum ValidTag {
Dd = 'dd',
Div = 'div',
Dt = 'dt',
Em = 'em',
H1 = 'h1',
H2 = 'h2',
H3 = 'h3',
H4 = 'h4',
H5 = 'h5',
H6 = 'h6',
Li = 'li',
P = 'p',
Span = 'span',
Strong = 'strong',
Ul = 'ul',
Label = 'label',
Input = 'input',
}
export interface TextProps extends BoxProps {
/**
* The text content of the Text component
*/
children: React.ReactNode;
/**
* The variation of font styles including sizes and weights of the Text component
* Possible values:
* `displayMd` large screen: 48px / small screen: 32px,
* `headingLg` large screen: 32px / small screen: 24px,
* `headingMd` large screen: 24px / small screen: 18px,
* `headingSm` large screen: 18px / small screen: 16px,
* `bodyLgMedium` large screen: 18px / small screen: 16px,
* `bodyMd` large screen: 16px / small screen: 14px,
* `bodyMdBold` large screen: 16px / small screen: 14px,
* `bodySm` large screen: 14px / small screen: 12px,
* `bodySmBold` large screen: 14px / small screen: 12px,
* `bodyXs` large screen: 12px / small screen: 10px,
* `inherit`
*/
variant?: TextVariant;
/**
* The color of the Text component Should use the COLOR object from
* ./ui/helpers/constants/design-system.js
*/
color?: TextColor | Color;
/**
* The font-weight of the Text component. Should use the FONT_WEIGHT object from
* ./ui/helpers/constants/design-system.js
*/
fontWeight?: keyof typeof FONT_WEIGHT;
/**
* The font-style of the Text component. Should use the FONT_STYLE object from
* ./ui/helpers/constants/design-system.js
*/
fontStyle?: keyof typeof FONT_STYLE;
/**
* The textTransform of the Text component. Should use the TEXT_TRANSFORM object from
* ./ui/helpers/constants/design-system.js
*/
textTransform?: keyof typeof TEXT_TRANSFORM;
/**
* The text-align of the Text component. Should use the TEXT_ALIGN object from
* ./ui/helpers/constants/design-system.js
*/
textAlign?: keyof typeof TEXT_ALIGN;
/**
* Change the dir (direction) global attribute of text to support the direction a language is written
* Possible values: `LEFT_TO_RIGHT` (default), `RIGHT_TO_LEFT`, `AUTO` (user agent decides)
*/
textDirection?: TextDirection;
/**
* The overflow-wrap of the Text component. Should use the OVERFLOW_WRAP object from
* ./ui/helpers/constants/design-system.js
*/
overflowWrap?: keyof typeof OVERFLOW_WRAP;
/**
* Used for long strings that can be cut off...
*/
ellipsis?: boolean;
/**
* Changes the root html element tag of the Text component.
*/
as?: ValidTag;
/**
* Additional className to assign the Text component
*/
className?: string;
}

View File

@ -337,7 +337,7 @@ export interface BoxProps extends React.HTMLAttributes<HTMLElement> {
/** /**
* The ref of the Box component. * The ref of the Box component.
*/ */
ref?: React.RefObject<HTMLElement>; ref?: React.Ref<HTMLElement>;
} }
declare const Box: React.FC<BoxProps>; declare const Box: React.FC<BoxProps>;

View File

@ -1,4 +1,4 @@
import { INVISIBLE_CHARACTER } from '../../components/component-library'; import { INVISIBLE_CHARACTER } from '../../components/component-library/text/deprecated';
export function getAccountNameErrorMessage( export function getAccountNameErrorMessage(
accounts, accounts,