Adding polymorphic 'as' prop to Box component and updating Typography component to use the same (#15518)

* Adding polymorphic as prop to Box component

* Updating Typography component to use 'as' as the polymorphic prop instead of 'tag'

* Fixing linting
feature/default_network_editable
George Marshall 2 years ago committed by GitHub
parent 94f46fbb1e
commit 092189cb5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      ui/components/app/create-new-vault/create-new-vault.js
  2. 8
      ui/components/app/edit-gas-display-education/edit-gas-display-education.component.js
  3. 10
      ui/components/app/edit-gas-display/edit-gas-display.component.js
  4. 4
      ui/components/app/flask/snap-settings-card/snap-settings-card.js
  5. 4
      ui/components/app/flask/snaps-authorship-pill/snaps-authorship-pill.js
  6. 2
      ui/components/app/recovery-phrase-reminder/recovery-phrase-reminder.js
  7. 25
      ui/components/ui/box/README.mdx
  8. 11
      ui/components/ui/box/box.js
  9. 20
      ui/components/ui/box/box.stories.js
  10. 18
      ui/components/ui/box/box.test.js
  11. 2
      ui/components/ui/chip/chip.js
  12. 2
      ui/components/ui/confusable/confusable.component.js
  13. 4
      ui/components/ui/definition-list/definition-list.js
  14. 2
      ui/components/ui/numeric-input/numeric-input.component.js
  15. 47
      ui/components/ui/typography/README.mdx
  16. 8
      ui/components/ui/typography/typography.js
  17. 35
      ui/components/ui/typography/typography.stories.js
  18. 58
      ui/components/ui/typography/typography.test.js
  19. 6
      ui/pages/first-time-flow/seed-phrase/seed-phrase-intro/seed-phrase-intro.component.js
  20. 12
      ui/pages/onboarding-flow/secure-your-wallet/secure-your-wallet.js
  21. 2
      ui/pages/permissions-connect/flask/snap-install/snap-install.js
  22. 4
      ui/pages/permissions-connect/flask/snap-update/snap-update.js
  23. 6
      ui/pages/swaps/awaiting-signatures/awaiting-signatures.js
  24. 6
      ui/pages/swaps/build-quote/build-quote.js
  25. 2
      ui/pages/swaps/fee-card/fee-card.js

@ -146,7 +146,7 @@ export default function CreateNewVault({
className="create-new-vault__terms-label"
htmlFor="create-new-vault__terms-checkbox"
>
<Typography tag="span">{termsOfUse}</Typography>
<Typography as="span">{termsOfUse}</Typography>
</label>
</div>
) : null}

@ -15,7 +15,7 @@ export default function EditGasDisplayEducation() {
return (
<div className="edit-gas-display-education">
<Typography
tag="p"
as="p"
color={COLORS.TEXT_ALTERNATIVE}
variant={TYPOGRAPHY.H6}
>
@ -29,7 +29,7 @@ export default function EditGasDisplayEducation() {
{t('editGasHigh')}
</Typography>
<Typography
tag="p"
as="p"
color={COLORS.TEXT_ALTERNATIVE}
variant={TYPOGRAPHY.H6}
>
@ -43,7 +43,7 @@ export default function EditGasDisplayEducation() {
{t('editGasMedium')}
</Typography>
<Typography
tag="p"
as="p"
color={COLORS.TEXT_ALTERNATIVE}
variant={TYPOGRAPHY.H6}
>
@ -57,7 +57,7 @@ export default function EditGasDisplayEducation() {
{t('editGasLow')}
</Typography>
<Typography
tag="p"
as="p"
color={COLORS.TEXT_ALTERNATIVE}
variant={TYPOGRAPHY.H6}
>

@ -196,17 +196,13 @@ export default function EditGasDisplay({
supportsEIP1559 &&
estimatedMaximumFiat !== undefined && (
<>
<Typography
tag="span"
key="label"
fontWeight={FONT_WEIGHT.BOLD}
>
<Typography as="span" key="label" fontWeight={FONT_WEIGHT.BOLD}>
{t('editGasSubTextFeeLabel')}
</Typography>
<Typography tag="span" key="secondary">
<Typography as="span" key="secondary">
{estimatedMaximumFiat}
</Typography>
<Typography tag="span" key="primary">
<Typography as="span" key="primary">
{`(${estimatedMaximumNative})`}
</Typography>
</>

@ -161,7 +161,7 @@ const SnapSettingsCard = ({
color={COLORS.TEXT_MUTED}
variant={TYPOGRAPHY.H8}
fontWeight={FONT_WEIGHT.NORMAL}
tag="span"
as="span"
className="snap-settings-card__date-added"
>
{`${
@ -177,7 +177,7 @@ const SnapSettingsCard = ({
variant={TYPOGRAPHY.H7}
fontWeight={FONT_WEIGHT.NORMAL}
align={TEXT_ALIGN.CENTER}
tag="span"
as="span"
className="snap-settings-card__version"
>
{t('shorthandVersion', [version])}

@ -54,7 +54,7 @@ const SnapsAuthorshipPill = ({ snapId, version, className }) => {
color={COLORS.PRIMARY_INVERSE}
variant={TYPOGRAPHY.H7}
align={TEXT_ALIGN.CENTER}
tag="span"
as="span"
className="version"
>
{t('shorthandVersion', [version])}
@ -67,7 +67,7 @@ const SnapsAuthorshipPill = ({ snapId, version, className }) => {
<Typography
className="chip__label"
variant={TYPOGRAPHY.H7}
tag="span"
as="span"
color={COLORS.TEXT_ALTERNATIVE}
title={packageName}
>

@ -47,7 +47,7 @@ export default function RecoveryPhraseReminder({ onConfirm, hasBackedUp }) {
<ul className="recovery-phrase-reminder__list">
<li>
<Typography
tag="span"
as="span"
color={COLORS.TEXT_DEFAULT}
fontWeight={FONT_WEIGHT.BOLD}
>

@ -42,6 +42,7 @@ Box is a utility component that can be used for layout or as a base for other UI
| borderWidth | 0, 1, 2, 4, 6, 8, 9, 10, 12 or array of numbers [1, 2] | - |
| borderRadius | [SIZES](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L74-L81) values or array of [SIZES](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L74-L81) values | - |
| borderStyle | [BORDER_STYLE](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L83-L88) values or array of [BORDER_STYLE](https://github.com/MetaMask/metamask-extension/blob/develop/ui/helpers/constants/design-system.js#L83-L88) values | - |
| as | The polymorphic `as` prop allows you to change the root HTML element of the Box component. Defaults to 'div' | 'div' |
## Usage
@ -134,14 +135,10 @@ import Box from '../ui/box';
Use the `backgroundColor` prop along with the `COLORS` object from `ui/helpers/constants/design-system.js` to change background color. The `backgroundColor` prop accepts [responsive props](#responsive-props) in the form of array props.
````jsx
<Canvas>
<Story id="ui-components-ui-box-box-stories-js--background-color" />
</Canvas>
**NOTE**: The `<Box/>` and `<Typography/>` color combinations above follow our design system color rules and should cover most general UI applications. Click "Show code" to see the code example. Do not use the [deprecated colors](#deprecated-colors)
Example of importing `COLORS` object with `Box` component
```jsx
@ -151,7 +148,7 @@ import Box from '../ui/box';
<Box backgroundColor={COLORS.BACKGROUND_DEFAULT}>
<Typography color={COLORS.TEXT_DEFAULT}>COLORS.BACKGROUND_DEFAULT</Typography>
</Box>;
````
```
### Border Color
@ -161,8 +158,6 @@ Use the `borderColor` prop along with the `COLORS` object from `ui/helpers/const
<Story id="ui-components-ui-box-box-stories-js--border-color" />
</Canvas>
**NOTE**: The `<Box/>` and `<Typography/>` color combinations above follow our design system color rules and should cover most general UI applications. Click "Show code" to see the code example. Do not use the [deprecated colors](#deprecated-colors)
Example of importing `COLORS` object with `Box` component
```jsx
@ -236,3 +231,19 @@ import Box from '../ui/box';
</Box>
</Box>;
```
### As
Use the `as` prop to change the root html element of the Box component
<Canvas>
<Story id="ui-components-ui-box-box-stories-js--as" />
</Canvas>
```jsx
import Box from '../../ui/box';
<Box as="ul">ul</Box>
<Box as="li">li</Box>
<Box as="button">button</Box>
```

@ -227,6 +227,7 @@ export default function Box({
children,
className,
backgroundColor,
as = 'div',
...props
}) {
const boxClassName = classnames(
@ -284,10 +285,11 @@ export default function Box({
if (typeof children === 'function') {
return children(boxClassName);
}
const Component = as;
return (
<div className={boxClassName} {...props}>
<Component className={boxClassName} {...props}>
{children}
</div>
</Component>
);
}
@ -351,4 +353,9 @@ Box.propTypes = {
]),
backgroundColor: MultipleBackgroundColors,
className: PropTypes.string,
/**
* The polymorphic `as` prop allows you to change the root HTML element of the Box component
* Defaults to 'div'
*/
as: PropTypes.string,
};

@ -166,6 +166,10 @@ export default {
control: 'select',
table: { category: 'padding' },
},
as: {
control: 'select',
options: ['div', 'ul', 'li', 'span', 'a', 'button'],
},
},
};
@ -406,3 +410,19 @@ export const ResponsiveProps = () => {
</>
);
};
export const As = (args) => {
return (
<>
<Typography marginBottom={4}>
You can change the root element of the Box component using the as prop.
Inspect the below elements to see the underlying HTML elements
</Typography>
<Box {...args}>div(default)</Box>
<Box as="ul">ul</Box>
<Box as="li">li</Box>
<Box as="button">button</Box>
<Box as="header">header</Box>
</>
);
};

@ -729,4 +729,22 @@ describe('Box', () => {
expect(getByText('Box content')).toHaveClass('box--lg:height-min');
});
});
describe('polymorphic "as" prop', () => {
it('should render the Box with different html root elements', () => {
const { container } = render(
<>
<Box>Box as div (default)</Box>
<Box as="ul">Box as ul</Box>
<Box as="button">Box as button</Box>
</>,
);
expect(container.querySelector('div')).toHaveTextContent(
'Box as div (default)',
);
expect(container.querySelector('ul')).toHaveTextContent('Box as ul');
expect(container.querySelector('button')).toHaveTextContent(
'Box as button',
);
});
});
});

@ -55,7 +55,7 @@ export default function Chip({
<Typography
className="chip__label"
variant={TYPOGRAPHY.H6}
tag="span"
as="span"
color={COLORS.TEXT_ALTERNATIVE}
{...labelProps}
>

@ -18,7 +18,7 @@ const Confusable = ({ input }) => {
return (
<Tooltip
key={index.toString()}
tag="span"
as="span"
position="top"
title={
zeroWidth

@ -39,7 +39,7 @@ export default function DefinitionList({
marginBottom: 1,
}}
className="definition-list__term"
tag="dt"
as="dt"
>
{term}
{tooltips[term] && (
@ -62,7 +62,7 @@ export default function DefinitionList({
}}
className="definition-list__definition"
overflowWrap={OVERFLOW_WRAP.BREAK_WORD}
tag="dd"
as="dd"
>
{definition}
</Typography>

@ -47,7 +47,7 @@ export default function NumericInput({
<Typography
color={COLORS.TEXT_ALTERNATIVE}
variant={TYPOGRAPHY.H7}
tag="span"
as="span"
>
{detailText}
</Typography>

@ -215,50 +215,63 @@ import { OVERFLOW_WRAP } from '../../../helpers/constants/design-system';
</div>;
```
### Tag
### As
Use the `tag` prop to change the root html element of the Typography component
Use the `as` prop to change the root html element of the Typography component
<Canvas>
<Story id="ui-components-ui-typography-typography-stories-js--tag" />
<Story id="ui-components-ui-typography-typography-stories-js--as" />
</Canvas>
```jsx
// If importing from ui/components/app/[YOUR_COMPONENT]/ directory
import Typography from '../../ui/typography';
<Typography tag="dd">dd</Typography>
<Typography tag="div">div</Typography>
<Typography tag="dt">dt</Typography>
<Typography tag="em">em</Typography>
<Typography tag="h1">h1</Typography>
<Typography tag="h2">h2</Typography>
<Typography tag="h3">h3</Typography>
<Typography tag="h4">h4</Typography>
<Typography tag="h5">h5</Typography>
<Typography tag="h6">h6</Typography>
<Typography tag="li">li</Typography>
<Typography tag="p">p</Typography>
<Typography tag="span">span</Typography>
<Typography tag="strong">strong</Typography>
<Typography as="dd">dd</Typography>
<Typography as="div">div</Typography>
<Typography as="dt">dt</Typography>
<Typography as="em">em</Typography>
<Typography as="h1">h1</Typography>
<Typography as="h2">h2</Typography>
<Typography as="h3">h3</Typography>
<Typography as="h4">h4</Typography>
<Typography as="h5">h5</Typography>
<Typography as="h6">h6</Typography>
<Typography as="li">li</Typography>
<Typography as="p">p</Typography>
<Typography as="span">span</Typography>
<Typography as="strong">strong</Typography>
```
Renders the html:
```html
<dd>dd</dd>
<div>div</div>
<dt>dt</dt>
<em>em</em>
<h1>h1</h1>
<h2>h2</h2>
<h3>h3</h3>
<h4>h4</h4>
<h5>h5</h5>
<h6>h6</h6>
<li>li</li>
<p>p</p>
<span>span</span>
<strong>strong</strong>
```

@ -57,7 +57,7 @@ export default function Typography({
align,
overflowWrap,
title,
tag,
as,
margin,
marginTop = 1,
marginRight,
@ -67,7 +67,7 @@ export default function Typography({
className,
children,
}) {
let Tag = tag ?? variant;
let Tag = as ?? variant;
let strongTagFontWeight;
if (Tag === 'strong') {
@ -147,9 +147,9 @@ Typography.propTypes = {
*/
overflowWrap: PropTypes.oneOf(Object.values(OVERFLOW_WRAP)),
/**
* Changes the root html element tag of the Typography component.
* Changes the root html element of the Typography component.
*/
tag: PropTypes.oneOf(ValidTags),
as: PropTypes.oneOf(ValidTags),
/**
* Adds margin to the Typography component should use valid size
*/

@ -6,7 +6,9 @@ import {
TEXT_ALIGN,
TYPOGRAPHY,
OVERFLOW_WRAP,
DISPLAY,
} from '../../../helpers/constants/design-system';
import Box from '../box';
import { ValidColors, ValidTags } from './typography';
@ -49,7 +51,7 @@ export default {
control: { type: 'select' },
options: Object.values(OVERFLOW_WRAP),
},
tag: {
as: {
control: { type: 'select' },
options: ValidTags,
},
@ -249,18 +251,27 @@ export const OverflowWrap = (args) => (
</div>
);
export const Tag = (args) => (
export const As = (args) => (
<>
{Object.values(ValidTags).map((tag) => (
<Typography
boxProps={{ backgroundColor: renderBackgroundColor(args.color) }}
{...args}
tag={tag}
key={tag}
>
{tag}
</Typography>
))}
<Typography boxProps={{ display: DISPLAY.BLOCK }} marginBottom={4}>
You can change the root element of the Typography component using the as
prop. Inspect the below elements to see the underlying HTML elements
</Typography>
<Box gap={4}>
{Object.values(ValidTags).map((as) => (
<Typography
{...args}
as={as}
key={as}
boxProps={{
backgroundColor: renderBackgroundColor(args.color),
display: DISPLAY.BLOCK,
}}
>
{as}
</Typography>
))}
</Box>
</>
);

@ -7,52 +7,52 @@ describe('Typography', () => {
const { getByText } = render(<Typography>Test type</Typography>);
expect(getByText('Test type')).toBeDefined();
});
it('should render the Typography with correct html tags', () => {
it('should render the Typography with correct html elements', () => {
const { getByText, container } = render(
<>
<Typography tag="p">p tag</Typography>
<Typography tag="h1">h1 tag</Typography>
<Typography tag="h2">h2 tag</Typography>
<Typography tag="h3">h3 tag</Typography>
<Typography tag="h4">h4 tag</Typography>
<Typography tag="h5">h5 tag</Typography>
<Typography tag="h6">h6 tag</Typography>
<Typography tag="span">span tag</Typography>
<Typography tag="strong">strong tag</Typography>
<Typography tag="em">em tag</Typography>
<Typography tag="li">li tag</Typography>
<Typography tag="div">div tag</Typography>
<Typography tag="dt">dt tag</Typography>
<Typography tag="dd">dd tag</Typography>
<Typography as="p">p</Typography>
<Typography as="h1">h1</Typography>
<Typography as="h2">h2</Typography>
<Typography as="h3">h3</Typography>
<Typography as="h4">h4</Typography>
<Typography as="h5">h5</Typography>
<Typography as="h6">h6</Typography>
<Typography as="span">span</Typography>
<Typography as="strong">strong</Typography>
<Typography as="em">em</Typography>
<Typography as="li">li</Typography>
<Typography as="div">div</Typography>
<Typography as="dt">dt</Typography>
<Typography as="dd">dd</Typography>
</>,
);
expect(container.querySelector('p')).toBeDefined();
expect(getByText('p tag')).toBeDefined();
expect(getByText('p')).toBeDefined();
expect(container.querySelector('h1')).toBeDefined();
expect(getByText('h1 tag')).toBeDefined();
expect(getByText('h1')).toBeDefined();
expect(container.querySelector('h2')).toBeDefined();
expect(getByText('h2 tag')).toBeDefined();
expect(getByText('h2')).toBeDefined();
expect(container.querySelector('h3')).toBeDefined();
expect(getByText('h3 tag')).toBeDefined();
expect(getByText('h3')).toBeDefined();
expect(container.querySelector('h4')).toBeDefined();
expect(getByText('h4 tag')).toBeDefined();
expect(getByText('h4')).toBeDefined();
expect(container.querySelector('h5')).toBeDefined();
expect(getByText('h5 tag')).toBeDefined();
expect(getByText('h5')).toBeDefined();
expect(container.querySelector('h6')).toBeDefined();
expect(getByText('h6 tag')).toBeDefined();
expect(getByText('h6')).toBeDefined();
expect(container.querySelector('span')).toBeDefined();
expect(getByText('span tag')).toBeDefined();
expect(getByText('span')).toBeDefined();
expect(container.querySelector('strong')).toBeDefined();
expect(getByText('strong tag')).toBeDefined();
expect(getByText('strong')).toBeDefined();
expect(container.querySelector('em')).toBeDefined();
expect(getByText('em tag')).toBeDefined();
expect(getByText('em')).toBeDefined();
expect(container.querySelector('li')).toBeDefined();
expect(getByText('li tag')).toBeDefined();
expect(getByText('li')).toBeDefined();
expect(container.querySelector('div')).toBeDefined();
expect(getByText('div tag')).toBeDefined();
expect(getByText('div')).toBeDefined();
expect(container.querySelector('dt')).toBeDefined();
expect(getByText('dt tag')).toBeDefined();
expect(getByText('dt')).toBeDefined();
expect(container.querySelector('dd')).toBeDefined();
expect(getByText('dd tag')).toBeDefined();
expect(getByText('dd')).toBeDefined();
});
});

@ -97,7 +97,7 @@ export default function SeedPhraseIntro() {
>
<Box marginBottom={4}>
<Typography
tag="span"
as="span"
color={COLORS.TEXT_DEFAULT}
fontWeight={FONT_WEIGHT.BOLD}
boxProps={{ display: 'block' }}
@ -108,7 +108,7 @@ export default function SeedPhraseIntro() {
</Box>
<Box marginBottom={4}>
<Typography
tag="span"
as="span"
color={COLORS.TEXT_DEFAULT}
fontWeight={FONT_WEIGHT.BOLD}
boxProps={{ display: 'block' }}
@ -124,7 +124,7 @@ export default function SeedPhraseIntro() {
</Box>
<Box marginBottom={4}>
<Typography
tag="span"
as="span"
color={COLORS.TEXT_DEFAULT}
fontWeight={FONT_WEIGHT.BOLD}
boxProps={{ display: 'block' }}

@ -127,20 +127,20 @@ export default function SecureYourWallet() {
<Box className="secure-your-wallet__desc">
<Box marginBottom={4}>
<Typography
tag="p"
as="p"
variant={TYPOGRAPHY.H4}
fontWeight={FONT_WEIGHT.BOLD}
boxProps={{ display: DISPLAY.BLOCK }}
>
{t('seedPhraseIntroSidebarTitleOne')}
</Typography>
<Typography tag="p" variant={TYPOGRAPHY.H4}>
<Typography as="p" variant={TYPOGRAPHY.H4}>
{t('seedPhraseIntroSidebarCopyOne')}
</Typography>
</Box>
<Box marginBottom={4}>
<Typography
tag="p"
as="p"
variant={TYPOGRAPHY.H4}
fontWeight={FONT_WEIGHT.BOLD}
boxProps={{ display: DISPLAY.BLOCK }}
@ -155,19 +155,19 @@ export default function SecureYourWallet() {
</Box>
<Box marginBottom={6}>
<Typography
tag="p"
as="p"
variant={TYPOGRAPHY.H4}
fontWeight={FONT_WEIGHT.BOLD}
boxProps={{ display: DISPLAY.BLOCK }}
>
{t('seedPhraseIntroSidebarTitleThree')}
</Typography>
<Typography tag="p" variant={TYPOGRAPHY.H4}>
<Typography as="p" variant={TYPOGRAPHY.H4}>
{t('seedPhraseIntroSidebarCopyTwo')}
</Typography>
</Box>
<Box className="secure-your-wallet__highlighted" marginBottom={2}>
<Typography tag="p" variant={TYPOGRAPHY.H4}>
<Typography as="p" variant={TYPOGRAPHY.H4}>
{t('seedPhraseIntroSidebarCopyThree')}
</Typography>
</Box>

@ -77,7 +77,7 @@ export default function SnapInstall({
padding: [4, 4, 0, 4],
}}
variant={TYPOGRAPHY.H7}
tag="span"
as="span"
>
{t('snapRequestsPermission')}
</Typography>

@ -76,7 +76,7 @@ export default function SnapUpdate({
padding: [4, 4, 0, 4],
}}
variant={TYPOGRAPHY.H7}
tag="span"
as="span"
>
{t('snapUpdateExplanation', [`${request.metadata.dappOrigin}`])}
</Typography>
@ -85,7 +85,7 @@ export default function SnapUpdate({
padding: [2, 4, 0, 4],
}}
variant={TYPOGRAPHY.H7}
tag="span"
as="span"
>
{t('snapRequestsPermission')}
</Typography>

@ -111,7 +111,7 @@ export default function AwaitingSignatures() {
<SwapStepIcon stepNumber={1} />
{t('swapAllowSwappingOf', [
<Typography
tag="span"
as="span"
fontWeight={FONT_WEIGHT.BOLD}
key="allowToken"
>
@ -123,14 +123,14 @@ export default function AwaitingSignatures() {
<SwapStepIcon stepNumber={2} />
{t('swapFromTo', [
<Typography
tag="span"
as="span"
fontWeight={FONT_WEIGHT.BOLD}
key="tokenFrom"
>
{sourceTokenInfo?.symbol}
</Typography>,
<Typography
tag="span"
as="span"
fontWeight={FONT_WEIGHT.BOLD}
key="tokenTo"
>

@ -626,7 +626,7 @@ export default function BuildQuote({
{t('stxDescription')}
</Typography>
<Typography
tag="ul"
as="ul"
variant={TYPOGRAPHY.H7}
fontWeight={FONT_WEIGHT.BOLD}
marginTop={3}
@ -637,7 +637,7 @@ export default function BuildQuote({
<li>
{t('stxBenefit4')}
<Typography
tag="span"
as="span"
fontWeight={FONT_WEIGHT.NORMAL}
variant={TYPOGRAPHY.H7}
>
@ -652,7 +652,7 @@ export default function BuildQuote({
>
{t('stxSubDescription')}&nbsp;
<Typography
tag="span"
as="span"
fontWeight={FONT_WEIGHT.BOLD}
variant={TYPOGRAPHY.H8}
color={COLORS.TEXT_ALTERNATIVE}

@ -118,7 +118,7 @@ export default function FeeCard({
secondaryFee?.maxFee !== undefined && (
<>
<Typography
tag="span"
as="span"
fontWeight={FONT_WEIGHT.BOLD}
color={COLORS.TEXT_ALTERNATIVE}
variant={TYPOGRAPHY.H7}

Loading…
Cancel
Save