From 04c8786ad081c0e2bc3c596ab2baa879e49f6d94 Mon Sep 17 00:00:00 2001 From: Siriwat K Date: Wed, 27 Mar 2024 19:56:10 +0700 Subject: [PATCH] [system] Add `spacing` theme token to be used in `theme.spacing()` (#40224) --- .../src/Typography/Typography.test.tsx | 5 +- .../src/styles/CssVarsProvider.test.tsx | 2 +- .../mui-joy/src/styles/defaultTheme.test.js | 1 + .../mui-joy/src/styles/extendTheme.test.js | 46 ++++++++++++++++ packages/mui-joy/src/styles/extendTheme.ts | 26 ++++++++-- .../mui-joy/src/styles/styleUtils.test.js | 4 +- packages/mui-joy/src/styles/types/theme.ts | 1 + packages/mui-material/src/Grid/Grid.js | 3 ++ .../src/styles/CssVarsProvider.test.js | 2 +- .../src/styles/experimental_extendTheme.d.ts | 2 + .../src/styles/experimental_extendTheme.js | 28 ++++++++-- .../styles/experimental_extendTheme.test.js | 45 ++++++++++++++++ .../src/createTheme/createSpacing.test.ts | 2 + .../src/createTheme/createSpacing.ts | 18 ++++--- .../src/cssVars/createCssVarsProvider.js | 3 ++ .../src/cssVars/cssVarsParser.test.ts | 15 ++++++ .../mui-system/src/cssVars/cssVarsParser.ts | 5 +- packages/mui-system/src/spacing/spacing.js | 52 ++++++++++--------- .../mui-system/src/spacing/spacing.test.js | 30 +++++++++++ 19 files changed, 244 insertions(+), 46 deletions(-) diff --git a/packages/mui-joy/src/Typography/Typography.test.tsx b/packages/mui-joy/src/Typography/Typography.test.tsx index e407bc7e8a12d0..0b721f3a5dc024 100644 --- a/packages/mui-joy/src/Typography/Typography.test.tsx +++ b/packages/mui-joy/src/Typography/Typography.test.tsx @@ -98,7 +98,10 @@ describe('', () => { }); }); - it('combines system properties with the sx prop', () => { + it('combines system properties with the sx prop', function test() { + if (/jsdom/.test(window.navigator.userAgent)) { + this.skip(); + } const { container } = render(); expect(container.firstChild).toHaveComputedStyle({ diff --git a/packages/mui-joy/src/styles/CssVarsProvider.test.tsx b/packages/mui-joy/src/styles/CssVarsProvider.test.tsx index 7a71401aaa3e7d..024699b3368a71 100644 --- a/packages/mui-joy/src/styles/CssVarsProvider.test.tsx +++ b/packages/mui-joy/src/styles/CssVarsProvider.test.tsx @@ -526,7 +526,7 @@ describe('[Joy] CssVarsProvider', () => { , ); - expect(container.firstChild?.textContent).to.equal('16px'); + expect(container.firstChild?.textContent).to.equal('calc(2 * var(--joy-spacing))'); }); }); diff --git a/packages/mui-joy/src/styles/defaultTheme.test.js b/packages/mui-joy/src/styles/defaultTheme.test.js index 3e1ed26552a813..25469909a49cd6 100644 --- a/packages/mui-joy/src/styles/defaultTheme.test.js +++ b/packages/mui-joy/src/styles/defaultTheme.test.js @@ -36,6 +36,7 @@ describe('defaultTheme', () => { 'shouldSkipGeneratingVar', 'generateStyleSheets', 'generateThemeVars', + 'generateSpacing', 'applyStyles', ]).to.includes(field); }); diff --git a/packages/mui-joy/src/styles/extendTheme.test.js b/packages/mui-joy/src/styles/extendTheme.test.js index 2ad947c7e97a9c..c13f29d5c99315 100644 --- a/packages/mui-joy/src/styles/extendTheme.test.js +++ b/packages/mui-joy/src/styles/extendTheme.test.js @@ -38,6 +38,7 @@ describe('extendTheme', () => { 'shouldSkipGeneratingVar', 'generateStyleSheets', 'generateThemeVars', + 'generateSpacing', 'applyStyles', ]).to.includes(field); }); @@ -106,6 +107,51 @@ describe('extendTheme', () => { }); }); + describe('spacing', () => { + it('produce spacing token by default', () => { + const theme = extendTheme(); + expect(theme.vars.spacing).to.equal('var(--joy-spacing, 8px)'); + expect(theme.spacing(2)).to.equal('calc(2 * var(--joy-spacing, 8px))'); + }); + + it('turn number to pixel', () => { + const theme = extendTheme({ spacing: 4 }); + expect(theme.vars.spacing).to.equal('var(--joy-spacing, 4px)'); + expect(theme.spacing(2)).to.equal('calc(2 * var(--joy-spacing, 4px))'); + }); + + it('can be customized as a string', () => { + const theme = extendTheme({ spacing: '0.5rem' }); + expect(theme.vars.spacing).to.equal('var(--joy-spacing, 0.5rem)'); + expect(theme.spacing(2)).to.equal('calc(2 * var(--joy-spacing, 0.5rem))'); + }); + + it('uses the provided value if it is a string', () => { + const theme = extendTheme({ spacing: '0.5rem' }); + expect(theme.spacing('1rem')).to.equal('1rem'); + }); + + it('can be customized as an array', () => { + const theme = extendTheme({ spacing: [0, 1, 2, 4, 8, 16, 32] }); + expect(theme.vars.spacing).to.deep.equal([ + 'var(--joy-spacing-0, 0px)', + 'var(--joy-spacing-1, 1px)', + 'var(--joy-spacing-2, 2px)', + 'var(--joy-spacing-3, 4px)', + 'var(--joy-spacing-4, 8px)', + 'var(--joy-spacing-5, 16px)', + 'var(--joy-spacing-6, 32px)', + ]); + expect(theme.spacing(2)).to.equal('var(--joy-spacing-2, 2px)'); + }); + + it('can be customized as a function', () => { + const theme = extendTheme({ spacing: (factor) => `${0.25 * factor}rem` }); + expect(theme.vars.spacing).to.deep.equal('var(--joy-spacing, 0.25rem)'); + expect(theme.spacing(2)).to.equal('calc(2 * var(--joy-spacing, 0.25rem))'); + }); + }); + describe('theme.unstable_sx', () => { const { render } = createRenderer(); diff --git a/packages/mui-joy/src/styles/extendTheme.ts b/packages/mui-joy/src/styles/extendTheme.ts index acccaded9c5ab4..7404c27310ef29 100644 --- a/packages/mui-joy/src/styles/extendTheme.ts +++ b/packages/mui-joy/src/styles/extendTheme.ts @@ -11,6 +11,7 @@ import { SxConfig, } from '@mui/system'; import { unstable_applyStyles as applyStyles } from '@mui/system/createTheme'; +import { createUnarySpacing } from '@mui/system/spacing'; import defaultSxConfig from './sxConfig'; import colors from '../colors'; import defaultShouldSkipGeneratingVar from './shouldSkipGeneratingVar'; @@ -43,6 +44,22 @@ type Partial3Level = { }; }; +function getSpacingVal(spacingInput: SpacingOptions | string | undefined) { + if (typeof spacingInput === 'number') { + return `${spacingInput}px`; + } + if (typeof spacingInput === 'string') { + return spacingInput; + } + if (typeof spacingInput === 'function') { + return getSpacingVal(spacingInput(1)); + } + if (Array.isArray(spacingInput)) { + return spacingInput; + } + return '8px'; +} + export type ColorSystemOptions = Partial3Level< MergeDefault > & { @@ -586,7 +603,7 @@ export default function extendTheme(themeOptions?: CssVarsThemeOptions): Theme { ), cssVarPrefix, getCssVar, - spacing: createSpacing(spacing), + spacing: getSpacingVal(spacing), } as unknown as Theme & { attribute: string; colorSchemeSelector: string }; // Need type casting due to module augmentation inside the repo /** @@ -646,8 +663,7 @@ export default function extendTheme(themeOptions?: CssVarsThemeOptions): Theme { }; const { vars, generateThemeVars, generateStyleSheets } = prepareCssVars( - // @ts-ignore property truDark is missing from colorSchemes - { colorSchemes, ...mergedScales }, + theme, parserConfig, ); theme.attribute = 'data-joy-color-scheme'; @@ -655,6 +671,10 @@ export default function extendTheme(themeOptions?: CssVarsThemeOptions): Theme { theme.vars = vars; theme.generateThemeVars = generateThemeVars; theme.generateStyleSheets = generateStyleSheets; + theme.generateSpacing = function generateSpacing() { + return createSpacing(spacing, createUnarySpacing(this)); + }; + theme.spacing = theme.generateSpacing(); theme.unstable_sxConfig = { ...defaultSxConfig, ...themeOptions?.unstable_sxConfig, diff --git a/packages/mui-joy/src/styles/styleUtils.test.js b/packages/mui-joy/src/styles/styleUtils.test.js index 336e818a0badfd..b5d20ca0899ecf 100644 --- a/packages/mui-joy/src/styles/styleUtils.test.js +++ b/packages/mui-joy/src/styles/styleUtils.test.js @@ -58,13 +58,13 @@ describe('getThemeValue', () => { it('return correct value if shorthand is provided', () => { expect( resolveSxValue({ theme: defaultTheme, ownerState: { sx: { p: 2 } } }, ['p']), - ).to.deep.equal({ p: '16px' }); // default theme.spacing(2) = '16px' + ).to.deep.equal({ p: 'calc(2 * var(--joy-spacing, 8px))' }); }); it('return correct value if number is provided', () => { expect( resolveSxValue({ theme: defaultTheme, ownerState: { sx: { padding: 2 } } }, ['padding']), - ).to.deep.equal({ padding: '16px' }); + ).to.deep.equal({ padding: 'calc(2 * var(--joy-spacing, 8px))' }); }); it('return correct value if css value is provided', () => { diff --git a/packages/mui-joy/src/styles/types/theme.ts b/packages/mui-joy/src/styles/types/theme.ts index 511a5d61f8f025..a75ec6487cba59 100644 --- a/packages/mui-joy/src/styles/types/theme.ts +++ b/packages/mui-joy/src/styles/types/theme.ts @@ -109,6 +109,7 @@ export interface Theme extends ThemeScales, RuntimeColorSystem { getColorSchemeSelector: (colorScheme: DefaultColorScheme | ExtendedColorScheme) => string; generateThemeVars: () => ThemeVars; generateStyleSheets: () => Record[]; + generateSpacing: () => Spacing; /** * A function to determine if the key, value should be attached as CSS Variable * `keys` is an array that represents the object path keys. diff --git a/packages/mui-material/src/Grid/Grid.js b/packages/mui-material/src/Grid/Grid.js index 62900dc203ac44..7d8935e4395b74 100644 --- a/packages/mui-material/src/Grid/Grid.js +++ b/packages/mui-material/src/Grid/Grid.js @@ -27,6 +27,9 @@ import gridClasses, { getGridUtilityClass } from './gridClasses'; function getOffset(val) { const parse = parseFloat(val); + if (Number.isNaN(parse)) { + return val; + } return `${parse}${String(val).replace(String(parse), '') || 'px'}`; } diff --git a/packages/mui-material/src/styles/CssVarsProvider.test.js b/packages/mui-material/src/styles/CssVarsProvider.test.js index 49f262ed817c3c..d9b2165222e160 100644 --- a/packages/mui-material/src/styles/CssVarsProvider.test.js +++ b/packages/mui-material/src/styles/CssVarsProvider.test.js @@ -267,7 +267,7 @@ describe('[Material UI] CssVarsProvider', () => { , ); - expect(container.firstChild?.textContent).to.equal('16px'); + expect(container.firstChild?.textContent).to.equal('calc(2 * var(--mui-spacing))'); }); }); diff --git a/packages/mui-material/src/styles/experimental_extendTheme.d.ts b/packages/mui-material/src/styles/experimental_extendTheme.d.ts index ea83de510f8959..013e945e2fbdf3 100644 --- a/packages/mui-material/src/styles/experimental_extendTheme.d.ts +++ b/packages/mui-material/src/styles/experimental_extendTheme.d.ts @@ -334,6 +334,7 @@ export interface ThemeVars { overlays: Overlays; shadows: Shadows; shape: Theme['shape']; + spacing: string; zIndex: ZIndex; } @@ -431,6 +432,7 @@ export interface CssVarsTheme extends ColorSystem { getColorSchemeSelector: (colorScheme: SupportedColorScheme) => string; generateThemeVars: () => ThemeVars; generateStyleSheets: () => Array>; + generateSpacing: () => Theme['spacing']; // Default theme tokens spacing: Theme['spacing']; diff --git a/packages/mui-material/src/styles/experimental_extendTheme.js b/packages/mui-material/src/styles/experimental_extendTheme.js index c04bbb28a03bd6..308f78d863644c 100644 --- a/packages/mui-material/src/styles/experimental_extendTheme.js +++ b/packages/mui-material/src/styles/experimental_extendTheme.js @@ -1,8 +1,7 @@ import deepmerge from '@mui/utils/deepmerge'; -import { - unstable_createGetCssVar as systemCreateGetCssVar, - unstable_prepareCssVars as prepareCssVars, -} from '@mui/system'; +import { unstable_createGetCssVar as systemCreateGetCssVar, createSpacing } from '@mui/system'; +import { createUnarySpacing } from '@mui/system/spacing'; +import { prepareCssVars } from '@mui/system/cssVars'; import styleFunctionSx, { unstable_defaultSxConfig as defaultSxConfig, } from '@mui/system/styleFunctionSx'; @@ -63,6 +62,22 @@ function setColorChannel(obj, key) { } } +function getSpacingVal(spacingInput) { + if (typeof spacingInput === 'number') { + return `${spacingInput}px`; + } + if (typeof spacingInput === 'string') { + return spacingInput; + } + if (typeof spacingInput === 'function') { + return getSpacingVal(spacingInput(1)); + } + if (Array.isArray(spacingInput)) { + return spacingInput; + } + return '8px'; +} + const silent = (fn) => { try { return fn(); @@ -124,6 +139,7 @@ export default function extendTheme(options = {}, ...args) { overlays: colorSchemesInput.dark?.overlays || defaultDarkOverlays, }, }, + spacing: getSpacingVal(input.spacing), }; Object.keys(theme.colorSchemes).forEach((key) => { @@ -414,7 +430,11 @@ export default function extendTheme(options = {}, ...args) { }); theme.generateThemeVars = generateThemeVars; theme.generateStyleSheets = generateStyleSheets; + theme.generateSpacing = function generateSpacing() { + return createSpacing(input.spacing, createUnarySpacing(this)); + }; theme.getColorSchemeSelector = (colorScheme) => `[${theme.attribute}="${colorScheme}"] &`; + theme.spacing = theme.generateSpacing(); theme.shouldSkipGeneratingVar = shouldSkipGeneratingVar; theme.unstable_sxConfig = { ...defaultSxConfig, diff --git a/packages/mui-material/src/styles/experimental_extendTheme.test.js b/packages/mui-material/src/styles/experimental_extendTheme.test.js index 1860fb4508ab99..297418eea7ada1 100644 --- a/packages/mui-material/src/styles/experimental_extendTheme.test.js +++ b/packages/mui-material/src/styles/experimental_extendTheme.test.js @@ -363,6 +363,51 @@ describe('experimental_extendTheme', () => { }); }); + describe('spacing', () => { + it('produce spacing token by default', () => { + const theme = extendTheme(); + expect(theme.vars.spacing).to.equal('var(--mui-spacing, 8px)'); + expect(theme.spacing(2)).to.equal('calc(2 * var(--mui-spacing, 8px))'); + }); + + it('turn number to pixel', () => { + const theme = extendTheme({ spacing: 4 }); + expect(theme.vars.spacing).to.equal('var(--mui-spacing, 4px)'); + expect(theme.spacing(2)).to.equal('calc(2 * var(--mui-spacing, 4px))'); + }); + + it('can be customized as a string', () => { + const theme = extendTheme({ spacing: '0.5rem' }); + expect(theme.vars.spacing).to.equal('var(--mui-spacing, 0.5rem)'); + expect(theme.spacing(2)).to.equal('calc(2 * var(--mui-spacing, 0.5rem))'); + }); + + it('uses the provided value if it is a string', () => { + const theme = extendTheme({ spacing: '0.5rem' }); + expect(theme.spacing('1rem')).to.equal('1rem'); + }); + + it('can be customized as an array', () => { + const theme = extendTheme({ spacing: [0, 1, 2, 4, 8, 16, 32] }); + expect(theme.vars.spacing).to.deep.equal([ + 'var(--mui-spacing-0, 0px)', + 'var(--mui-spacing-1, 1px)', + 'var(--mui-spacing-2, 2px)', + 'var(--mui-spacing-3, 4px)', + 'var(--mui-spacing-4, 8px)', + 'var(--mui-spacing-5, 16px)', + 'var(--mui-spacing-6, 32px)', + ]); + expect(theme.spacing(2)).to.equal('var(--mui-spacing-2, 2px)'); + }); + + it('can be customized as a function', () => { + const theme = extendTheme({ spacing: (factor) => `${0.25 * factor}rem` }); + expect(theme.vars.spacing).to.deep.equal('var(--mui-spacing, 0.25rem)'); + expect(theme.spacing(2)).to.equal('calc(2 * var(--mui-spacing, 0.25rem))'); + }); + }); + it('shallow merges multiple arguments', () => { const theme = extendTheme({ foo: 'I am foo' }, { bar: 'I am bar' }); expect(theme.foo).to.equal('I am foo'); diff --git a/packages/mui-system/src/createTheme/createSpacing.test.ts b/packages/mui-system/src/createTheme/createSpacing.test.ts index dbbe9eae433c45..41f917b4c881bf 100644 --- a/packages/mui-system/src/createTheme/createSpacing.test.ts +++ b/packages/mui-system/src/createTheme/createSpacing.test.ts @@ -16,6 +16,8 @@ describe('createSpacing', () => { expect(spacing(2)).to.equal('4px'); spacing = createSpacing((factor: number) => `${0.25 * factor}rem`); expect(spacing(2)).to.equal('0.5rem'); + spacing = createSpacing('0.5rem'); + expect(spacing(2)).to.equal('calc(2 * 0.5rem)'); }); it('should support recursion', () => { diff --git a/packages/mui-system/src/createTheme/createSpacing.ts b/packages/mui-system/src/createTheme/createSpacing.ts index 3e0db4679233ce..67c654e0e10c1e 100644 --- a/packages/mui-system/src/createTheme/createSpacing.ts +++ b/packages/mui-system/src/createTheme/createSpacing.ts @@ -2,6 +2,7 @@ import { createUnarySpacing } from '../spacing'; export type SpacingOptions = | number + | string | Spacing | ((abs: number) => number | string) | ((abs: number | string) => number | string) @@ -24,18 +25,19 @@ export interface Spacing { ): string; } -export default function createSpacing(spacingInput: SpacingOptions = 8): Spacing { - // Already transformed. - if ((spacingInput as any).mui) { - return spacingInput as Spacing; - } - +export default function createSpacing( + spacingInput: SpacingOptions = 8, // Material Design layouts are visually balanced. Most measurements align to an 8dp grid, which aligns both spacing and the overall layout. // Smaller components, such as icons, can align to a 4dp grid. // https://m2.material.io/design/layout/understanding-layout.html - const transform = createUnarySpacing({ + transform = createUnarySpacing({ spacing: spacingInput, - }); + }), +): Spacing { + // Already transformed. + if ((spacingInput as any).mui) { + return spacingInput as Spacing; + } const spacing = (...argsInput: ReadonlyArray): string => { if (process.env.NODE_ENV !== 'production') { diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.js b/packages/mui-system/src/cssVars/createCssVarsProvider.js index 5f218509fc0be9..22f781020af1a5 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.js +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.js @@ -153,6 +153,9 @@ export default function createCssVarsProvider(options) { cssVarPrefix, vars: themeVars, }; + if (typeof theme.generateSpacing === 'function') { + theme.spacing = theme.generateSpacing(); + } // 4. Resolve the color scheme and merge it to the theme Object.entries(colorSchemes).forEach(([key, scheme]) => { diff --git a/packages/mui-system/src/cssVars/cssVarsParser.test.ts b/packages/mui-system/src/cssVars/cssVarsParser.test.ts index 25c4672c5da9a2..f8b4e58d015b32 100644 --- a/packages/mui-system/src/cssVars/cssVarsParser.test.ts +++ b/packages/mui-system/src/cssVars/cssVarsParser.test.ts @@ -359,6 +359,21 @@ describe('cssVarsParser', () => { }); }); + it('varsWithDefaults are suffixed with px from array', () => { + const { varsWithDefaults } = cssVarsParser({ + spacing: [0, 1, 2, 6, 16], + }); + expect(varsWithDefaults).to.deep.equal({ + spacing: [ + 'var(--spacing-0, 0px)', + 'var(--spacing-1, 1px)', + 'var(--spacing-2, 2px)', + 'var(--spacing-3, 6px)', + 'var(--spacing-4, 16px)', + ], + }); + }); + it('should add a fallback value', () => { const { varsWithDefaults } = cssVarsParser({ palette: { diff --git a/packages/mui-system/src/cssVars/cssVarsParser.ts b/packages/mui-system/src/cssVars/cssVarsParser.ts index a7e241bfa11889..0e4113f55fb7bc 100644 --- a/packages/mui-system/src/cssVars/cssVarsParser.ts +++ b/packages/mui-system/src/cssVars/cssVarsParser.ts @@ -138,10 +138,11 @@ export default function cssVarsParser>( if (!shouldSkipGeneratingVar || !shouldSkipGeneratingVar(keys, value)) { // only create css & var if `shouldSkipGeneratingVar` return false const cssVar = `--${prefix ? `${prefix}-` : ''}${keys.join('-')}`; - Object.assign(css, { [cssVar]: getCssValue(keys, value) }); + const resolvedValue = getCssValue(keys, value); + Object.assign(css, { [cssVar]: resolvedValue }); assignNestedKeys(vars, keys, `var(${cssVar})`, arrayKeys); - assignNestedKeys(varsWithDefaults, keys, `var(${cssVar}, ${value})`, arrayKeys); + assignNestedKeys(varsWithDefaults, keys, `var(${cssVar}, ${resolvedValue})`, arrayKeys); } } }, diff --git a/packages/mui-system/src/spacing/spacing.js b/packages/mui-system/src/spacing/spacing.js index c2fecdd9389961..ecf0ada82d05a1 100644 --- a/packages/mui-system/src/spacing/spacing.js +++ b/packages/mui-system/src/spacing/spacing.js @@ -93,30 +93,35 @@ export const paddingKeys = [ const spacingKeys = [...marginKeys, ...paddingKeys]; export function createUnaryUnit(theme, themeKey, defaultValue, propName) { - const themeSpacing = getPath(theme, themeKey, false) ?? defaultValue; + const themeSpacing = getPath(theme, themeKey, true) ?? defaultValue; - if (typeof themeSpacing === 'number') { - return (abs) => { - if (typeof abs === 'string') { - return abs; + if (typeof themeSpacing === 'number' || typeof themeSpacing === 'string') { + return (val) => { + if (typeof val === 'string') { + return val; } if (process.env.NODE_ENV !== 'production') { - if (typeof abs !== 'number') { + if (typeof val !== 'number') { console.error( - `MUI: Expected ${propName} argument to be a number or a string, got ${abs}.`, + `MUI: Expected ${propName} argument to be a number or a string, got ${val}.`, ); } } - return themeSpacing * abs; + + if (typeof themeSpacing === 'string') { + return `calc(${val} * ${themeSpacing})`; + } + return themeSpacing * val; }; } if (Array.isArray(themeSpacing)) { - return (abs) => { - if (typeof abs === 'string') { - return abs; + return (val) => { + if (typeof val === 'string') { + return val; } + const abs = Math.abs(val); if (process.env.NODE_ENV !== 'production') { if (!Number.isInteger(abs)) { @@ -137,7 +142,17 @@ export function createUnaryUnit(theme, themeKey, defaultValue, propName) { } } - return themeSpacing[abs]; + const transformed = themeSpacing[abs]; + + if (val >= 0) { + return transformed; + } + + if (typeof transformed === 'number') { + return -transformed; + } + + return `-${transformed}`; }; } @@ -166,18 +181,7 @@ export function getValue(transformer, propValue) { return propValue; } - const abs = Math.abs(propValue); - const transformed = transformer(abs); - - if (propValue >= 0) { - return transformed; - } - - if (typeof transformed === 'number') { - return -transformed; - } - - return `-${transformed}`; + return transformer(propValue); } export function getStyleFromPropValue(cssProperties, transformer) { diff --git a/packages/mui-system/src/spacing/spacing.test.js b/packages/mui-system/src/spacing/spacing.test.js index 1b6a77996c6ecd..92f8f5306e94fd 100644 --- a/packages/mui-system/src/spacing/spacing.test.js +++ b/packages/mui-system/src/spacing/spacing.test.js @@ -36,6 +36,36 @@ describe('system spacing', () => { }); expect(output3).to.deep.equal({ padding: 4 }); }); + + it('should be able to use string value', () => { + const output1 = spacing({ + theme: { + spacing: '4px', + }, + p: 2, + }); + expect(output1).to.deep.equal({ padding: 'calc(2 * 4px)' }); + }); + + it('should be able to use string value with negative amount', () => { + const output1 = spacing({ + theme: { + spacing: '4px', + }, + p: -2, + }); + expect(output1).to.deep.equal({ padding: 'calc(-2 * 4px)' }); + }); + + it('should use the provided value directly if theme.spacing is a string', () => { + const output1 = spacing({ + theme: { + spacing: '4px', + }, + p: '1rem', + }); + expect(output1).to.deep.equal({ padding: '1rem' }); + }); }); describe('warnings', () => {