diff --git a/.storybook/metamask-storybook-theme.js b/.storybook/metamask-storybook-theme.js index 49f8c814d..2bba8734c 100644 --- a/.storybook/metamask-storybook-theme.js +++ b/.storybook/metamask-storybook-theme.js @@ -7,6 +7,6 @@ export default create({ brandTitle: 'MetaMask Storybook', // Typography - fontBase: 'Euclid, Roboto, Helvetica, Arial, sans-serif', + fontBase: 'Euclid Circular B, Roboto, Helvetica, Arial, sans-serif', fontCode: 'Inconsolata, monospace', }); diff --git a/app/fonts/Euclid/EuclidCircularB-Medium.ttf b/app/fonts/Euclid/EuclidCircularB-Medium.ttf new file mode 100644 index 000000000..7a2ae44a1 Binary files /dev/null and b/app/fonts/Euclid/EuclidCircularB-Medium.ttf differ diff --git a/package.json b/package.json index c6dbf98e9..23f29b1c4 100644 --- a/package.json +++ b/package.json @@ -123,7 +123,7 @@ "@material-ui/core": "^4.11.0", "@metamask/contract-metadata": "^1.31.0", "@metamask/controllers": "^30.1.0", - "@metamask/design-tokens": "^1.8.0", + "@metamask/design-tokens": "^1.9.0", "@metamask/eth-ledger-bridge-keyring": "^0.13.0", "@metamask/eth-token-tracker": "^4.0.0", "@metamask/etherscan-link": "^2.1.0", diff --git a/ui/components/component-library/component-library-components.scss b/ui/components/component-library/component-library-components.scss index fddd92321..28e1daeff 100644 --- a/ui/components/component-library/component-library-components.scss +++ b/ui/components/component-library/component-library-components.scss @@ -2,3 +2,4 @@ @import 'avatar-token/avatar-token'; @import 'base-avatar/base-avatar'; @import 'base-icon/base-icon'; +@import 'text/text'; diff --git a/ui/components/component-library/text/README.mdx b/ui/components/component-library/text/README.mdx new file mode 100644 index 000000000..197cebb2b --- /dev/null +++ b/ui/components/component-library/text/README.mdx @@ -0,0 +1,302 @@ +import { Story, Canvas, ArgsTable } from '@storybook/addon-docs'; +import ActionableMessage from '../../ui/actionable-message'; +import { Text } from './text'; + +# Text + +> This Text (fka Typography) component has breaking changes in variant options and the line heights associated to each variant. + +Good typography improves readability, legibility and hierarchy of information. + + + + + +## Props + + + +### Variant + +Use the `variant` prop and the `TEXT` object from `./ui/helpers/constants/design-system.js` to change the font size of the component. + + + + + +```jsx +import { Text } from '../../ui/component-library/text'; +import { TEXT } from '../../../helpers/constants/design-system'; + +display-md +heading-lg +heading-md +heading-sm +body-md +body-sm +body-xs +``` + +### Color + +Use the `color` prop and the `COLORS` object from `./ui/helpers/constants/design-system.js` to change the color of the `Text` component. + + + + + +```jsx +import { Text } from '../../ui/component-library/text'; +import { COLORS } from '../../../helpers/constants/design-system'; + + + text-default + + + text-alternative + + + text-muted + + + overlay-inverse + + + primary-default + + + primary-inverse + + + error-default + + + error-inverse + + + success-default + + + success-inverse + + + warning-inverse + + + info-default + + + info-inverse + +``` + +### Font Weight + +Use the `fontWeight` prop and the `FONT_WEIGHT` object from `./ui/helpers/constants/design-system.js` to change the font weight of the `Text` component. There are 3 font weights: + +- `FONT_WEIGHT.NORMAL` = `normal` || `400` +- `FONT_WEIGHT.MEDIUM` = `medium` || `500` +- `FONT_WEIGHT.BOLD` = `bold` || `700` + + + + + +```jsx +import { Text } from '../../ui/component-library/text'; +import { FONT_WEIGHT } from '../../../helpers/constants/design-system'; + + + normal + + + medium + + + bold + +``` + +### Font Style + +Use the `fontStyle` prop and the `FONT_STYLE` object from `./ui/helpers/constants/design-system.js` to change the font style of the `Text` component. There are 2 font styles: + +- `FONT_STYLE.NORMAL` +- `FONT_STYLE.ITALIC` + + + + + +```jsx +import { Text } from '../../ui/component-library/text'; +import { FONT_STYLE } from '../../../helpers/constants/design-system'; + + + normal + + + bold + +``` + +### Text Transform + +Use the `textTransform` prop and the `TEXT_TRANSFORM` object from `./ui/helpers/constants/design-system.js` to change the text alignment of the `Text` component + + + + + +```jsx +import { Text } from '../../ui/component-library/text'; +import { TEXT_TRANSFORM } from '../../../helpers/constants/design-system'; + + + uppercase + + + lowercase + + + capitalize + +``` + +### Text Align + +Use the `textAlign` prop and the `TEXT_ALIGN` object from `./ui/helpers/constants/design-system.js` to change the text alignment of the `Text` component + + + + + +```jsx +import { Text } from '../../ui/component-library/text'; +import { TEXT_ALIGN } from '../../../helpers/constants/design-system'; + + + left + + + center + + + right + + + justify + + + end + +``` + +### Overflow Wrap + +Use the `overflowWrap` prop and the `OVERFLOW_WRAP` object from `./ui/helpers/constants/design-system.js` to change the overflow wrap of the `Text` component + + + + + +```jsx +import { Text } from '../../ui/component-library/text'; +import { OVERFLOW_WRAP } from '../../../helpers/constants/design-system'; + +
+ + {OVERFLOW_WRAP.NORMAL}: 0x39013f961c378f02c2b82a6e1d31e9812786fd9d + + + {OVERFLOW_WRAP.BREAK_WORD}: 0x39013f961c378f02c2b82a6e1d31e9812786fd9d + +
; +``` + +### Ellipsis + +Use the boolean `ellipsis` prop to change the if the `Text` component to have an ellipsis. + + + + + +```jsx +import { Text } from '../../ui/component-library/text'; + +
+ Ellipsis: 0x39013f961c378f02c2b82a6e1d31e9812786fd9d + No Ellipsis: 0x39013f961c378f02c2b82a6e1d31e9812786fd9d +
; +``` + +### As + +Use the `as` prop to change the root html element of the `Text` component + + + + + +```jsx +import { Text } from '../../ui/component-library/text'; + +dd +div +dt +em +h1 +h2 +h3 +h4 +h5 +h6 +li +p +span +strong +``` + +Renders the html: + +```html +
dd
+
div
+
dt
+em +

h1

+

h2

+

h3

+

h4

+
h5
+
h6
+
  • li
  • +

    p

    +span +strong +``` + +### Box Props + +Use any valid box props [Box](/?path=/story/ui-components-ui-box-box-stories-js--default-story) component props to the Text component. + +### Class Name + +Adds an additional class to the `Text` component + +### Children + +The text content of the `Text` component diff --git a/ui/components/component-library/text/index.js b/ui/components/component-library/text/index.js new file mode 100644 index 000000000..8463c3cf8 --- /dev/null +++ b/ui/components/component-library/text/index.js @@ -0,0 +1 @@ +export { Text } from './text'; diff --git a/ui/components/component-library/text/text.js b/ui/components/component-library/text/text.js new file mode 100644 index 000000000..3ca747b69 --- /dev/null +++ b/ui/components/component-library/text/text.js @@ -0,0 +1,145 @@ +import React from 'react'; +import classnames from 'classnames'; +import PropTypes from 'prop-types'; +import Box from '../../ui/box'; +import { + FONT_WEIGHT, + FONT_STYLE, + TEXT, + TEXT_ALIGN, + TEXT_TRANSFORM, + OVERFLOW_WRAP, + TEXT_COLORS, +} from '../../../helpers/constants/design-system'; + +export const ValidTags = [ + 'dd', + 'div', + 'dt', + 'em', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'li', + 'p', + 'span', + 'strong', + 'ul', + 'label', +]; + +export const Text = ({ + variant = TEXT.BODY_MD, + color = TEXT_COLORS.TEXT_DEFAULT, + fontWeight, + fontStyle, + textTransform, + textAlign, + overflowWrap, + ellipsis, + as, + className, + children, + ...props +}) => { + let Tag = as ?? variant; + let strongTagFontWeight; + + if (Tag === 'strong') { + strongTagFontWeight = FONT_WEIGHT.BOLD; + } + + const computedClassName = classnames( + 'text', + className, + `text--${variant}`, + (strongTagFontWeight || fontWeight) && + `text--font-weight-${strongTagFontWeight || fontWeight}`, + { + [`text--font-style-${fontStyle}`]: Boolean(fontStyle), + [`text--ellipsis`]: Boolean(ellipsis), + [`text--text-transform-${textTransform}`]: Boolean(textTransform), + [`text--text-align-${textAlign}`]: Boolean(textAlign), + [`text--color-${color}`]: Boolean(color), + [`text--overflow-wrap-${overflowWrap}`]: Boolean(overflowWrap), + }, + ); + + // // Set a default tag based on variant + const splitTag = Tag.split('-')[0]; + if (splitTag === 'body') { + Tag = 'p'; + } else if (splitTag === 'heading') { + Tag = 'h2'; + } else if (splitTag === 'display') { + Tag = 'h1'; + } + + return ( + + {children} + + ); +}; + +Text.propTypes = { + /** + * The variation of font styles including sizes and weights of the Text component (display, heading, body) + */ + variant: PropTypes.oneOf(Object.values(TEXT)), + /** + * The color of the Text component Should use the COLOR object from + * ./ui/helpers/constants/design-system.js + */ + color: PropTypes.oneOf(Object.values(TEXT_COLORS)), + /** + * The font-weight of the Text component. Should use the FONT_WEIGHT object from + * ./ui/helpers/constants/design-system.js + */ + fontWeight: PropTypes.oneOf(Object.values(FONT_WEIGHT)), + /** + * The font-style of the Text component. Should use the FONT_STYLE object from + * ./ui/helpers/constants/design-system.js + */ + fontStyle: PropTypes.oneOf(Object.values(FONT_STYLE)), + /** + * The textTransform of the Text component. Should use the TEXT_TRANSFORM object from + * ./ui/helpers/constants/design-system.js + */ + textTransform: PropTypes.oneOf(Object.values(TEXT_TRANSFORM)), + /** + * The text-align of the Text component. Should use the TEXT_ALIGN object from + * ./ui/helpers/constants/design-system.js + */ + textAlign: PropTypes.oneOf(Object.values(TEXT_ALIGN)), + /** + * The overflow-wrap of the Text component. Should use the OVERFLOW_WRAP object from + * ./ui/helpers/constants/design-system.js + */ + overflowWrap: PropTypes.oneOf(Object.values(OVERFLOW_WRAP)), + /** + * Used for long strings that can be cut off... + */ + ellipsis: PropTypes.bool, + /** + * Changes the root html element tag of the Text component. + */ + as: PropTypes.oneOf(ValidTags), + /** + * Additional className to assign the Text component + */ + className: PropTypes.string, + /** + * The text content of the Text component + */ + children: PropTypes.node.isRequired, + /** + * Text component accepts all Box component props + */ + ...Box.propTypes, +}; + +export default Text; diff --git a/ui/components/component-library/text/text.scss b/ui/components/component-library/text/text.scss new file mode 100644 index 000000000..5d1ad4e01 --- /dev/null +++ b/ui/components/component-library/text/text.scss @@ -0,0 +1,104 @@ +@use "design-system"; +@use "sass:map"; + +$text-variants: ( + display: ("md"), + heading: ( "sm", "md", "lg"), + body: ("xs", "sm", "sm-bold", "md", "md-bold", "lg-medium"), +); + +// Variable output mixin +// screen size, type, size + +@mixin textVariables($type, $size) { + font-family: var(--typography-s-#{$type}-#{$size}-font-family); + font-weight: var(--typography-s-#{$type}-#{$size}-font-weight); + font-size: var(--typography-s-#{$type}-#{$size}-font-size); + line-height: var(--typography-s-#{$type}-#{$size}-line-height); + letter-spacing: var(--typography-s-#{$type}-#{$size}-letter-spacing); + + @include screen-md-min { + font-family: var(--typography-l-#{$type}-#{$size}-font-family); + font-weight: var(--typography-l-#{$type}-#{$size}-font-weight); + font-size: var(--typography-l-#{$type}-#{$size}-font-size); + line-height: var(--typography-l-#{$type}-#{$size}-line-height); + letter-spacing: var(--typography-l-#{$type}-#{$size}-letter-spacing); + } +} + + + +.text { + // Set default styles + color: var(--color-text-default); + font-family: var(----font-family-sans); + + @each $type, $size-options in $text-variants { + &--#{$type} { + // Sets a default + @include textVariables($type, "md"); + // Generates all the size options + @each $size in $size-options { + &-#{$size} { + @include textVariables($type, $size); + } + } + } + } + + @each $variant, $color in $color-map { + &--color-#{$variant} { + color: var($color); + } + } + + @each $weight in $font-weight { + &--font-weight-#{$weight} { + @if $weight == "medium" { + font-weight: var(--font-weight-medium); + } + + @else { + font-weight: $weight; + } + } + } + + @each $style in $font-style { + &--font-style-#{$style} { + font-style: $style; + } + } + + @each $alignment in $text-align { + &--text-align-#{$alignment} { + text-align: $alignment; + } + } + + @each $overflow in $overflow-wrap { + &--overflow-wrap-#{$overflow} { + overflow-wrap: $overflow; + } + } + + &--ellipsis { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + } + + &--text-transform-uppercase { + text-transform: uppercase; + } + + &--text-transform-lowercase { + text-transform: lowercase; + } + + &--text-transform-capitalize { + text-transform: capitalize; + } +} + + diff --git a/ui/components/component-library/text/text.stories.js b/ui/components/component-library/text/text.stories.js new file mode 100644 index 000000000..2b8fbfa15 --- /dev/null +++ b/ui/components/component-library/text/text.stories.js @@ -0,0 +1,270 @@ +import React from 'react'; +import { + COLORS, + DISPLAY, + BACKGROUND_COLORS, + BORDER_COLORS, + FONT_WEIGHT, + FONT_STYLE, + TEXT_COLORS, + TEXT_ALIGN, + TEXT, + OVERFLOW_WRAP, + TEXT_TRANSFORM, + FRACTIONS, +} from '../../../helpers/constants/design-system'; + +import Box from '../../ui/box'; +import { ValidTags, Text } from './text'; + +import README from './README.mdx'; + +const sizeKnobOptions = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; +const marginSizeKnobOptions = [...sizeKnobOptions, 'auto']; + +export default { + title: 'Components/ComponentLibrary/Text', + id: __filename, + parameters: { + docs: { + page: README, + }, + }, + argTypes: { + variant: { + control: { type: 'select' }, + options: Object.values(TEXT), + }, + color: { + control: { type: 'select' }, + options: Object.values(TEXT_COLORS), + }, + 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, + }, + className: { + control: { type: 'text' }, + }, + children: { + control: { type: 'text' }, + }, + display: { + options: Object.values(DISPLAY), + control: 'select', + table: { category: 'box props' }, + }, + backgroundColor: { + options: Object.values(BACKGROUND_COLORS), + control: 'select', + table: { category: 'box props' }, + }, + borderColor: { + options: Object.values(BORDER_COLORS), + 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) { + let bgColor; + switch (color) { + case COLORS.OVERLAY_INVERSE: + bgColor = COLORS.OVERLAY_DEFAULT; + break; + case COLORS.PRIMARY_INVERSE: + bgColor = COLORS.PRIMARY_DEFAULT; + break; + case COLORS.ERROR_INVERSE: + bgColor = COLORS.ERROR_DEFAULT; + break; + case COLORS.WARNING_INVERSE: + bgColor = COLORS.WARNING_DEFAULT; + break; + case COLORS.SUCCESS_INVERSE: + bgColor = COLORS.SUCCESS_DEFAULT; + break; + case COLORS.INFO_INVERSE: + bgColor = COLORS.INFO_DEFAULT; + break; + default: + bgColor = null; + break; + } + + return bgColor; +} + +export const DefaultStory = (args) => {args.children}; + +DefaultStory.storyName = 'Default'; + +DefaultStory.args = { + children: 'The quick orange fox jumped over the lazy dog.', +}; + +export const Variant = (args) => ( + <> + {Object.values(TEXT).map((variant) => ( + + {args.children || variant} + + ))} + +); + +export const Color = (args) => { + // Index of last valid color in TEXT_COLORS array + return ( + <> + {Object.values(TEXT_COLORS).map((color) => { + return ( + + {color} + + ); + })} + + ); +}; + +export const FontWeight = (args) => ( + <> + {Object.values(FONT_WEIGHT).map((weight) => ( + + {weight} + + ))} + +); + +export const FontStyle = (args) => ( + <> + {Object.values(FONT_STYLE).map((style) => ( + + {style} + + ))} + +); + +export const TextTransform = (args) => ( + <> + {Object.values(TEXT_TRANSFORM).map((transform) => ( + + {transform} + + ))} + +); + +export const TextAlign = (args) => ( + <> + {Object.values(TEXT_ALIGN).map((align) => ( + + {align} + + ))} + +); + +export const OverflowWrap = (args) => ( + + + {OVERFLOW_WRAP.NORMAL}: 0x39013f961c378f02c2b82a6e1d31e9812786fd9d + + + {OVERFLOW_WRAP.BREAK_WORD}: 0x39013f961c378f02c2b82a6e1d31e9812786fd9d + + +); + +export const Ellipsis = (args) => ( + + + Ellipsis: 0x39013f961c378f02c2b82a6e1d31e9812786fd9d + + + No Ellipsis: 0x39013f961c378f02c2b82a6e1d31e9812786fd9d + + +); + +export const As = (args) => ( + <> + {Object.values(ValidTags).map((tag) => ( +
    + + {tag} + +
    + ))} + +); diff --git a/ui/components/component-library/text/text.test.js b/ui/components/component-library/text/text.test.js new file mode 100644 index 000000000..84a8f1672 --- /dev/null +++ b/ui/components/component-library/text/text.test.js @@ -0,0 +1,221 @@ +import * as React from 'react'; +import { render } from '@testing-library/react'; +import { + COLORS, + FONT_STYLE, + FONT_WEIGHT, + OVERFLOW_WRAP, + TEXT, + TEXT_ALIGN, + TEXT_TRANSFORM, +} from '../../../helpers/constants/design-system'; +import { Text } from '.'; + +describe('Text', () => { + it('should render the Text without crashing', () => { + const { getByText } = render(Test type); + expect(getByText('Test type')).toBeDefined(); + }); + it('should render the Text with correct html elements', () => { + const { getByText, container } = render( + <> + p + h1 + h2 + h3 + h4 + h5 + h6 + span + strong + em + li + div + dt + dd + , + ); + 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 } = render( + <> + display-md + heading-lg + heading-md + heading-sm + body-lg-medium + body-md + body-sm + body-xs + , + ); + + expect(getByText('display-md')).toHaveClass('text--display-md'); + expect(getByText('heading-lg')).toHaveClass('text--heading-lg'); + expect(getByText('heading-md')).toHaveClass('text--heading-md'); + expect(getByText('heading-sm')).toHaveClass('text--heading-sm'); + expect(getByText('body-lg-medium')).toHaveClass('text--body-lg-medium'); + expect(getByText('body-md')).toHaveClass('text--body-md'); + expect(getByText('body-sm')).toHaveClass('text--body-sm'); + expect(getByText('body-xs')).toHaveClass('text--body-xs'); + }); + + it('should render the Text with proper font weight class name', () => { + const { getByText } = render( + <> + bold + medium + normal + , + ); + expect(getByText('bold')).toHaveClass('text--font-weight-bold'); + expect(getByText('medium')).toHaveClass('text--font-weight-medium'); + expect(getByText('normal')).toHaveClass('text--font-weight-normal'); + }); + + it('should render the Text with proper text color class name', () => { + const { getByText } = render( + <> + text-default + text-alternative + text-muted + overlay-inverse + primary-default + primary-inverse + error-default + error-inverse + success-default + success-inverse + warning-inverse + info-default + info-inverse + , + ); + expect(getByText('text-default')).toHaveClass('text--color-text-default'); + expect(getByText('text-alternative')).toHaveClass( + 'text--color-text-alternative', + ); + expect(getByText('text-muted')).toHaveClass('text--color-text-muted'); + expect(getByText('overlay-inverse')).toHaveClass( + 'text--color-overlay-inverse', + ); + expect(getByText('primary-default')).toHaveClass( + 'text--color-primary-default', + ); + expect(getByText('primary-inverse')).toHaveClass( + 'text--color-primary-inverse', + ); + expect(getByText('error-default')).toHaveClass('text--color-error-default'); + expect(getByText('error-inverse')).toHaveClass('text--color-error-inverse'); + expect(getByText('success-default')).toHaveClass( + 'text--color-success-default', + ); + expect(getByText('success-inverse')).toHaveClass( + 'text--color-success-inverse', + ); + expect(getByText('warning-inverse')).toHaveClass( + 'text--color-warning-inverse', + ); + expect(getByText('info-default')).toHaveClass('text--color-info-default'); + expect(getByText('info-inverse')).toHaveClass('text--color-info-inverse'); + }); + + it('should render the Text with proper font style class name', () => { + const { getByText } = render( + <> + italic + normal + , + ); + expect(getByText('italic')).toHaveClass('text--font-style-italic'); + expect(getByText('normal')).toHaveClass('text--font-style-normal'); + }); + + it('should render the Text with proper text align class name', () => { + const { getByText } = render( + <> + left + center + right + justify + end + , + ); + + expect(getByText('left')).toHaveClass('text--text-align-left'); + expect(getByText('center')).toHaveClass('text--text-align-center'); + expect(getByText('right')).toHaveClass('text--text-align-right'); + expect(getByText('justify')).toHaveClass('text--text-align-justify'); + expect(getByText('end')).toHaveClass('text--text-align-end'); + }); + + it('should render the Text with proper overflow wrap class name', () => { + const { getByText } = render( + <> + break-word + normal + , + ); + expect(getByText('break-word')).toHaveClass( + 'text--overflow-wrap-break-word', + ); + expect(getByText('normal')).toHaveClass('text--overflow-wrap-normal'); + }); + + it('should render the Text with proper ellipsis class name', () => { + const { getByText } = render( + <> + ellipsis + , + ); + expect(getByText('ellipsis')).toHaveClass('text--ellipsis'); + }); + + it('should render the Text with proper text transform class name', () => { + const { getByText } = render( + <> + uppercase + lowercase + capitalize + , + ); + expect(getByText('uppercase')).toHaveClass( + 'text--text-transform-uppercase', + ); + expect(getByText('lowercase')).toHaveClass( + 'text--text-transform-lowercase', + ); + expect(getByText('capitalize')).toHaveClass( + 'text--text-transform-capitalize', + ); + }); +}); diff --git a/ui/css/design-system/attributes.scss b/ui/css/design-system/attributes.scss index fb8c14451..e80e25026 100644 --- a/ui/css/design-system/attributes.scss +++ b/ui/css/design-system/attributes.scss @@ -45,7 +45,7 @@ $directions: top, right, bottom, left; $display: block, flex, grid, inline-block, inline-grid, inline-flex, list-item, none; $text-align: left, right, center, justify, end; $overflow-wrap: normal, break-word; -$font-weight: bold, normal, 100, 200, 300, 400, 500, 600, 700, 800, 900; +$font-weight: bold, medium, normal, 100, 200, 300, 400, 500, 600, 700, 800, 900; $font-style: normal, italic, oblique; $font-size: 10px, 12px; diff --git a/ui/css/design-system/typography.scss b/ui/css/design-system/typography.scss index 8bdc20f96..a7b16b46c 100644 --- a/ui/css/design-system/typography.scss +++ b/ui/css/design-system/typography.scss @@ -1,3 +1,5 @@ +@use "sass:map"; + $fa-font-path: 'fonts/fontawesome'; @import '../../../node_modules/@fortawesome/fontawesome-free/scss/fontawesome'; @@ -48,27 +50,34 @@ $fa-font-path: 'fonts/fontawesome'; } @font-face { - font-family: 'Euclid'; + font-family: 'Euclid Circular B'; font-style: normal; font-weight: 400; src: url('fonts/Euclid/EuclidCircularB-Regular-WebXL.ttf') format('truetype'); } @font-face { - font-family: 'Euclid'; + font-family: 'Euclid Circular B'; font-style: italic; font-weight: 400; src: url('fonts/Euclid/EuclidCircularB-RegularItalic-WebXL.ttf') format('truetype'); } @font-face { - font-family: 'Euclid'; + font-family: 'Euclid Circular B'; + font-style: normal; + font-weight: 500; + src: url('fonts/Euclid/EuclidCircularB-Medium.ttf') format('truetype'); +} + +@font-face { + font-family: 'Euclid Circular B'; font-style: normal; font-weight: 700; src: url('fonts/Euclid/EuclidCircularB-Bold-WebXL.ttf') format('truetype'); } -$font-family: Euclid, Roboto, Helvetica, Arial, sans-serif; +$font-family: 'Euclid Circular B', Roboto, Helvetica, Arial, sans-serif; $typography-variants: ( 'h1': 2.5rem, diff --git a/ui/helpers/constants/design-system.js b/ui/helpers/constants/design-system.js index 699f8bbe4..bc0ffebc6 100644 --- a/ui/helpers/constants/design-system.js +++ b/ui/helpers/constants/design-system.js @@ -158,6 +158,17 @@ export const TYPOGRAPHY = { Paragraph: 'p', }; +export const TEXT = { + DISPLAY_MD: 'display-md', + HEADING_LG: 'heading-lg', + HEADING_MD: 'heading-md', + HEADING_SM: 'heading-sm', + BODY_LG: 'body-lg-medium', + BODY_MD: 'body-md', + BODY_SM: 'body-sm', + BODY_XS: 'body-xs', +}; + const NONE = 'none'; export const SIZES = { @@ -269,8 +280,15 @@ export const TEXT_ALIGN = { END: 'end', }; +export const TEXT_TRANSFORM = { + UPPERCASE: 'uppercase', + LOWERCASE: 'lowercase', + CAPITALIZE: 'capitalize', +}; + export const FONT_WEIGHT = { BOLD: 'bold', + MEDIUM: 'medium', NORMAL: 'normal', }; diff --git a/yarn.lock b/yarn.lock index dbb217cb7..1c33fa9f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2914,10 +2914,10 @@ web3 "^0.20.7" web3-provider-engine "^16.0.3" -"@metamask/design-tokens@^1.6.0", "@metamask/design-tokens@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@metamask/design-tokens/-/design-tokens-1.8.0.tgz#072f455d23e4650ee81681ef066a99a56a9b573a" - integrity sha512-EO0WaMRPcegh2EPWdmAqtFX0aZ7hO0NyJasUQyVrYeN1XNGUC2WzXfqwaI0wSV79NE/WEE3c9g5se+MQMExLew== +"@metamask/design-tokens@^1.6.0", "@metamask/design-tokens@^1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@metamask/design-tokens/-/design-tokens-1.9.0.tgz#2b173c671f36b0d3faa2e31ea4bf66e811a7ff49" + integrity sha512-L3oIhbE7MVQgiX7bEqdlU32jNyLbYXCj9sJNCOzACIHycB1TIO8TS34dEI7FAf9pC8o0qvMI3k8ur+SD9myVxw== "@metamask/eslint-config-jest@^9.0.0": version "9.0.0"