From 4b734a0e0deb2d2e1e7a209b33b14ba821a57b3a Mon Sep 17 00:00:00 2001 From: Alexey Ryabov Date: Sat, 21 Mar 2020 12:58:31 +0300 Subject: [PATCH] [Typography] Add ability to specify custom variants --- docs/pages/api-docs/typography.md | 2 +- .../pages/components/typography/typography.md | 4 ++ .../typography/CustomVariants.js | 44 ++++++++++++++++ .../typography/CustomVariants.tsx | 52 +++++++++++++++++++ .../customization/typography/typography.md | 28 ++++++++++ .../material-ui/src/Typography/Typography.js | 20 ++----- .../src/styles/createMuiTheme.test.js | 21 ++++++++ .../src/styles/createTypography.d.ts | 24 +++++++-- .../src/styles/createTypography.js | 2 + 9 files changed, 176 insertions(+), 21 deletions(-) create mode 100644 docs/src/pages/customization/typography/CustomVariants.js create mode 100644 docs/src/pages/customization/typography/CustomVariants.tsx diff --git a/docs/pages/api-docs/typography.md b/docs/pages/api-docs/typography.md index 62e430719bcfd3..019ccd0273d5cf 100644 --- a/docs/pages/api-docs/typography.md +++ b/docs/pages/api-docs/typography.md @@ -33,7 +33,7 @@ You can learn more about the difference by [reading this guide](/guides/minimizi | gutterBottom | bool | false | If `true`, the text will have a bottom margin. | | noWrap | bool | false | If `true`, the text will not wrap, but instead will truncate with a text overflow ellipsis.
Note that text overflow can only happen with block or inline-block level elements (the element needs to have a width in order to overflow). | | paragraph | bool | false | If `true`, the text will have a bottom margin. | -| variant | 'h1'
| 'h2'
| 'h3'
| 'h4'
| 'h5'
| 'h6'
| 'subtitle1'
| 'subtitle2'
| 'body1'
| 'body2'
| 'caption'
| 'button'
| 'overline'
| 'srOnly'
| 'inherit'
| 'body1' | Applies the theme typography styles. | +| variant | string | 'body1' | Applies the theme typography styles. | | variantMapping | object | { h1: 'h1', h2: 'h2', h3: 'h3', h4: 'h4', h5: 'h5', h6: 'h6', subtitle1: 'h6', subtitle2: 'h6', body1: 'p', body2: 'p',} | The component maps the variant prop to a range of different DOM element types. For instance, subtitle1 to `
`. If you wish to change that mapping, you can provide your own. Alternatively, you can use the `component` prop. | The `ref` is forwarded to the root element. diff --git a/docs/src/pages/components/typography/typography.md b/docs/src/pages/components/typography/typography.md index 2755101df3603b..ee1e9376e77f12 100644 --- a/docs/src/pages/components/typography/typography.md +++ b/docs/src/pages/components/typography/typography.md @@ -54,6 +54,10 @@ Hopefully, you might be able to take advantage of the [`typography`](/customizat {{"demo": "pages/components/typography/TypographyTheme.js"}} +## Custom Variants + +Sometimes default variants are not enough. For this reason you can [specify your variants via theme](/customization/typography#custom) + ## Changing the semantic element The Typography component uses the `variantMapping` property to associate a UI variant with a semantic element. diff --git a/docs/src/pages/customization/typography/CustomVariants.js b/docs/src/pages/customization/typography/CustomVariants.js new file mode 100644 index 00000000000000..f5112dc0b594e8 --- /dev/null +++ b/docs/src/pages/customization/typography/CustomVariants.js @@ -0,0 +1,44 @@ +import React from 'react'; +import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles'; +import Typography from '@material-ui/core/Typography'; + +const theme = createMuiTheme({ + typography: { + customVariants: { + special1: { + fontSize: 15, + fontWeight: 600, + fontStyle: 'italic', + textTransform: 'uppercase', + }, + special2: { + fontSize: 12, + fontWeight: 300, + fontStyle: 'italic', + }, + }, + }, + props: { + MuiTypography: { + variantMapping: { + special1: 'h1', + special2: 'span', + }, + }, + }, +}); + +export default function CustomVariants() { + return ( +
+ + + Custom Variant + + + Custom Variant + + +
+ ); +} diff --git a/docs/src/pages/customization/typography/CustomVariants.tsx b/docs/src/pages/customization/typography/CustomVariants.tsx new file mode 100644 index 00000000000000..ea9caab8c0b876 --- /dev/null +++ b/docs/src/pages/customization/typography/CustomVariants.tsx @@ -0,0 +1,52 @@ +import React from 'react'; +import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles'; +import Typography from '@material-ui/core/Typography'; + +type CustomVariant = 'special1' | 'special2'; + +// You need to specify custom variant names via module augmentation +declare module '@material-ui/core/styles/createTypography' { + interface CustomVariants extends Record {} + interface CustomVariantsOptions extends Record {} +} + +const theme = createMuiTheme({ + typography: { + customVariants: { + special1: { + fontSize: 15, + fontWeight: 600, + fontStyle: 'italic', + textTransform: 'uppercase', + }, + special2: { + fontSize: 12, + fontWeight: 300, + fontStyle: 'italic', + }, + }, + }, + props: { + MuiTypography: { + variantMapping: { + special1: 'h1', + special2: 'span', + }, + }, + }, +}); + +export default function CustomVariants() { + return ( +
+ + + Custom Variant + + + Custom Variant + + +
+ ); +} diff --git a/docs/src/pages/customization/typography/typography.md b/docs/src/pages/customization/typography/typography.md index ef19e6a2217d70..68391e597bf86c 100644 --- a/docs/src/pages/customization/typography/typography.md +++ b/docs/src/pages/customization/typography/typography.md @@ -174,6 +174,8 @@ To be done: [#15251](https://github.com/mui-org/material-ui/issues/15251). ## Variants +### Built-in + The typography object comes with [13 variants](/components/typography/#component) by default: - h1 @@ -210,6 +212,32 @@ const theme = createMuiTheme({ {{"demo": "pages/customization/typography/TypographyVariants.js"}} +### Custom + +In addition to default variants, you can specify your custom variants: + +```js +const theme = createMuiTheme({ + typography: { + customVariants: { + special1: { + fontSize: 15, + fontWeight: 600, + fontStyle: 'italic', + textTransform: 'uppercase', + }, + special2: { + fontSize: 12, + fontWeight: 300, + fontStyle: 'italic', + }, + }, + }, +}); +``` + +{{"demo": "pages/customization/typography/CustomVariants.js"}} + ## Default values You can explore the default values of the typography using [the theme explorer](/customization/default-theme/?expand-path=$.typography) or by opening the dev tools console on this page (`window.theme.typography`). diff --git a/packages/material-ui/src/Typography/Typography.js b/packages/material-ui/src/Typography/Typography.js index b12f64103901f4..f7e090444f102e 100644 --- a/packages/material-ui/src/Typography/Typography.js +++ b/packages/material-ui/src/Typography/Typography.js @@ -5,6 +5,8 @@ import withStyles from '../styles/withStyles'; import capitalize from '../utils/capitalize'; export const styles = theme => ({ + /* Styles applied to the root element if `variant` is from user defined variants (customVariants). */ + ...theme.typography.customVariants, /* Styles applied to the root element. */ root: { margin: 0, @@ -219,23 +221,7 @@ Typography.propTypes = { /** * Applies the theme typography styles. */ - variant: PropTypes.oneOf([ - 'h1', - 'h2', - 'h3', - 'h4', - 'h5', - 'h6', - 'subtitle1', - 'subtitle2', - 'body1', - 'body2', - 'caption', - 'button', - 'overline', - 'srOnly', - 'inherit', - ]), + variant: PropTypes.string, /** * The component maps the variant prop to a range of different DOM element types. * For instance, subtitle1 to `
`. diff --git a/packages/material-ui/src/styles/createMuiTheme.test.js b/packages/material-ui/src/styles/createMuiTheme.test.js index bf23075e880458..cf4eec006b9cfd 100644 --- a/packages/material-ui/src/styles/createMuiTheme.test.js +++ b/packages/material-ui/src/styles/createMuiTheme.test.js @@ -117,6 +117,27 @@ describe('createMuiTheme', () => { }); }); + describe('typography customVariants', () => { + it('should provide the default value', () => { + const muiTheme = createMuiTheme(); + assert.deepEqual(muiTheme.typography.customVariants, {}); + }); + + it('should have the customVariants as expected', () => { + const customVariants = { + one: { + fontSize: '1.8rem', + }, + two: { + fontWeight: 300, + }, + }; + + const muiTheme = createMuiTheme({ typography: { customVariants } }); + assert.deepEqual(muiTheme.typography.customVariants, customVariants); + }); + }); + it('shallow merges multiple arguments', () => { const muiTheme = createMuiTheme({ foo: 'I am foo' }, { bar: 'I am bar' }); assert.strictEqual(muiTheme.foo, 'I am foo'); diff --git a/packages/material-ui/src/styles/createTypography.d.ts b/packages/material-ui/src/styles/createTypography.d.ts index 8bdcd0da96c225..8981271e63d184 100644 --- a/packages/material-ui/src/styles/createTypography.d.ts +++ b/packages/material-ui/src/styles/createTypography.d.ts @@ -15,7 +15,8 @@ export type Variant = | 'body2' | 'caption' | 'button' - | 'overline'; + | 'overline' + | keyof CustomVariants; export interface FontStyle extends Required<{ @@ -38,14 +39,31 @@ export interface FontStyleOptions extends Partial { export type TypographyStyle = CSSProperties; export interface TypographyStyleOptions extends TypographyStyle {} +export interface CustomVariants {} +export interface CustomVariantsOptions {} + +export interface TypographyCustomVariants { + customVariants: CustomVariants; +} + +export interface TypographyCustomVariantsOptions { + customVariants?: CustomVariantsOptions; +} + export interface TypographyUtils { pxToRem: (px: number) => string; } -export interface Typography extends Record, FontStyle, TypographyUtils {} +export interface Typography + extends Record, + FontStyle, + TypographyUtils, + TypographyCustomVariants {} export interface TypographyOptions - extends Partial & FontStyleOptions> {} + extends Partial< + Record & FontStyleOptions & TypographyCustomVariantsOptions + > {} export default function createTypography( palette: Palette, diff --git a/packages/material-ui/src/styles/createTypography.js b/packages/material-ui/src/styles/createTypography.js index bb3b6fe572692f..bc9a8c3a46956b 100644 --- a/packages/material-ui/src/styles/createTypography.js +++ b/packages/material-ui/src/styles/createTypography.js @@ -28,6 +28,7 @@ export default function createTypography(palette, typography) { // Apply the CSS properties to all the variants. allVariants, pxToRem: pxToRem2, + customVariants = {}, ...other } = typeof typography === 'function' ? typography(palette) : typography; @@ -85,6 +86,7 @@ export default function createTypography(palette, typography) { fontWeightRegular, fontWeightMedium, fontWeightBold, + customVariants, ...variants, }, other,