From e039510335b2020c578867c1b0d24ecb7935756f Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Tue, 13 Dec 2022 14:13:29 +0100 Subject: [PATCH] [Material You] Add shape design tokens (#35393) --- docs/pages/experiments/md3/index.tsx | 2 +- .../mui-material-next/src/Button/Button.tsx | 2 +- .../src/styles/Theme.types.ts | 40 ++++++++++++------- .../src/styles/defaultTheme.ts | 3 -- .../src/styles/extendTheme.ts | 16 ++++---- .../mui-material-next/src/styles/shape.ts | 19 +++++++++ .../src/styles/{states.ts => state.ts} | 4 +- .../src/styles/styled.test.js | 26 ++++++++++++ .../mui-material-next/src/styles/sxConfig.ts | 29 +++++++++++++- packages/mui-system/src/spacing.d.ts | 4 +- 10 files changed, 114 insertions(+), 31 deletions(-) create mode 100644 packages/mui-material-next/src/styles/shape.ts rename packages/mui-material-next/src/styles/{states.ts => state.ts} (74%) diff --git a/docs/pages/experiments/md3/index.tsx b/docs/pages/experiments/md3/index.tsx index b2eb04b23f59d6..6916f9d02b6ccd 100644 --- a/docs/pages/experiments/md3/index.tsx +++ b/docs/pages/experiments/md3/index.tsx @@ -159,7 +159,7 @@ function DemoComponents() { bgcolor: 'error', border: 1, borderColor: 'tertiary', - borderRadius: '1px', + borderRadius: 'medium', }} > Button diff --git a/packages/mui-material-next/src/Button/Button.tsx b/packages/mui-material-next/src/Button/Button.tsx index bf482406fed6ba..bc6394f4e9e7fe 100644 --- a/packages/mui-material-next/src/Button/Button.tsx +++ b/packages/mui-material-next/src/Button/Button.tsx @@ -268,7 +268,7 @@ export const ButtonRoot = styled('button', { theme.sys.typescale.label.large.tracking / theme.sys.typescale.label.large.size }rem`; - const borderRadiusValue: string | number = tokens.md3.shape.borderRadius; + const borderRadiusValue: string | number = tokens.sys.shape.corner.full; const borderRadius = Number.isNaN(Number(borderRadiusValue)) ? borderRadiusValue : `${borderRadiusValue}px`; diff --git a/packages/mui-material-next/src/styles/Theme.types.ts b/packages/mui-material-next/src/styles/Theme.types.ts index 440530c0da2c57..3c0a16c371edb9 100644 --- a/packages/mui-material-next/src/styles/Theme.types.ts +++ b/packages/mui-material-next/src/styles/Theme.types.ts @@ -89,7 +89,7 @@ export interface MD3Typeface { }; } -export interface MD3States { +export interface MD3State { hover: { stateLayerOpacity: number; }; @@ -129,21 +129,35 @@ export interface MD3Typescale { display: TypescaleValue; } -export interface Shapes { - borderRadius: number; +export interface MD3Shape { + corner: { + none: string; + extraSmall: string; + extraSmallTop: string; + small: string; + medium: string; + large: string; + largeEnd: string; + largeTop: string; + extraLarge: string; + extraLargeTop: string; + full: string; + }; +} + +export interface MD3ShapeOptions { + corner?: Partial; } export interface MD3CssVarsThemeOptions extends Omit { - md3?: { - shape?: Partial; - }; ref?: { typeface?: Partial; }; sys?: { typescale?: Partial; - state?: Partial; + state?: Partial; elevation?: string[]; + shape?: MD3ShapeOptions; }; } @@ -173,11 +187,9 @@ export interface Theme extends Omit { sys: { color: MD3ColorSchemeTokens; typescale: MD3Typescale; - state: MD3States; + state: MD3State; elevation: string[]; - }; - md3: { - shape: Shapes; + shape: MD3Shape; }; palette: MD2Theme['palette']; vars: MD2Theme['vars'] & { @@ -189,11 +201,9 @@ export interface Theme extends Omit { sys: { color: MD3ColorSchemeTokens; typescale: MD3Typescale; - state: MD3States; + state: MD3State; elevation: string[]; - }; - md3: { - shape: Shapes; + shape: MD3Shape; }; }; unstable_sxConfig: SxConfig; diff --git a/packages/mui-material-next/src/styles/defaultTheme.ts b/packages/mui-material-next/src/styles/defaultTheme.ts index 3daba490449ec5..75b041c1185e21 100644 --- a/packages/mui-material-next/src/styles/defaultTheme.ts +++ b/packages/mui-material-next/src/styles/defaultTheme.ts @@ -12,7 +12,6 @@ export const getThemeWithVars = ( opacity, overlays, shape, - md3, ref, sys, palette: paletteInput, @@ -37,7 +36,6 @@ export const getThemeWithVars = ( opacity, overlays, shape, - md3, ref: { ...ref, ...colorSchemeRef, @@ -72,7 +70,6 @@ export const getThemeWithVars = ( ...sys, ...colorSchemeSys, }, - md3, palette, }, } as unknown as Theme; diff --git a/packages/mui-material-next/src/styles/extendTheme.ts b/packages/mui-material-next/src/styles/extendTheme.ts index f4f9b19c1c73d6..460c461c1c084f 100644 --- a/packages/mui-material-next/src/styles/extendTheme.ts +++ b/packages/mui-material-next/src/styles/extendTheme.ts @@ -23,8 +23,9 @@ import createMd3LightColorScheme from './createLightColorScheme'; import createMd3DarkColorScheme from './createDarkColorScheme'; import md3Typescale from './typescale'; import md3Typeface from './typeface'; -import md3State from './states'; +import md3State from './state'; import { elevationLight, elevationDark } from './elevation'; +import md3shape from './shape'; const defaultLightOverlays: Overlays = [...Array(25)].map(() => undefined) as Overlays; const defaultDarkOverlays: Overlays = [...Array(25)].map((_, index) => { @@ -55,6 +56,11 @@ export default function extendTheme(options: CssVarsThemeOptions = {}, ...args: const md3LightColors = createMd3LightColorScheme(getCssVar, md3CommonPalette); const md3DarkColors = createMd3DarkColorScheme(getCssVar, md3CommonPalette); + const shape = { + ...input.sys?.shape, + ...md3shape, + corner: { ...input.sys?.shape?.corner, ...md3shape.corner }, + }; const { palette: lightPalette, @@ -79,12 +85,7 @@ export default function extendTheme(options: CssVarsThemeOptions = {}, ...args: state: { ...md3State, ...input.sys?.state }, color: { ...md3LightColors, ...colorSchemesInput.light?.sys?.color }, elevation: colorSchemesInput.light?.sys?.elevation ?? elevationLight, - }, - md3: { - shape: { - borderRadius: 100, - ...input?.shape, - }, + shape, }, palette: { ...(colorSchemesInput.light && colorSchemesInput.light?.palette), @@ -114,6 +115,7 @@ export default function extendTheme(options: CssVarsThemeOptions = {}, ...args: state: { ...md3State, ...input.sys?.state }, color: { ...md3DarkColors, ...colorSchemesInput.dark?.sys?.color }, elevation: colorSchemesInput.dark?.sys?.elevation ?? elevationDark, + shape, }, }); diff --git a/packages/mui-material-next/src/styles/shape.ts b/packages/mui-material-next/src/styles/shape.ts new file mode 100644 index 00000000000000..8da414f66e4e2a --- /dev/null +++ b/packages/mui-material-next/src/styles/shape.ts @@ -0,0 +1,19 @@ +import { MD3Shape } from './Theme.types'; + +const mdSysShape: MD3Shape = { + corner: { + none: '0px', + extraSmall: '4px', + extraSmallTop: '4px 4px 0 0', + small: '8px', + medium: '12px', + large: '16px', + largeEnd: '0 16px 16px 0', + largeTop: '16px 16px 0 0', + extraLarge: '28px', + extraLargeTop: '28px 28px 0 0', + full: '100px', + }, +}; + +export default mdSysShape; diff --git a/packages/mui-material-next/src/styles/states.ts b/packages/mui-material-next/src/styles/state.ts similarity index 74% rename from packages/mui-material-next/src/styles/states.ts rename to packages/mui-material-next/src/styles/state.ts index 13f07fc543a7d2..2db34a26b47660 100644 --- a/packages/mui-material-next/src/styles/states.ts +++ b/packages/mui-material-next/src/styles/state.ts @@ -1,4 +1,6 @@ -const mdSysState = { +import { MD3State } from './Theme.types'; + +const mdSysState: MD3State = { hover: { stateLayerOpacity: 0.08, }, diff --git a/packages/mui-material-next/src/styles/styled.test.js b/packages/mui-material-next/src/styles/styled.test.js index 43fa2987f0b07e..28d4a0ef06dae6 100644 --- a/packages/mui-material-next/src/styles/styled.test.js +++ b/packages/mui-material-next/src/styles/styled.test.js @@ -198,5 +198,31 @@ describe('styled', () => { borderRightColor: 'rgb(242, 184, 181)', }); }); + + it('should apply borderRadius from sys.shape.corner', function test() { + if (/jsdom/.test(window.navigator.userAgent)) { + this.skip(); + } + const Div = styled('div')``; + + render(
); + + expect(screen.getByTestId('target')).toHaveComputedStyle({ + borderTopLeftRadius: '8px', + }); + }); + + it('should multiple borderRadius with theme.shape.borderRadius if provided as number', function test() { + if (/jsdom/.test(window.navigator.userAgent)) { + this.skip(); + } + const Div = styled('div')``; + + render(
); + + expect(screen.getByTestId('target')).toHaveComputedStyle({ + borderTopLeftRadius: '16px', + }); + }); }); }); diff --git a/packages/mui-material-next/src/styles/sxConfig.ts b/packages/mui-material-next/src/styles/sxConfig.ts index eb2bc0efa2743d..83f2932de1c743 100644 --- a/packages/mui-material-next/src/styles/sxConfig.ts +++ b/packages/mui-material-next/src/styles/sxConfig.ts @@ -1,4 +1,11 @@ -import { getPath, handleBreakpoints, SxConfig, unstable_defaultSxConfig } from '@mui/system'; +import { + getPath, + handleBreakpoints, + SxConfig, + unstable_defaultSxConfig, + createUnaryUnit, + getValue, +} from '@mui/system'; interface PaletteStyleOptions { prop: string; @@ -33,6 +40,23 @@ function createPaletteStyle(options: PaletteStyleOptions = { prop: 'color' }) { return fn; } +// eslint-disable-next-line no-restricted-globals +const isNumber = (value: string | number) => typeof value === 'number' || !isNaN(parseFloat(value)); + +const createBorderRadiusStyle = (props: Record) => { + if (props.borderRadius !== undefined && props.borderRadius !== null) { + const numberTransformer = createUnaryUnit(props.theme, 'shape.borderRadius', 4, 'borderRadius'); + const styleFromPropValue = (propValue: string | number) => ({ + borderRadius: isNumber(propValue) + ? getValue(numberTransformer, propValue) + : getPath(props.theme, `sys.shape.corner.${propValue}`, true), + }); + return handleBreakpoints(props, props.borderRadius, styleFromPropValue); + } + + return null; +}; + const sxConfig: SxConfig = { ...unstable_defaultSxConfig, color: { @@ -59,6 +83,9 @@ const sxConfig: SxConfig = { borderRightColor: { style: createPaletteStyle({ prop: 'borderRightColor' }), }, + borderRadius: { + style: createBorderRadiusStyle, + }, }; export default sxConfig; diff --git a/packages/mui-system/src/spacing.d.ts b/packages/mui-system/src/spacing.d.ts index d5587dc06beeb9..bd50acd23899ea 100644 --- a/packages/mui-system/src/spacing.d.ts +++ b/packages/mui-system/src/spacing.d.ts @@ -1,5 +1,6 @@ import { SimpleStyleFunction, spacing, PropsFor } from './Box'; +export type SpacingValueType = string | number | null | undefined; export type SpacingProps = PropsFor; export function createUnarySpacing(theme: { spacing: Spacing }): Spacing extends number ? (abs: number | string) => number | number @@ -16,7 +17,7 @@ export function createUnaryUnit( defaultValue: Spacing, propName: string, ): Spacing extends number - ? (abs: number | string) => number | number + ? (abs: SpacingValueType) => number | number : Spacing extends any[] ? (abs: Index | string) => Spacing[Index] | string : Spacing extends (...args: unknown[]) => unknown @@ -72,7 +73,6 @@ export const padding: SimpleStyleFunction< | 'paddingBlockEnd' >; -export type SpacingValueType = string | number | null | undefined; export function getValue( transformer: (prop: SpacingValueType) => SpacingValueType, propValue: SpacingValueType,