diff --git a/docs/data/material/customization/theme-components/GlobalThemeOverrideSx.js b/docs/data/material/customization/theme-components/GlobalThemeOverrideSx.js index d78df9369e8e28..28329516e060c1 100644 --- a/docs/data/material/customization/theme-components/GlobalThemeOverrideSx.js +++ b/docs/data/material/customization/theme-components/GlobalThemeOverrideSx.js @@ -1,9 +1,5 @@ import * as React from 'react'; -import { - ThemeProvider, - createTheme, - experimental_sx as sx, -} from '@mui/material/styles'; +import { ThemeProvider, createTheme } from '@mui/material/styles'; import Chip from '@mui/material/Chip'; import Check from '@mui/icons-material/Check'; @@ -11,20 +7,22 @@ const finalTheme = createTheme({ components: { MuiChip: { styleOverrides: { - root: sx({ - // https://mui.com/system/getting-started/the-sx-prop/#spacing - px: 1, - py: 0.25, - // https://mui.com/system/borders/#border-radius - borderRadius: 1, // 4px as default. - }), + root: ({ theme }) => + theme.unstable_sx({ + // https://mui.com/system/getting-started/the-sx-prop/#spacing + px: 1, + py: 0.25, + // https://mui.com/system/borders/#border-radius + borderRadius: 1, // 4px as default. + }), label: { padding: 'initial', }, - icon: sx({ - mr: 0.5, - ml: '-2px', - }), + icon: ({ theme }) => + theme.unstable_sx({ + mr: 0.5, + ml: '-2px', + }), }, }, }, diff --git a/docs/data/material/customization/theme-components/GlobalThemeOverrideSx.tsx b/docs/data/material/customization/theme-components/GlobalThemeOverrideSx.tsx index d78df9369e8e28..28329516e060c1 100644 --- a/docs/data/material/customization/theme-components/GlobalThemeOverrideSx.tsx +++ b/docs/data/material/customization/theme-components/GlobalThemeOverrideSx.tsx @@ -1,9 +1,5 @@ import * as React from 'react'; -import { - ThemeProvider, - createTheme, - experimental_sx as sx, -} from '@mui/material/styles'; +import { ThemeProvider, createTheme } from '@mui/material/styles'; import Chip from '@mui/material/Chip'; import Check from '@mui/icons-material/Check'; @@ -11,20 +7,22 @@ const finalTheme = createTheme({ components: { MuiChip: { styleOverrides: { - root: sx({ - // https://mui.com/system/getting-started/the-sx-prop/#spacing - px: 1, - py: 0.25, - // https://mui.com/system/borders/#border-radius - borderRadius: 1, // 4px as default. - }), + root: ({ theme }) => + theme.unstable_sx({ + // https://mui.com/system/getting-started/the-sx-prop/#spacing + px: 1, + py: 0.25, + // https://mui.com/system/borders/#border-radius + borderRadius: 1, // 4px as default. + }), label: { padding: 'initial', }, - icon: sx({ - mr: 0.5, - ml: '-2px', - }), + icon: ({ theme }) => + theme.unstable_sx({ + mr: 0.5, + ml: '-2px', + }), }, }, }, diff --git a/docs/data/material/customization/theme-components/theme-components.md b/docs/data/material/customization/theme-components/theme-components.md index 188e86cabd1683..046c1c85dce85a 100644 --- a/docs/data/material/customization/theme-components/theme-components.md +++ b/docs/data/material/customization/theme-components/theme-components.md @@ -116,18 +116,20 @@ const finalTheme = createTheme({ components: { MuiChip: { styleOverrides: { - root: sx({ - px: 1, - py: 0.25, - borderRadius: 1, - }), + root: ({ theme }) => + theme.unstable_sx({ + px: 1, + py: 0.25, + borderRadius: 1, + }), label: { padding: 'initial', }, - icon: sx({ - mr: 0.5, - ml: '-2px', - }), + icon: ({ theme }) => + theme.unstable_sx({ + mr: 0.5, + ml: '-2px', + }), }, }, }, diff --git a/docs/data/system/experimental-api/configure-the-sx-prop/ChangeTheBehaviorSxProp.js b/docs/data/system/experimental-api/configure-the-sx-prop/ChangeTheBehaviorSxProp.js new file mode 100644 index 00000000000000..37efe351afd4a5 --- /dev/null +++ b/docs/data/system/experimental-api/configure-the-sx-prop/ChangeTheBehaviorSxProp.js @@ -0,0 +1,31 @@ +import * as React from 'react'; +import { createTheme, ThemeProvider, Box, Stack } from '@mui/system'; + +// Retain type safety. + +const theme = createTheme({ + unstable_sxConfig: { + // You can now use the background key in sx + // by providing direct values from the palette + borderRadius: { + themeKey: 'shape', + }, + }, + shape: { + sm: 4, + md: 8, + lg: 12, + }, +}); + +export default function ChangeTheBehaviorSxProp() { + return ( + + + + + + + + ); +} diff --git a/docs/data/system/experimental-api/configure-the-sx-prop/ChangeTheBehaviorSxProp.tsx b/docs/data/system/experimental-api/configure-the-sx-prop/ChangeTheBehaviorSxProp.tsx new file mode 100644 index 00000000000000..eb0477a69f2a34 --- /dev/null +++ b/docs/data/system/experimental-api/configure-the-sx-prop/ChangeTheBehaviorSxProp.tsx @@ -0,0 +1,38 @@ +import * as React from 'react'; +import { createTheme, ThemeProvider, Box, Stack } from '@mui/system'; + +// Retain type safety. +declare module '@mui/system' { + interface Shape { + sm: number; + md: number; + lg: number; + } +} + +const theme = createTheme({ + unstable_sxConfig: { + // You can now use the background key in sx + // by providing direct values from the palette + borderRadius: { + themeKey: 'shape', + }, + }, + shape: { + sm: 4, + md: 8, + lg: 12, + }, +}); + +export default function ChangeTheBehaviorSxProp() { + return ( + + + + + + + + ); +} diff --git a/docs/data/system/experimental-api/configure-the-sx-prop/ChangeTheBehaviorSxProp.tsx.preview b/docs/data/system/experimental-api/configure-the-sx-prop/ChangeTheBehaviorSxProp.tsx.preview new file mode 100644 index 00000000000000..563ab3ef514f8b --- /dev/null +++ b/docs/data/system/experimental-api/configure-the-sx-prop/ChangeTheBehaviorSxProp.tsx.preview @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/docs/data/system/experimental-api/configure-the-sx-prop/ExtendTheSxProp.js b/docs/data/system/experimental-api/configure-the-sx-prop/ExtendTheSxProp.js new file mode 100644 index 00000000000000..2b96d7f2a88f43 --- /dev/null +++ b/docs/data/system/experimental-api/configure-the-sx-prop/ExtendTheSxProp.js @@ -0,0 +1,37 @@ +import * as React from 'react'; +import { createTheme, ThemeProvider, Box, handleBreakpoints } from '@mui/system'; + +const customTheme = createTheme({ + unstable_sxConfig: { + size: { + style: (props) => { + const { size, theme } = props; + + const styleFromPropValue = (propValueFinal) => { + const value = theme.spacing(propValueFinal); + + return { + width: value, + height: value, + }; + }; + + // Adding support for the breakpoints syntax + return handleBreakpoints(props, size, styleFromPropValue); + }, + }, + }, +}); + +export default function ExtendSxProp() { + return ( + + + + ); +} diff --git a/docs/data/system/experimental-api/configure-the-sx-prop/ExtendTheSxProp.tsx b/docs/data/system/experimental-api/configure-the-sx-prop/ExtendTheSxProp.tsx new file mode 100644 index 00000000000000..a6f071dc97282f --- /dev/null +++ b/docs/data/system/experimental-api/configure-the-sx-prop/ExtendTheSxProp.tsx @@ -0,0 +1,37 @@ +import * as React from 'react'; +import { createTheme, ThemeProvider, Box, handleBreakpoints } from '@mui/system'; + +const customTheme = createTheme({ + unstable_sxConfig: { + size: { + style: (props) => { + const { size, theme } = props; + + const styleFromPropValue = (propValueFinal: number) => { + const value = theme.spacing(propValueFinal); + + return { + width: value, + height: value, + }; + }; + + // Adding support for the breakpoints syntax + return handleBreakpoints(props, size, styleFromPropValue); + }, + }, + }, +}); + +export default function ExtendSxProp() { + return ( + + + + ); +} diff --git a/docs/data/system/experimental-api/configure-the-sx-prop/ExtendTheSxProp.tsx.preview b/docs/data/system/experimental-api/configure-the-sx-prop/ExtendTheSxProp.tsx.preview new file mode 100644 index 00000000000000..4ca9079ae6b641 --- /dev/null +++ b/docs/data/system/experimental-api/configure-the-sx-prop/ExtendTheSxProp.tsx.preview @@ -0,0 +1,8 @@ + + + \ No newline at end of file diff --git a/docs/data/system/experimental-api/configure-the-sx-prop/configure-the-sx-prop.md b/docs/data/system/experimental-api/configure-the-sx-prop/configure-the-sx-prop.md new file mode 100644 index 00000000000000..1e80481d137ec6 --- /dev/null +++ b/docs/data/system/experimental-api/configure-the-sx-prop/configure-the-sx-prop.md @@ -0,0 +1,26 @@ +# Configure the sx prop + +

Learn about the experimental API for extending or changing the behavior of the sx prop.

+ +## Extend the sx prop + +You can add new keys to be processed by the `sx` prop by extending the `unstable_sxConfig` option inside the theme, as shown below: + +{{"demo": "ExtendTheSxProp.js" }} + +## Override existing behavior + +It is also possible to change some of the existing behavior of the `sx` prop. +For example, in some design systems, the border radiuses need to be restricted to specific values, instead of allowing any number to be used—as is the default with MUI System. +You can change this behavior by providing a custom config for the `borderRadius` property: + +{{"demo": "ChangeTheBehaviorSxProp.js" }} + +## API + +Each key in the `unstable_sx` config can define the following properties: + +- `cssProperty` (_string_ [optional]): Indicates the CSS property, if it is different than the key +- `themeKey` (_string_ [optional]): The path of the theme mapping +- `transform` (_(cssValue: unknown, userValue: unknown) => number | string | React.CSSProperties | CSSObject_ [optional]): Lets users define a function that can transform the value before it's returned +- `style` (_(props: any) => CSSObject_ [optional]): Offers maximum customizability. Note that you need to make sure that the breakpoint values can be processed diff --git a/docs/data/system/getting-started/usage/usage.md b/docs/data/system/getting-started/usage/usage.md index 9e300e6da04b24..2d1c0a179874c4 100644 --- a/docs/data/system/getting-started/usage/usage.md +++ b/docs/data/system/getting-started/usage/usage.md @@ -157,9 +157,9 @@ It works with both Emotion and styled-components. | Benchmark case | Code snippet | Time normalized | | :-------------------------------- | :-------------------- | --------------- | | a. Render 1,000 primitives | `
` | 100ms | - | b. Render 1,000 components | `
` | 120ms | - | c. Render 1,000 styled components | `` | 160ms | - | d. Render 1,000 Box | `` | 370ms | + | b. Render 1,000 components | `
` | 112ms | + | c. Render 1,000 styled components | `` | 181ms | + | d. Render 1,000 Box | `` | 296ms | diff --git a/docs/data/system/pages.ts b/docs/data/system/pages.ts index b8dff15a1777d4..a2936405ac5688 100644 --- a/docs/data/system/pages.ts +++ b/docs/data/system/pages.ts @@ -63,6 +63,17 @@ const pages = [ icon: 'CodeIcon', children: pagesApi, }, + { + pathname: '/system/experimental-api', + title: 'Experimental APIs', + icon: 'ExperimentIcon', + children: [ + { + pathname: '/system/experimental-api/configure-the-sx-prop', + title: 'Configure the sx prop', + }, + ], + }, { pathname: '/system/styles', title: 'Styles', diff --git a/docs/data/system/styled/UsingWithSx.js b/docs/data/system/styled/UsingWithSx.js index 9e50b6d44f5f71..ba14414f409018 100644 --- a/docs/data/system/styled/UsingWithSx.js +++ b/docs/data/system/styled/UsingWithSx.js @@ -1,10 +1,5 @@ import * as React from 'react'; -import { - styled, - createTheme, - ThemeProvider, - experimental_sx as sx, -} from '@mui/system'; +import { styled, createTheme, ThemeProvider } from '@mui/system'; const customTheme = createTheme({ palette: { @@ -15,8 +10,8 @@ const customTheme = createTheme({ }, }); -const MyThemeComponent = styled('div')( - sx({ +const MyThemeComponent = styled('div')(({ theme }) => + theme.unstable_sx({ color: 'primary.contrastText', backgroundColor: 'primary.main', padding: 1, diff --git a/docs/data/system/styled/UsingWithSx.tsx b/docs/data/system/styled/UsingWithSx.tsx index 9e50b6d44f5f71..ba14414f409018 100644 --- a/docs/data/system/styled/UsingWithSx.tsx +++ b/docs/data/system/styled/UsingWithSx.tsx @@ -1,10 +1,5 @@ import * as React from 'react'; -import { - styled, - createTheme, - ThemeProvider, - experimental_sx as sx, -} from '@mui/system'; +import { styled, createTheme, ThemeProvider } from '@mui/system'; const customTheme = createTheme({ palette: { @@ -15,8 +10,8 @@ const customTheme = createTheme({ }, }); -const MyThemeComponent = styled('div')( - sx({ +const MyThemeComponent = styled('div')(({ theme }) => + theme.unstable_sx({ color: 'primary.contrastText', backgroundColor: 'primary.main', padding: 1, diff --git a/docs/data/system/styled/styled.md b/docs/data/system/styled/styled.md index 6f3a69f6f9238a..5af4d2c8d68398 100644 --- a/docs/data/system/styled/styled.md +++ b/docs/data/system/styled/styled.md @@ -208,13 +208,13 @@ const MyStyledButton = (props) => ( ### How can I use the `sx` syntax with the `styled()` utility? -If you are one of those who prefers the `sx` syntax and wants to use it in both the `sx` prop and the `styled()` utility, you can use the `experimental_sx` utility from the `@mui/system`: +If you prefer the `sx` syntax and want to use it in both the `sx` prop and the `styled()` utility, you can use the `unstable_sx` utility from the `theme`: {{"demo": "UsingWithSx.js", "defaultCodeOpen": true}} -The overhead added by using the `experimental_sx` utility is the same as if you were to use the `sx` prop on the component. +The overhead added by using the `unstable_sx` utility is the same as if you were to use the `sx` prop on the component. -> Note: You can use `experimental_sx` outside of the `styled()` utility, too; e.g., for defining `variants` in your custom theme. +> Note: You can use `unstable_sx` outside of the `styled()` utility, too; e.g., for defining `variants` in your custom theme. ## How to use components selector API diff --git a/docs/pages/blog/callback-support-in-style-overrides.md b/docs/pages/blog/callback-support-in-style-overrides.md index 96f088a1226f55..b7e25bc17cd95d 100644 --- a/docs/pages/blog/callback-support-in-style-overrides.md +++ b/docs/pages/blog/callback-support-in-style-overrides.md @@ -117,26 +117,23 @@ const Label = styled('span')({ `sx` helps developers write less code and be more productive once they are familiar with the API. With the callback support in `styleOverrides`, it is now possible to use an `sx`-like syntax in global theme overrides. -All you need is to use the [`experimental_sx`](/system/styled/#how-can-i-use-the-sx-syntax-with-the-styled-utility) function. In the following example, I use `sx` to theme the `Chip` component: +All you need is to use the [`unstable_sx`](/system/styled/#how-can-i-use-the-sx-syntax-with-the-styled-utility) function from the `theme`. In the following example, the `sx` is used to style the `Chip` component: ```jsx -import { - ThemeProvider, - createTheme, - experimental_sx as sx, -} from '@mui/material/styles'; +import { ThemeProvider, createTheme } from '@mui/material/styles'; + theme.unstable_sx({ + px: '12px', // shorthand for padding-left & right + py: '6px', // shorthand for padding-top & bottom + fontWeight: 500, + borderRadius: '8px', + }), label: { padding: 0, }, @@ -159,19 +156,19 @@ An array can be used as a return type to make the code easier to add/remove cond ```js // The is omitted for readability. { - root: ({ ownerState }) => [ - sx({ + root: ({ ownerState, theme }) => [ + theme.unstable_sx({ px: '12px', py: '6px', fontWeight: 500, borderRadius: '8px', }), ownerState.variant === 'outlined' && ownerState.color === 'default' && - sx({ + theme.unstable_sx({ borderColor: 'text.secondary', }), ownerState.size === 'small' && - sx({ + theme.unstable_sx({ fontSize: { xs: '0.875rem', sm: '0.75rem' }, }) ], diff --git a/docs/pages/experiments/md3/index.tsx b/docs/pages/experiments/md3/index.tsx index 61614b46bf6467..0472963c9ffd07 100644 --- a/docs/pages/experiments/md3/index.tsx +++ b/docs/pages/experiments/md3/index.tsx @@ -151,6 +151,7 @@ function DemoComponents() { bgcolor: 'error', border: 1, borderColor: 'tertiary', + borderRadius: '1px', }} > Button @@ -161,10 +162,12 @@ function DemoComponents() { bgcolor: 'error.40', border: 1, borderColor: 'tertiary.40', + borderRadius: 2, }} > Button + MD2 Button

CSS vars playground

diff --git a/docs/pages/system/experimental-api/configure-the-sx-prop.js b/docs/pages/system/experimental-api/configure-the-sx-prop.js new file mode 100644 index 00000000000000..45c27611cde73e --- /dev/null +++ b/docs/pages/system/experimental-api/configure-the-sx-prop.js @@ -0,0 +1,7 @@ +import * as React from 'react'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import * as pageProps from 'docs/data/system/experimental-api/configure-the-sx-prop/configure-the-sx-prop.md?@mui/markdown'; + +export default function Page() { + return ; +} diff --git a/docs/translations/translations.json b/docs/translations/translations.json index 26149cf9612b28..9c4f72bd77bb7a 100644 --- a/docs/translations/translations.json +++ b/docs/translations/translations.json @@ -193,6 +193,8 @@ "/system/react-container": "Container", "/system/react-grid": "Grid", "/system/react-stack": "Stack", + "/system/experimental-api": "Experimental APIs", + "/system/experimental-api/configure-the-sx-prop": "Configure the sx prop", "/system/styles": "Styles", "/system/styles/basics": "Basics", "/system/styles/advanced": "Advanced", diff --git a/packages/mui-joy/src/Box/Box.test.js b/packages/mui-joy/src/Box/Box.test.js index 54193a56457090..b99f66c0393e17 100644 --- a/packages/mui-joy/src/Box/Box.test.js +++ b/packages/mui-joy/src/Box/Box.test.js @@ -1,7 +1,7 @@ import * as React from 'react'; import { expect } from 'chai'; import { createRenderer, describeConformance } from 'test/utils'; -import { ThemeProvider } from '@mui/joy/styles'; +import { ThemeProvider, CssVarsProvider, extendTheme } from '@mui/joy/styles'; import { unstable_ClassNameGenerator as ClassNameGenerator } from '@mui/joy/className'; import Box from '@mui/joy/Box'; @@ -65,4 +65,189 @@ describe('Joy ', () => { expect(container.firstChild).to.have.class('CompanyBox-root'); }); }); + + describe('sx', () => { + const theme = extendTheme({ + colorSchemes: { + light: { + palette: { + primary: { + 500: 'rgb(0, 0, 255)', + }, + }, + }, + }, + radius: { + md: '77px', + }, + shadow: { + md: 'rgb(0, 0, 0) 0px 0px 10px 0px', + }, + }); + + it('color', function test() { + const isJSDOM = /jsdom/.test(window.navigator.userAgent); + + if (isJSDOM) { + this.skip(); + } + + const { container } = render( + + + , + ); + + expect(container.firstChild).toHaveComputedStyle({ + color: 'rgb(0, 0, 255)', + }); + }); + + it('bgcolor', function test() { + const isJSDOM = /jsdom/.test(window.navigator.userAgent); + + if (isJSDOM) { + this.skip(); + } + + const { container } = render( + + + , + ); + + expect(container.firstChild).toHaveComputedStyle({ + backgroundColor: 'rgb(0, 0, 255)', + }); + }); + + it('backgroundColor', function test() { + const isJSDOM = /jsdom/.test(window.navigator.userAgent); + + if (isJSDOM) { + this.skip(); + } + + const { container } = render( + + + , + ); + + expect(container.firstChild).toHaveComputedStyle({ + backgroundColor: 'rgb(0, 0, 255)', + }); + }); + + it('borderRadius', function test() { + const isJSDOM = /jsdom/.test(window.navigator.userAgent); + + if (isJSDOM) { + this.skip(); + } + + const { container } = render( + + + , + ); + + expect(container.firstChild).toHaveComputedStyle({ + borderTopLeftRadius: '77px', + borderTopRightRadius: '77px', + borderBottomLeftRadius: '77px', + borderBottomRightRadius: '77px', + }); + }); + + it('boxShadow', function test() { + const isJSDOM = /jsdom/.test(window.navigator.userAgent); + + if (isJSDOM) { + this.skip(); + } + + const { container } = render( + + + , + ); + + expect(container.firstChild).toHaveComputedStyle({ + boxShadow: 'rgb(0, 0, 0) 0px 0px 10px 0px', + }); + }); + + it('fontSize', function test() { + const isJSDOM = /jsdom/.test(window.navigator.userAgent); + + if (isJSDOM) { + this.skip(); + } + + const { container } = render( + + + , + ); + + expect(container.firstChild).toHaveComputedStyle({ + fontSize: '16px', + }); + }); + + it('fontWeight', function test() { + const isJSDOM = /jsdom/.test(window.navigator.userAgent); + + if (isJSDOM) { + this.skip(); + } + + const { container } = render( + + + , + ); + + expect(container.firstChild).toHaveComputedStyle({ + fontWeight: '500', + }); + }); + + it('letterSpacing', function test() { + const isJSDOM = /jsdom/.test(window.navigator.userAgent); + + if (isJSDOM) { + this.skip(); + } + + const { container } = render( + + + , + ); + + expect(container.firstChild).toHaveComputedStyle({ + letterSpacing: '1.328px', + }); + }); + + it('lineHeight', function test() { + const isJSDOM = /jsdom/.test(window.navigator.userAgent); + + if (isJSDOM) { + this.skip(); + } + + const { container } = render( + + + , + ); + + expect(container.firstChild).toHaveComputedStyle({ + lineHeight: '24px', + }); + }); + }); }); diff --git a/packages/mui-joy/src/Box/Box.tsx b/packages/mui-joy/src/Box/Box.tsx index 6f3115e13cc403..9192e6a906140a 100644 --- a/packages/mui-joy/src/Box/Box.tsx +++ b/packages/mui-joy/src/Box/Box.tsx @@ -4,13 +4,11 @@ import { OverridableComponent } from '@mui/types'; import { unstable_ClassNameGenerator as ClassNameGenerator } from '../className'; import { BoxTypeMap } from './BoxProps'; import defaultTheme from '../styles/defaultTheme'; -import styleFunctionSx from '../styles/styleFunctionSx'; const Box = createBox({ defaultTheme, defaultClassName: 'JoyBox-root', generateClassName: ClassNameGenerator.generate, - styleFunctionSx, }) as OverridableComponent; Box.propTypes /* remove-proptypes */ = { diff --git a/packages/mui-joy/src/styles/CssVarsProvider.tsx b/packages/mui-joy/src/styles/CssVarsProvider.tsx index f47e62034c3886..ec25fd66ade574 100644 --- a/packages/mui-joy/src/styles/CssVarsProvider.tsx +++ b/packages/mui-joy/src/styles/CssVarsProvider.tsx @@ -1,8 +1,11 @@ import { deepmerge } from '@mui/utils'; -import { unstable_createCssVarsProvider as createCssVarsProvider } from '@mui/system'; +import { + unstable_createCssVarsProvider as createCssVarsProvider, + unstable_styleFunctionSx as styleFunctionSx, +} from '@mui/system'; import extendTheme from './extendTheme'; import { createSoftInversion, createSolidInversion } from './variantUtils'; -import type { Theme, DefaultColorScheme, ExtendedColorScheme } from './types'; +import type { Theme, DefaultColorScheme, ExtendedColorScheme, SxProps } from './types'; const shouldSkipGeneratingVar = (keys: string[]) => !!keys[0].match(/^(typography|variants|breakpoints|colorInversion|colorInversionConfig)$/) || @@ -30,6 +33,11 @@ const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssV mergedTheme.colorInversion, { clone: false }, ); + + // TOOD remove this intermediary function call. + mergedTheme.unstable_sx = function sx(props: SxProps) { + return styleFunctionSx({ sx: props, theme: this }); + }; return mergedTheme; }, shouldSkipGeneratingVar, diff --git a/packages/mui-joy/src/styles/ThemeProvider.tsx b/packages/mui-joy/src/styles/ThemeProvider.tsx index 76df36c94ff756..2a8d8029d10eaa 100644 --- a/packages/mui-joy/src/styles/ThemeProvider.tsx +++ b/packages/mui-joy/src/styles/ThemeProvider.tsx @@ -1,5 +1,10 @@ import * as React from 'react'; -import { ThemeProvider as SystemThemeProvider, useTheme as useSystemTheme } from '@mui/system'; +import { + ThemeProvider as SystemThemeProvider, + unstable_styleFunctionSx as styleFunctionSx, + useTheme as useSystemTheme, +} from '@mui/system'; +import { SxProps } from './types'; import defaultTheme, { getThemeWithVars } from './defaultTheme'; import type { CssVarsThemeOptions } from './extendTheme'; @@ -7,6 +12,15 @@ export const useTheme = () => { return useSystemTheme(defaultTheme); }; +const getTheme = (themeInput: CssVarsThemeOptions) => { + const theme = getThemeWithVars(themeInput); + theme.unstable_sx = function sx(props: SxProps) { + return styleFunctionSx({ sx: props, theme: this }); + }; + + return theme; +}; + export default function ThemeProvider({ children, theme: themeInput, @@ -14,7 +28,7 @@ export default function ThemeProvider({ theme?: CssVarsThemeOptions; }>) { return ( - + {children} ); diff --git a/packages/mui-joy/src/styles/defaultTheme.test.js b/packages/mui-joy/src/styles/defaultTheme.test.js index 38928cc057b694..b3125cabadaff9 100644 --- a/packages/mui-joy/src/styles/defaultTheme.test.js +++ b/packages/mui-joy/src/styles/defaultTheme.test.js @@ -29,6 +29,8 @@ describe('defaultTheme', () => { 'vars', 'cssVarPrefix', 'getColorSchemeSelector', + 'unstable_sxConfig', + 'unstable_sx', ]).to.includes(field); }); }); diff --git a/packages/mui-joy/src/styles/defaultTheme.ts b/packages/mui-joy/src/styles/defaultTheme.ts index cce16945265ee6..7d48cf03a1291a 100644 --- a/packages/mui-joy/src/styles/defaultTheme.ts +++ b/packages/mui-joy/src/styles/defaultTheme.ts @@ -1,7 +1,9 @@ import { deepmerge } from '@mui/utils'; +import { unstable_styleFunctionSx as styleFunctionSx } from '@mui/system'; import extendTheme from './extendTheme'; +import defaultSxConfig from './sxConfig'; import type { CssVarsThemeOptions, ColorSystemOptions } from './extendTheme'; -import type { Theme, RuntimeColorSystem } from './types'; +import type { Theme, RuntimeColorSystem, SxProps } from './types'; import { createVariant, createSoftInversion, createSolidInversion } from './variantUtils'; export const getThemeWithVars = ( @@ -95,4 +97,9 @@ defaultTheme.colorInversion = deepmerge( defaultTheme.colorInversion, ); +defaultTheme.unstable_sxConfig = defaultSxConfig; +defaultTheme.unstable_sx = function sx(props: SxProps) { + return styleFunctionSx({ sx: props, theme: this }); +}; + export default defaultTheme; diff --git a/packages/mui-joy/src/styles/extendTheme.test.js b/packages/mui-joy/src/styles/extendTheme.test.js index 37f5636066f82e..cf39c5667968c9 100644 --- a/packages/mui-joy/src/styles/extendTheme.test.js +++ b/packages/mui-joy/src/styles/extendTheme.test.js @@ -23,6 +23,8 @@ describe('extendTheme', () => { 'colorInversionConfig', 'variants', 'cssVarPrefix', + 'unstable_sxConfig', + 'unstable_sx', ]).to.includes(field); }); }); diff --git a/packages/mui-joy/src/styles/extendTheme.ts b/packages/mui-joy/src/styles/extendTheme.ts index bff0c2f194c0b9..141a3d4f05c220 100644 --- a/packages/mui-joy/src/styles/extendTheme.ts +++ b/packages/mui-joy/src/styles/extendTheme.ts @@ -6,14 +6,17 @@ import { createSpacing, unstable_createGetCssVar as systemCreateGetCssVar, colorChannel, + unstable_styleFunctionSx as styleFunctionSx, + SxConfig, } from '@mui/system'; +import defaultSxConfig from './sxConfig'; import colors from '../colors'; import { DefaultColorScheme, ExtendedColorScheme } from './types/colorScheme'; import { ColorSystem, ColorPaletteProp, PaletteRange } from './types/colorSystem'; import { Focus } from './types/focus'; import { TypographySystem, FontSize } from './types/typography'; import { Variants, VariantOverrides, ColorInversionConfig } from './types/variants'; -import { Theme, ThemeCssVar, ThemeScales } from './types'; +import { Theme, ThemeCssVar, ThemeScales, SxProps } from './types'; import { Components } from './components'; import { generateUtilityClass } from '../className'; import { createVariant } from './variantUtils'; @@ -60,6 +63,7 @@ export interface CssVarsThemeOptions extends Partial2Level { spacing?: SpacingOptions; components?: Components; colorSchemes?: Partial>; + unstable_sxConfig?: SxConfig; } export const createGetCssVar = (cssVarPrefix = 'joy') => @@ -623,5 +627,16 @@ export default function extendTheme(themeOptions?: CssVarsThemeOptions): Theme { attachColorChannels(colorSystem.palette); }); + theme.unstable_sxConfig = { + ...defaultSxConfig, + ...themeOptions?.unstable_sxConfig, + }; + theme.unstable_sx = function sx(props: SxProps) { + return styleFunctionSx({ + sx: props, + theme: this, + }); + }; + return theme; } diff --git a/packages/mui-joy/src/styles/index.ts b/packages/mui-joy/src/styles/index.ts index f674dcf5b89451..254a66e088fd5d 100644 --- a/packages/mui-joy/src/styles/index.ts +++ b/packages/mui-joy/src/styles/index.ts @@ -71,7 +71,6 @@ export { default as styled } from './styled'; export { default as ThemeProvider } from './ThemeProvider'; export * from './ThemeProvider'; export { default as useThemeProps } from './useThemeProps'; -export { sx as experimental_sx } from './styleFunctionSx'; export { ColorInversionProvider, useColorInversion } from './ColorInversion'; export { default as extendTheme, createGetCssVar } from './extendTheme'; export type { CssVarsThemeOptions } from './extendTheme'; diff --git a/packages/mui-joy/src/styles/styleFunctionSx.spec.tsx b/packages/mui-joy/src/styles/styleFunctionSx.spec.tsx index e143ae90a818e7..e2bde5aad54bed 100644 --- a/packages/mui-joy/src/styles/styleFunctionSx.spec.tsx +++ b/packages/mui-joy/src/styles/styleFunctionSx.spec.tsx @@ -1,10 +1,22 @@ -import { experimental_sx as sx, styled } from '@mui/joy/styles'; +import { styled } from '@mui/joy/styles'; // Can be used in the styled() utility -const Test = styled('div')( - sx({ +const Test = styled('div')(({ theme }) => + theme.unstable_sx({ color: 'primary.100', bgcolor: 'primary.700', m: 2, }), ); + +// Can be used in when styles are defined as arrays +const TestArray = styled('div')( + ({ theme }) => theme.unstable_sx({ color: 'primary.100' }), + ({ theme }) => theme.unstable_sx({ mt: 2 }), +); + +// Can be used inside pseudo elements +const TestPseudo = styled('div')(({ theme }) => ({ + ...theme.unstable_sx({ color: 'primary.100' }), + '&:hover': theme.unstable_sx({ color: 'primary.700' }), +})); diff --git a/packages/mui-joy/src/styles/styleFunctionSx.test.js b/packages/mui-joy/src/styles/styleFunctionSx.test.js deleted file mode 100644 index b16baf81347169..00000000000000 --- a/packages/mui-joy/src/styles/styleFunctionSx.test.js +++ /dev/null @@ -1,132 +0,0 @@ -import { expect } from 'chai'; -import { createBreakpoints } from '@mui/system'; -import styleFunctionSx from './styleFunctionSx'; - -describe('styleFunctionSx', () => { - const theme = { - palette: { - primary: { - 500: '#ff5252', - }, - }, - vars: { - palette: { - primary: { - 500: 'var(--palette-primary-500)', - textColor: 'var(--palette-primary-textColor)', - containedBg: 'var(--palette-primary-containedBg)', - outlinedBorder: 'var(--palette-primary-outlinedBorder)', - }, - }, - radius: { - md: 'var(--radius-md)', - }, - shadow: { - md: 'var(--shadow-md)', - }, - fontFamily: { - display: 'var(--fontFamily-display)', - }, - fontSize: { - sm: 'var(--fontSize-sm)', - md: 'var(--fontSize-md)', - xl: 'var(--fontSize-xl)', - }, - fontWeight: { - md: 'var(--fontWeight-md)', - }, - letterSpacing: { - md: 'var(--letterSpacing-md)', - }, - lineHeight: { - md: 'var(--lineHeight-md)', - }, - }, - breakpoints: createBreakpoints({}), - }; - it('color', () => { - expect(styleFunctionSx({ theme, sx: { color: 'primary.500' } })).to.deep.equal({ - color: 'var(--palette-primary-500)', - }); - }); - - it('bgcolor', () => { - expect(styleFunctionSx({ theme, sx: { bgcolor: 'primary.containedBg' } })).to.deep.equal({ - backgroundColor: 'var(--palette-primary-containedBg)', - }); - }); - - it('backgroundColor', () => { - expect( - styleFunctionSx({ theme, sx: { backgroundColor: 'primary.containedBg' } }), - ).to.deep.equal({ - backgroundColor: 'var(--palette-primary-containedBg)', - }); - }); - - it('borderColor', () => { - expect(styleFunctionSx({ theme, sx: { borderColor: 'primary.outlinedBorder' } })).to.deep.equal( - { - borderColor: 'var(--palette-primary-outlinedBorder)', - }, - ); - }); - - it('borderRadius', () => { - expect(styleFunctionSx({ theme, sx: { borderRadius: 'md' } })).to.deep.equal({ - borderRadius: 'var(--radius-md)', - }); - }); - - it('boxShadow', () => { - expect(styleFunctionSx({ theme, sx: { boxShadow: 'md' } })).to.deep.equal({ - boxShadow: 'var(--shadow-md)', - }); - }); - - it('fontFamily', () => { - expect(styleFunctionSx({ theme, sx: { fontFamily: 'display' } })).to.deep.equal({ - fontFamily: 'var(--fontFamily-display)', - }); - }); - - it('fontSize', () => { - expect(styleFunctionSx({ theme, sx: { fontSize: 'md' } })).to.deep.equal({ - fontSize: 'var(--fontSize-md)', - }); - }); - - it('fontWeight', () => { - expect(styleFunctionSx({ theme, sx: { fontWeight: 'md' } })).to.deep.equal({ - fontWeight: 'var(--fontWeight-md)', - }); - }); - - it('letterSpacing', () => { - expect(styleFunctionSx({ theme, sx: { letterSpacing: 'md' } })).to.deep.equal({ - letterSpacing: 'var(--letterSpacing-md)', - }); - }); - - it('lineHeight', () => { - expect(styleFunctionSx({ theme, sx: { lineHeight: 'md' } })).to.deep.equal({ - lineHeight: 'var(--lineHeight-md)', - }); - }); - - it('should handle reponsive styles', () => { - expect( - styleFunctionSx({ theme, sx: { fontSize: { xs: 'sm', md: 'md', xl: 'xl' } } }), - ).to.deep.equal({ - '@media (min-width:0px)': { - fontSize: 'var(--fontSize-sm)', - }, - '@media (min-width:900px)': { - fontSize: 'var(--fontSize-md)', - }, - '@media (min-width:1536px)': { - fontSize: 'var(--fontSize-xl)', - }, - }); - }); -}); diff --git a/packages/mui-joy/src/styles/styleFunctionSx.ts b/packages/mui-joy/src/styles/styleFunctionSx.ts deleted file mode 100644 index 363b9dc8de62bf..00000000000000 --- a/packages/mui-joy/src/styles/styleFunctionSx.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { - Interpolation, - unstable_createStyleFunctionSx, - compose, - style, - display, - flexbox, - grid, - positions, - sizing, - spacing, - border, - borderTop, - borderRight, - borderBottom, - borderLeft, - borderColor, - borderTopColor, - borderRightColor, - borderBottomColor, - borderLeftColor, - palette, - typographyVariant, -} from '@mui/system'; -import { Theme, SxProps } from './types'; - -// The default system themeKey is shape -const borderRadius = style({ - prop: 'borderRadius', - themeKey: 'radius', -}); - -const borders = compose( - border, - borderTop, - borderRight, - borderBottom, - borderLeft, - borderColor, - borderTopColor, - borderRightColor, - borderBottomColor, - borderLeftColor, - borderRadius, -); - -// The default system themeKey is shadows -const boxShadow = style({ - prop: 'boxShadow', - themeKey: 'shadow', -}); - -// The default system themeKey is typography -export const fontFamily = style({ - prop: 'fontFamily', - themeKey: 'fontFamily', -}); - -// The default system themeKey is typography -export const fontSize = style({ - prop: 'fontSize', - themeKey: 'fontSize', -}); - -// The default system themeKey is typography -export const fontWeight = style({ - prop: 'fontWeight', - themeKey: 'fontWeight', -}); - -// The default system themeKey is typography -export const letterSpacing = style({ - prop: 'letterSpacing', - themeKey: 'letterSpacing', -}); - -export const lineHeight = style({ - prop: 'lineHeight', - themeKey: 'lineHeight', -}); - -const typography = compose( - typographyVariant, - fontFamily, - fontSize, - fontWeight, - letterSpacing, - lineHeight, -); - -const styleFunctionMapping = { - borders, - display, - flexbox, - grid, - positions, - palette, - boxShadow, - sizing, - spacing, - typography, -}; - -const styleFunctionSx = unstable_createStyleFunctionSx(styleFunctionMapping); - -styleFunctionSx.filterProps = ['sx']; - -export const sx = (styles: SxProps) => { - return ({ theme }: { theme: Theme }) => - styleFunctionSx({ sx: styles, theme }) as Interpolation<{ theme: Theme }>; -}; - -export default styleFunctionSx; diff --git a/packages/mui-joy/src/styles/styled.test.tsx b/packages/mui-joy/src/styles/styled.test.tsx index e4fe16ce320f13..8ce677f6efd539 100644 --- a/packages/mui-joy/src/styles/styled.test.tsx +++ b/packages/mui-joy/src/styles/styled.test.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { expect } from 'chai'; import { createRenderer } from 'test/utils'; -import { ThemeProvider, styled } from '@mui/joy/styles'; +import { CssVarsProvider, ThemeProvider, styled, extendTheme } from '@mui/joy/styles'; import defaultTheme from './defaultTheme'; const toPixel = (val: string | number | undefined) => (typeof val === 'number' ? `${val}px` : val); @@ -47,4 +47,32 @@ describe('[Joy] styled', () => { borderBottomLeftRadius: '50%', }); }); + + it('supports unstable_sx in the theme callback', function test() { + if (/jsdom/.test(window.navigator.userAgent)) { + this.skip(); + } + const customTheme = extendTheme({ + colorSchemes: { + light: { + palette: { + primary: { + plainColor: 'rgb(255, 0, 0)', + }, + }, + }, + }, + }); + const Text = styled('div')(({ theme }) => theme.unstable_sx({ color: 'primary.plainColor' })); + + const { container } = render( + + Text + , + ); + + expect(container.firstChild).toHaveComputedStyle({ + color: 'rgb(255, 0, 0)', + }); + }); }); diff --git a/packages/mui-joy/src/styles/styled.ts b/packages/mui-joy/src/styles/styled.ts index 0b3efd0b9649e9..a6dfd1c5a1f408 100644 --- a/packages/mui-joy/src/styles/styled.ts +++ b/packages/mui-joy/src/styles/styled.ts @@ -1,8 +1,7 @@ import { createStyled } from '@mui/system'; import { Theme } from './types'; import defaultTheme from './defaultTheme'; -import styleFunctionSx from './styleFunctionSx'; -const styled = createStyled({ defaultTheme, styleFunctionSx }); +const styled = createStyled({ defaultTheme }); export default styled; diff --git a/packages/mui-joy/src/styles/sxConfig.ts b/packages/mui-joy/src/styles/sxConfig.ts new file mode 100644 index 00000000000000..40963c5e80b70c --- /dev/null +++ b/packages/mui-joy/src/styles/sxConfig.ts @@ -0,0 +1,35 @@ +import { SxConfig, unstable_defaultSxConfig } from '@mui/system'; + +const sxConfig: SxConfig = { + ...unstable_defaultSxConfig, + // The default system themeKey is shape + borderRadius: { + themeKey: 'radius', + }, + // The default system themeKey is shadows + boxShadow: { + themeKey: 'shadow', + }, + // The default system themeKey is typography + fontFamily: { + themeKey: 'fontFamily', + }, + // The default system themeKey is typography + fontSize: { + themeKey: 'fontSize', + }, + // The default system themeKey is typography + fontWeight: { + themeKey: 'fontWeight', + }, + // The default system themeKey is typography + letterSpacing: { + themeKey: 'letterSpacing', + }, + // The default system themeKey is typography + lineHeight: { + themeKey: 'lineHeight', + }, +}; + +export default sxConfig; diff --git a/packages/mui-joy/src/styles/types/theme.ts b/packages/mui-joy/src/styles/types/theme.ts index 4621a31fdc4967..7a4a4352a606ae 100644 --- a/packages/mui-joy/src/styles/types/theme.ts +++ b/packages/mui-joy/src/styles/types/theme.ts @@ -4,6 +4,8 @@ import { Spacing, SxProps as SystemSxProps, SystemProps as SystemSystemProps, + CSSObject, + SxConfig, } from '@mui/system'; import { DefaultColorScheme, ExtendedColorScheme } from './colorScheme'; import { ColorSystem } from './colorSystem'; @@ -80,6 +82,8 @@ export interface Theme extends ThemeScales, RuntimeColorSystem { vars: ThemeVars; getCssVar: (field: ThemeCssVar, ...vars: ThemeCssVar[]) => string; getColorSchemeSelector: (colorScheme: DefaultColorScheme | ExtendedColorScheme) => string; + unstable_sxConfig: SxConfig; + unstable_sx: (props: SxProps) => CSSObject; } export type SxProps = SystemSxProps; diff --git a/packages/mui-material-next/src/styles/CssVarsProvider.tsx b/packages/mui-material-next/src/styles/CssVarsProvider.tsx index 05a9aef2bb47a2..b3a7522df9074e 100644 --- a/packages/mui-material-next/src/styles/CssVarsProvider.tsx +++ b/packages/mui-material-next/src/styles/CssVarsProvider.tsx @@ -1,9 +1,14 @@ -import { unstable_createCssVarsProvider as createCssVarsProvider } from '@mui/system'; +import { + unstable_createCssVarsProvider as createCssVarsProvider, + unstable_styleFunctionSx as styleFunctionSx, + SxProps, +} from '@mui/system'; import { SupportedColorScheme, private_createTypography as createTypography, private_excludeVariablesFromRoot as excludeVariablesFromRoot, } from '@mui/material/styles'; +import { Theme } from './Theme.types'; import defaultTheme from './defaultTheme'; const shouldSkipGeneratingVar = (keys: string[]) => @@ -26,6 +31,9 @@ const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = typography: createTypography(theme.palette, theme.typography), }; + newTheme.unstable_sx = function sx(props: SxProps) { + return styleFunctionSx({ sx: props, theme: this }); + }; return newTheme; }, shouldSkipGeneratingVar, diff --git a/packages/mui-material-next/src/styles/Theme.types.ts b/packages/mui-material-next/src/styles/Theme.types.ts index 5db38f25017d04..964e05a6342831 100644 --- a/packages/mui-material-next/src/styles/Theme.types.ts +++ b/packages/mui-material-next/src/styles/Theme.types.ts @@ -1,4 +1,4 @@ -import { SxProps as SystemSxProps } from '@mui/system'; +import { SxProps as SystemSxProps, SxConfig, CSSObject } from '@mui/system'; import { CssVarsTheme as MD2Theme, SupportedColorScheme, @@ -192,6 +192,8 @@ export interface Theme extends Omit { shape: Shapes; }; }; + unstable_sxConfig: SxConfig; + unstable_sx: (props: SystemSxProps) => CSSObject; } export type SxProps = SystemSxProps; diff --git a/packages/mui-material-next/src/styles/defaultTheme.ts b/packages/mui-material-next/src/styles/defaultTheme.ts index 394ec08f05c481..3daba490449ec5 100644 --- a/packages/mui-material-next/src/styles/defaultTheme.ts +++ b/packages/mui-material-next/src/styles/defaultTheme.ts @@ -1,6 +1,8 @@ import { deepmerge } from '@mui/utils'; +import { unstable_styleFunctionSx as styleFunctionSx, SxProps } from '@mui/system'; import extendTheme from './extendTheme'; import type { Theme, CssVarsThemeOptions, ColorSystemOptions } from './Theme.types'; +import defaultSxConfig from './sxConfig'; export const getThemeWithVars = ( themeInput?: Omit & ColorSystemOptions, @@ -78,4 +80,9 @@ export const getThemeWithVars = ( const defaultTheme = getThemeWithVars(); +defaultTheme.unstable_sxConfig = defaultSxConfig; +defaultTheme.unstable_sx = function sx(props: SxProps) { + return styleFunctionSx({ sx: props, theme: this }); +}; + export default defaultTheme; diff --git a/packages/mui-material-next/src/styles/extendTheme.ts b/packages/mui-material-next/src/styles/extendTheme.ts index 90df3bac3eefaf..b321d806e38908 100644 --- a/packages/mui-material-next/src/styles/extendTheme.ts +++ b/packages/mui-material-next/src/styles/extendTheme.ts @@ -6,6 +6,8 @@ import { lighten, emphasize, unstable_createGetCssVar as systemCreateGetCssVar, + unstable_styleFunctionSx as styleFunctionSx, + SxProps, } from '@mui/system'; import { createTheme as createThemeWithoutVars, @@ -14,6 +16,7 @@ import { ColorSystem as MD2ColorSystem, Overlays, } from '@mui/material/styles'; +import defaultSxConfig from './sxConfig'; import { Theme, MD3Palettes, MD3ColorSchemeTokens, CssVarsThemeOptions } from './Theme.types'; import md3CommonPalette from './palette'; import createMd3LightColorScheme from './createLightColorScheme'; @@ -420,5 +423,16 @@ export default function extendTheme(options: CssVarsThemeOptions = {}, ...args: theme = args.reduce((acc, argument) => deepmerge(acc, argument), theme); + theme.unstable_sxConfig = { + ...defaultSxConfig, + ...input?.unstable_sxConfig, + }; + theme.unstable_sx = function sx(props: SxProps) { + return styleFunctionSx({ + sx: props, + theme: this, + }); + }; + return theme; } diff --git a/packages/mui-material-next/src/styles/styleFunctionSx.ts b/packages/mui-material-next/src/styles/styleFunctionSx.ts deleted file mode 100644 index 9160b29d1bd000..00000000000000 --- a/packages/mui-material-next/src/styles/styleFunctionSx.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { - Interpolation, - unstable_createStyleFunctionSx, - compose, - getPath, - getStyleValue as getValue, - display, - flexbox, - grid, - positions, - sizing, - spacing, - border, - borderTop, - borderRight, - borderBottom, - borderLeft, - borderTopColor, - borderRightColor, - borderBottomColor, - borderLeftColor, - createUnaryUnit, - handleBreakpoints, - responsivePropType, - typography, -} from '@mui/system'; -import { SxProps, Theme } from './Theme.types'; - -interface PaletteStyleOptions { - prop: string; - cssProperty?: string | boolean; -} - -function paletteStyle(options: PaletteStyleOptions = { prop: 'color' }) { - const { prop, cssProperty = options.prop } = options; - - const fn = (props: Record) => { - if (props[prop] == null) { - return null; - } - - const propValue: any = props[prop]; - const theme = props.theme; - const colorThemeMapping = getPath(theme, 'sys.color') || {}; - const paletteThemeMapping = getPath(theme, 'ref.palette') || {}; - - const styleFromPropValue = (propValueFinal: any) => { - // check the value in the color mapping first - let value = getValue(colorThemeMapping, undefined, propValueFinal); - - if (propValueFinal === value) { - // haven't found value in colors mapping, so we are checking in the palette mapping - value = getValue(paletteThemeMapping, undefined, propValueFinal); - } - - if (cssProperty === false) { - return value; - } - - return { - [cssProperty as string]: value, - }; - }; - - return handleBreakpoints(props, propValue, styleFromPropValue); - }; - - fn.propTypes = - process.env.NODE_ENV !== 'production' - ? { - [prop]: responsivePropType, - } - : {}; - - fn.filterProps = [prop]; - - return fn; -} - -// Palette values should reference the color tokens -export const color = paletteStyle({ - prop: 'color', -}); - -export const bgcolor = paletteStyle({ - prop: 'bgcolor', - cssProperty: 'backgroundColor', -}); - -export const backgroundColor = paletteStyle({ - prop: 'backgroundColor', -}); - -const palette = compose(color, bgcolor, backgroundColor); - -// Border radius should mapa to md3.shape -export const borderRadius = (props: any) => { - if (props.borderRadius !== undefined && props.borderRadius !== null) { - const transformer = createUnaryUnit(props.theme, 'md3.shape.borderRadius', 4, 'borderRadius'); - const styleFromPropValue = (propValue: any) => ({ - // @ts-ignore - borderRadius: getValue(transformer, propValue), - }); - return handleBreakpoints(props, props.borderRadius, styleFromPropValue); - } - - return null; -}; - -borderRadius.propTypes = - process.env.NODE_ENV !== 'production' ? { borderRadius: responsivePropType } : {}; - -const borderColor = paletteStyle({ - prop: 'borderColor', -}); - -borderRadius.filterProps = ['borderRadius']; -const borders = compose( - border, - borderTop, - borderRight, - borderBottom, - borderLeft, - borderColor, - borderTopColor, - borderRightColor, - borderBottomColor, - borderLeftColor, - borderRadius, -); - -const styleFunctionMapping = { - borders, - display, - flexbox, - grid, - positions, - palette, - sizing, - spacing, - typography, -}; - -const styleFunctionSx = unstable_createStyleFunctionSx(styleFunctionMapping); - -styleFunctionSx.filterProps = ['sx']; - -export const sx = (styles: SxProps) => { - return ({ theme }: { theme: Theme }) => - styleFunctionSx({ sx: styles, theme }) as Interpolation<{ theme: Theme }>; -}; - -export default styleFunctionSx; diff --git a/packages/mui-material-next/src/styles/styled.test.js b/packages/mui-material-next/src/styles/styled.test.js new file mode 100644 index 00000000000000..43fa2987f0b07e --- /dev/null +++ b/packages/mui-material-next/src/styles/styled.test.js @@ -0,0 +1,202 @@ +import * as React from 'react'; +import { expect } from 'chai'; +import { createRenderer, screen } from 'test/utils'; +import { styled } from '@mui/material-next/styles'; + +describe('styled', () => { + const { render } = createRenderer(); + + it('should work', () => { + const Div = styled('div')` + width: 200px; + `; + + const { container } = render(
Test
); + + expect(container.firstChild).toHaveComputedStyle({ + width: '200px', + }); + }); + + it('should use defaultTheme if no theme is provided', () => { + const Div = styled('div')` + width: ${(props) => props.theme.spacing(1)}; + `; + + const { container } = render(
Test
); + + expect(container.firstChild).toHaveComputedStyle({ + width: '8px', + }); + }); + + describe('dynamic styles', () => { + it('can adapt styles to props', () => { + const Div = styled('div')` + font-size: ${(props) => props.scale * 8}px; + padding-left: ${(props) => props.scale * 2}px; + `; + render(
); + + expect(screen.getByTestId('target')).toHaveComputedStyle({ + fontSize: '32px', + paddingLeft: '8px', + }); + }); + }); + + describe('sx prop', () => { + it('should apply color prop to theme.sys.color if available', function test() { + if (/jsdom/.test(window.navigator.userAgent)) { + this.skip(); + } + const Div = styled('div')``; + + render(
); + + expect(screen.getByTestId('target')).toHaveComputedStyle({ + color: 'rgb(179, 38, 30)', + }); + }); + it('should apply color prop to theme.ref.palette if available', function test() { + if (/jsdom/.test(window.navigator.userAgent)) { + this.skip(); + } + const Div = styled('div')``; + + render(
); + + expect(screen.getByTestId('target')).toHaveComputedStyle({ + color: 'rgb(242, 184, 181)', + }); + }); + it('should apply bgcolor prop to theme.sys.color if available', function test() { + if (/jsdom/.test(window.navigator.userAgent)) { + this.skip(); + } + const Div = styled('div')``; + + render(
); + + expect(screen.getByTestId('target')).toHaveComputedStyle({ + backgroundColor: 'rgb(179, 38, 30)', + }); + }); + it('should apply bgcolor prop to theme.ref.palette if available', function test() { + if (/jsdom/.test(window.navigator.userAgent)) { + this.skip(); + } + const Div = styled('div')``; + + render(
); + + expect(screen.getByTestId('target')).toHaveComputedStyle({ + backgroundColor: 'rgb(242, 184, 181)', + }); + }); + it('should apply backgroundColor prop to theme.sys.color if available', function test() { + if (/jsdom/.test(window.navigator.userAgent)) { + this.skip(); + } + const Div = styled('div')``; + + render(
); + + expect(screen.getByTestId('target')).toHaveComputedStyle({ + backgroundColor: 'rgb(179, 38, 30)', + }); + }); + it('should apply backgroundColor prop to theme.ref.palette if available', function test() { + if (/jsdom/.test(window.navigator.userAgent)) { + this.skip(); + } + const Div = styled('div')``; + + render(
); + + expect(screen.getByTestId('target')).toHaveComputedStyle({ + backgroundColor: 'rgb(242, 184, 181)', + }); + }); + it('should apply border*Color props to theme.sys.color if available', function test() { + if (/jsdom/.test(window.navigator.userAgent)) { + this.skip(); + } + const Div = styled('div')``; + + render( +
, + ); + + expect(screen.getByTestId('target')).toHaveComputedStyle({ + borderTopColor: 'rgb(179, 38, 30)', + borderBottomColor: 'rgb(179, 38, 30)', + borderLeftColor: 'rgb(179, 38, 30)', + borderRightColor: 'rgb(179, 38, 30)', + }); + }); + it('should apply border*Color props to theme.ref.palette if available', function test() { + if (/jsdom/.test(window.navigator.userAgent)) { + this.skip(); + } + const Div = styled('div')``; + + render( +
, + ); + + expect(screen.getByTestId('target')).toHaveComputedStyle({ + borderTopColor: 'rgb(242, 184, 181)', + borderBottomColor: 'rgb(242, 184, 181)', + borderLeftColor: 'rgb(242, 184, 181)', + borderRightColor: 'rgb(242, 184, 181)', + }); + }); + it('should apply borderColor props to theme.sys.color if available', function test() { + if (/jsdom/.test(window.navigator.userAgent)) { + this.skip(); + } + const Div = styled('div')``; + + render(
); + + expect(screen.getByTestId('target')).toHaveComputedStyle({ + borderTopColor: 'rgb(179, 38, 30)', + borderBottomColor: 'rgb(179, 38, 30)', + borderLeftColor: 'rgb(179, 38, 30)', + borderRightColor: 'rgb(179, 38, 30)', + }); + }); + it('should apply borderColor props to theme.ref.palette if available', function test() { + if (/jsdom/.test(window.navigator.userAgent)) { + this.skip(); + } + const Div = styled('div')``; + + render(
); + + expect(screen.getByTestId('target')).toHaveComputedStyle({ + borderTopColor: 'rgb(242, 184, 181)', + borderBottomColor: 'rgb(242, 184, 181)', + borderLeftColor: 'rgb(242, 184, 181)', + borderRightColor: 'rgb(242, 184, 181)', + }); + }); + }); +}); diff --git a/packages/mui-material-next/src/styles/styled.ts b/packages/mui-material-next/src/styles/styled.ts index 2e8f6c5a463872..f0cccfa63f3c13 100644 --- a/packages/mui-material-next/src/styles/styled.ts +++ b/packages/mui-material-next/src/styles/styled.ts @@ -1,8 +1,7 @@ import { createStyled } from '@mui/system'; import { Theme } from './Theme.types'; import defaultTheme from './defaultTheme'; -import styleFunctionSx from './styleFunctionSx'; -const styled = createStyled({ defaultTheme, styleFunctionSx }); +const styled = createStyled({ defaultTheme }); export default styled; diff --git a/packages/mui-material-next/src/styles/sxConfig.ts b/packages/mui-material-next/src/styles/sxConfig.ts new file mode 100644 index 00000000000000..eb2bc0efa2743d --- /dev/null +++ b/packages/mui-material-next/src/styles/sxConfig.ts @@ -0,0 +1,64 @@ +import { getPath, handleBreakpoints, SxConfig, unstable_defaultSxConfig } from '@mui/system'; + +interface PaletteStyleOptions { + prop: string; + cssProperty?: string | boolean; +} + +function createPaletteStyle(options: PaletteStyleOptions = { prop: 'color' }) { + const { prop, cssProperty = options.prop } = options; + + const fn = (props: Record) => { + if (props[prop] == null) { + return null; + } + + const propValue: any = props[prop]; + const theme = props.theme; + + const styleFromPropValue = (propValueFinal: any) => { + const value = + getPath(theme, `sys.color.${propValueFinal}`, true) || + getPath(theme, `ref.palette.${propValueFinal}`, true) || + getPath(theme, `palette.${propValueFinal}`, true) || + propValueFinal; + + return { + [cssProperty as string]: value, + }; + }; + + return handleBreakpoints(props, propValue, styleFromPropValue); + }; + return fn; +} + +const sxConfig: SxConfig = { + ...unstable_defaultSxConfig, + color: { + style: createPaletteStyle({ prop: 'color' }), + }, + bgcolor: { + style: createPaletteStyle({ prop: 'bgcolor', cssProperty: 'backgroundColor' }), + }, + backgroundColor: { + style: createPaletteStyle({ prop: 'backgroundColor', cssProperty: 'backgroundColor' }), + }, + borderColor: { + style: createPaletteStyle({ prop: 'borderColor' }), + }, + borderTopColor: { + style: createPaletteStyle({ prop: 'borderTopColor' }), + }, + borderBottomColor: { + style: createPaletteStyle({ prop: 'borderBottomColor' }), + }, + borderLeftColor: { + style: createPaletteStyle({ prop: 'borderLeftColor' }), + }, + borderRightColor: { + style: createPaletteStyle({ prop: 'borderRightColor' }), + }, +}; + +export default sxConfig; diff --git a/packages/mui-material/src/styles/CssVarsProvider.tsx b/packages/mui-material/src/styles/CssVarsProvider.tsx index f45fd6ec66bd77..3a6b6d2e0e3840 100644 --- a/packages/mui-material/src/styles/CssVarsProvider.tsx +++ b/packages/mui-material/src/styles/CssVarsProvider.tsx @@ -1,5 +1,12 @@ -import { unstable_createCssVarsProvider as createCssVarsProvider } from '@mui/system'; -import experimental_extendTheme, { SupportedColorScheme } from './experimental_extendTheme'; +import { + unstable_createCssVarsProvider as createCssVarsProvider, + SxProps, + unstable_styleFunctionSx as styleFunctionSx, +} from '@mui/system'; +import experimental_extendTheme, { + SupportedColorScheme, + CssVarsTheme, +} from './experimental_extendTheme'; import createTypography from './createTypography'; import excludeVariablesFromRoot from './excludeVariablesFromRoot'; @@ -25,6 +32,13 @@ const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = typography: createTypography(theme.palette, theme.typography), }; + newTheme.unstable_sx = function sx(props: SxProps) { + return styleFunctionSx({ + sx: props, + theme: this, + }); + }; + return newTheme; }, shouldSkipGeneratingVar, diff --git a/packages/mui-material/src/styles/createTheme.d.ts b/packages/mui-material/src/styles/createTheme.d.ts index e9b8fd92cb2084..ef8cb895b1fb14 100644 --- a/packages/mui-material/src/styles/createTheme.d.ts +++ b/packages/mui-material/src/styles/createTheme.d.ts @@ -1,4 +1,10 @@ -import { ThemeOptions as SystemThemeOptions, Theme as SystemTheme } from '@mui/system'; +import { + ThemeOptions as SystemThemeOptions, + Theme as SystemTheme, + SxProps, + CSSObject, + SxConfig, +} from '@mui/system'; import { Mixins, MixinsOptions } from './createMixins'; import { Palette, PaletteOptions } from './createPalette'; import { Typography, TypographyOptions } from './createTypography'; @@ -16,6 +22,7 @@ export interface ThemeOptions extends Omit { typography?: TypographyOptions | ((palette: Palette) => TypographyOptions); zIndex?: ZIndexOptions; unstable_strictMode?: boolean; + unstable_sxConfig?: SxConfig; } interface BaseTheme extends SystemTheme { @@ -36,6 +43,8 @@ export {}; */ export interface Theme extends BaseTheme { components?: Components; + unstable_sx: (props: SxProps) => CSSObject; + unstable_sxConfig: SxConfig; } /** diff --git a/packages/mui-material/src/styles/createTheme.js b/packages/mui-material/src/styles/createTheme.js index 18f999af86aeca..0073130a2a8070 100644 --- a/packages/mui-material/src/styles/createTheme.js +++ b/packages/mui-material/src/styles/createTheme.js @@ -1,5 +1,9 @@ import { deepmerge } from '@mui/utils'; -import { createTheme as systemCreateTheme } from '@mui/system'; +import { + createTheme as systemCreateTheme, + unstable_defaultSxConfig as defaultSxConfig, + unstable_styleFunctionSx as styleFunctionSx, +} from '@mui/system'; import MuiError from '@mui/utils/macros/MuiError.macro'; import generateUtilityClass from '../generateUtilityClass'; import createMixins from './createMixins'; @@ -104,6 +108,17 @@ function createTheme(options = {}, ...args) { }); } + muiTheme.unstable_sxConfig = { + ...defaultSxConfig, + ...other?.unstable_sxConfig, + }; + muiTheme.unstable_sx = function sx(props) { + return styleFunctionSx({ + sx: props, + theme: this, + }); + }; + return muiTheme; } diff --git a/packages/mui-material/src/styles/experimental_extendTheme.d.ts b/packages/mui-material/src/styles/experimental_extendTheme.d.ts index 3ade54bca13098..2fe728b1be0ed8 100644 --- a/packages/mui-material/src/styles/experimental_extendTheme.d.ts +++ b/packages/mui-material/src/styles/experimental_extendTheme.d.ts @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { OverridableStringUnion } from '@mui/types'; +import { SxConfig, SxProps, CSSObject } from '@mui/system'; import { ThemeOptions, Theme } from './createTheme'; import { Palette, PaletteOptions } from './createPalette'; import { Shadows } from './shadows'; @@ -401,6 +402,8 @@ export interface CssVarsTheme extends ColorSystem { shadows: Theme['shadows']; mixins: Theme['mixins']; zIndex: Theme['zIndex']; + unstable_sxConfig: SxConfig; + unstable_sx: (props: SxProps) => CSSObject; } /** diff --git a/packages/mui-material/src/styles/experimental_extendTheme.js b/packages/mui-material/src/styles/experimental_extendTheme.js index b86ac72cb0bd55..6dad1260415650 100644 --- a/packages/mui-material/src/styles/experimental_extendTheme.js +++ b/packages/mui-material/src/styles/experimental_extendTheme.js @@ -6,6 +6,8 @@ import { private_safeLighten as safeLighten, private_safeEmphasize as safeEmphasize, unstable_createGetCssVar as systemCreateGetCssVar, + unstable_defaultSxConfig as defaultSxConfig, + unstable_styleFunctionSx as styleFunctionSx, } from '@mui/system'; import createThemeWithoutVars from './createTheme'; import getOverlayAlpha from './getOverlayAlpha'; @@ -390,5 +392,16 @@ export default function extendTheme(options = {}, ...args) { theme = args.reduce((acc, argument) => deepmerge(acc, argument), theme); + theme.unstable_sxConfig = { + ...defaultSxConfig, + ...input?.unstable_sxConfig, + }; + theme.unstable_sx = function sx(props) { + return styleFunctionSx({ + sx: props, + theme: this, + }); + }; + return theme; } diff --git a/packages/mui-material/src/styles/index.d.ts b/packages/mui-material/src/styles/index.d.ts index bb2e23b2f89e26..f7d1a625424649 100644 --- a/packages/mui-material/src/styles/index.d.ts +++ b/packages/mui-material/src/styles/index.d.ts @@ -64,7 +64,6 @@ export { ColorObject, StyledEngineProvider, SxProps, - experimental_sx, } from '@mui/system'; export { default as useTheme } from './useTheme'; export { default as useThemeProps } from './useThemeProps'; diff --git a/packages/mui-material/src/styles/index.js b/packages/mui-material/src/styles/index.js index 011245f31907b7..c87fa88993319e 100644 --- a/packages/mui-material/src/styles/index.js +++ b/packages/mui-material/src/styles/index.js @@ -13,7 +13,6 @@ export { lighten, css, keyframes, - experimental_sx, } from '@mui/system'; export { default as createTheme, createMuiTheme } from './createTheme'; export { default as unstable_createMuiStrictModeTheme } from './createMuiStrictModeTheme'; diff --git a/packages/mui-material/src/styles/index.spec.ts b/packages/mui-material/src/styles/index.spec.ts index 537faa39dadef5..fc1e9f35054f10 100644 --- a/packages/mui-material/src/styles/index.spec.ts +++ b/packages/mui-material/src/styles/index.spec.ts @@ -1,25 +1,26 @@ -import { experimental_sx as sx, styled, createTheme } from '@mui/material/styles'; +import { styled, createTheme } from '@mui/material/styles'; -// Can use the experimental_sx in the styled() utility -const Test = styled('div')( - sx({ +// Can use the unstable_sx in the styled() utility +const Test = styled('div')(({ theme }) => + theme.unstable_sx({ color: 'primary.main', bgcolor: 'primary.light', m: 2, }), ); -// Can use the experimental_sx in the theme's variants +// Can use the unstable_sx in the theme's variants const customTheme = createTheme({ components: { MuiButton: { variants: [ { props: {}, - style: sx({ - m: 2, - p: 1, - }), + style: ({ theme }) => + theme.unstable_sx({ + m: 2, + p: 1, + }), }, ], }, diff --git a/packages/mui-material/src/styles/styled.spec.tsx b/packages/mui-material/src/styles/styled.spec.tsx index ecf22af2ef8d4f..5a15be60f0b7e0 100644 --- a/packages/mui-material/src/styles/styled.spec.tsx +++ b/packages/mui-material/src/styles/styled.spec.tsx @@ -1,11 +1,5 @@ import * as React from 'react'; -import { - styled, - css, - ThemeProvider, - createTheme, - experimental_sx as sx, -} from '@mui/material/styles'; +import { styled, css, ThemeProvider, createTheme } from '@mui/material/styles'; const Box = styled('div')(({ theme }) => ({ color: theme.palette.primary.main, @@ -140,13 +134,14 @@ function Button({ mark: (props) => ({ ...(props['data-index'] === 0 && {}), }), - thumb: sx({ - p: 1, - }), - track: ({ ownerState }) => [ - sx({ height: 10 }), + thumb: ({ theme }) => + theme.unstable_sx({ + p: 1, + }), + track: ({ ownerState, theme }) => [ + theme.unstable_sx({ height: 10 }), ownerState.orientation === 'vertical' && - sx({ + theme.unstable_sx({ my: 2, }), ], @@ -159,7 +154,3 @@ function Button({ Hello ; - -/** - * ============================================================ - */ diff --git a/packages/mui-system/src/borders.js b/packages/mui-system/src/borders.js index 18f3360ca81e8a..7ed3d41588fa1c 100644 --- a/packages/mui-system/src/borders.js +++ b/packages/mui-system/src/borders.js @@ -4,7 +4,7 @@ import compose from './compose'; import { createUnaryUnit, getValue } from './spacing'; import { handleBreakpoints } from './breakpoints'; -function getBorder(value) { +export function borderTransform(value) { if (typeof value !== 'number') { return value; } @@ -15,31 +15,31 @@ function getBorder(value) { export const border = style({ prop: 'border', themeKey: 'borders', - transform: getBorder, + transform: borderTransform, }); export const borderTop = style({ prop: 'borderTop', themeKey: 'borders', - transform: getBorder, + transform: borderTransform, }); export const borderRight = style({ prop: 'borderRight', themeKey: 'borders', - transform: getBorder, + transform: borderTransform, }); export const borderBottom = style({ prop: 'borderBottom', themeKey: 'borders', - transform: getBorder, + transform: borderTransform, }); export const borderLeft = style({ prop: 'borderLeft', themeKey: 'borders', - transform: getBorder, + transform: borderTransform, }); export const borderColor = style({ diff --git a/packages/mui-system/src/createBox.d.ts b/packages/mui-system/src/createBox.d.ts index cdf0123ddde8b9..707fd655467278 100644 --- a/packages/mui-system/src/createBox.d.ts +++ b/packages/mui-system/src/createBox.d.ts @@ -1,9 +1,7 @@ import Box from './Box'; -import styleFunctionSx from './styleFunctionSx'; export default function createBox(options?: { defaultTheme: object; defaultClassName?: string; generateClassName?: (componentName: string) => string; - styleFunctionSx?: typeof styleFunctionSx; }): typeof Box; diff --git a/packages/mui-system/src/createBox.js b/packages/mui-system/src/createBox.js index a47792ad6df652..080b7df08c5e91 100644 --- a/packages/mui-system/src/createBox.js +++ b/packages/mui-system/src/createBox.js @@ -1,16 +1,11 @@ import * as React from 'react'; import clsx from 'clsx'; import styled from '@mui/styled-engine'; -import defaultStyleFunctionSx, { extendSxProp } from './styleFunctionSx'; +import styleFunctionSx, { extendSxProp } from './styleFunctionSx'; import useTheme from './useTheme'; export default function createBox(options = {}) { - const { - defaultTheme, - defaultClassName = 'MuiBox-root', - generateClassName, - styleFunctionSx = defaultStyleFunctionSx, - } = options; + const { defaultTheme, defaultClassName = 'MuiBox-root', generateClassName } = options; const BoxRoot = styled('div', { shouldForwardProp: (prop) => prop !== 'theme' && prop !== 'sx' && prop !== 'as', })(styleFunctionSx); diff --git a/packages/mui-system/src/createStyled.js b/packages/mui-system/src/createStyled.js index 8f5938fad48c17..679dd95d7c3f04 100644 --- a/packages/mui-system/src/createStyled.js +++ b/packages/mui-system/src/createStyled.js @@ -3,7 +3,7 @@ import styledEngineStyled, { internal_processStyles as processStyles } from '@mu import { getDisplayName } from '@mui/utils'; import createTheme from './createTheme'; import propsToClassKey from './propsToClassKey'; -import defaultStyleFunctionSx from './styleFunctionSx'; +import styleFunctionSx from './styleFunctionSx'; function isEmpty(obj) { return Object.keys(obj).length === 0; @@ -81,7 +81,6 @@ export default function createStyled(input = {}) { defaultTheme = systemDefaultTheme, rootShouldForwardProp = shouldForwardProp, slotShouldForwardProp = shouldForwardProp, - styleFunctionSx = defaultStyleFunctionSx, } = input; const systemSx = (props) => { diff --git a/packages/mui-system/src/createStyled.test.js b/packages/mui-system/src/createStyled.test.js index 05f3c9913d8b03..833ed5b735aad9 100644 --- a/packages/mui-system/src/createStyled.test.js +++ b/packages/mui-system/src/createStyled.test.js @@ -4,7 +4,6 @@ import { spy } from 'sinon'; import { ThemeProvider, createTheme } from '@mui/material/styles'; import { createRenderer } from 'test/utils'; import createStyled from './createStyled'; -import sx from './sx'; describe('createStyled', () => { const { render } = createRenderer(); @@ -294,12 +293,13 @@ describe('createStyled', () => { components: { MuiButton: { styleOverrides: { - root: sx({ - pt: 10, - }), - icon: ({ ownerState }) => [ + root: ({ theme }) => + theme.unstable_sx({ + pt: 10, + }), + icon: ({ ownerState, theme }) => [ ownerState.color === 'primary' && - sx({ + theme.unstable_sx({ mr: 10, }), ], diff --git a/packages/mui-system/src/createTheme/createTheme.d.ts b/packages/mui-system/src/createTheme/createTheme.d.ts index f32a14211b791e..8de5e3c8d6340e 100644 --- a/packages/mui-system/src/createTheme/createTheme.d.ts +++ b/packages/mui-system/src/createTheme/createTheme.d.ts @@ -1,6 +1,8 @@ +import { CSSObject } from '@mui/styled-engine'; import { Breakpoints, BreakpointsOptions } from './createBreakpoints'; import { Shape, ShapeOptions } from './shape'; import { Spacing, SpacingOptions } from './createSpacing'; +import { SxConfig, SxProps } from '../styleFunctionSx'; export { Breakpoint, BreakpointOverrides } from './createBreakpoints'; @@ -18,6 +20,7 @@ export interface ThemeOptions { components?: Record; typography?: unknown; zIndex?: Record; + unstable_sxConfig?: SxConfig; } export interface Theme { @@ -32,6 +35,8 @@ export interface Theme { mixins?: unknown; typography?: unknown; zIndex?: unknown; + unstable_sxConfig: SxConfig; + unstable_sx: (props: SxProps) => CSSObject; } /** diff --git a/packages/mui-system/src/createTheme/createTheme.js b/packages/mui-system/src/createTheme/createTheme.js index 079979a4af01e1..2cb236a1e2ac28 100644 --- a/packages/mui-system/src/createTheme/createTheme.js +++ b/packages/mui-system/src/createTheme/createTheme.js @@ -2,6 +2,8 @@ import { deepmerge } from '@mui/utils'; import createBreakpoints from './createBreakpoints'; import shape from './shape'; import createSpacing from './createSpacing'; +import styleFunctionSx from '../styleFunctionSx/styleFunctionSx'; +import defaultSxConfig from '../styleFunctionSx/defaultSxConfig'; function createTheme(options = {}, ...args) { const { @@ -29,6 +31,17 @@ function createTheme(options = {}, ...args) { muiTheme = args.reduce((acc, argument) => deepmerge(acc, argument), muiTheme); + muiTheme.unstable_sxConfig = { + ...defaultSxConfig, + ...other?.unstable_sxConfig, + }; + muiTheme.unstable_sx = function sx(props) { + return styleFunctionSx({ + sx: props, + theme: this, + }); + }; + return muiTheme; } diff --git a/packages/mui-system/src/sx/sx.test.js b/packages/mui-system/src/createTheme/createTheme.test.js similarity index 85% rename from packages/mui-system/src/sx/sx.test.js rename to packages/mui-system/src/createTheme/createTheme.test.js index 2e14aa33e47a4e..c86c8911ccae13 100644 --- a/packages/mui-system/src/sx/sx.test.js +++ b/packages/mui-system/src/createTheme/createTheme.test.js @@ -1,9 +1,9 @@ import * as React from 'react'; import { expect } from 'chai'; import { createRenderer } from 'test/utils'; -import { experimental_sx as sx, styled, ThemeProvider } from '@mui/system'; +import { createTheme, styled, ThemeProvider } from '@mui/system'; -describe('sx', () => { +describe('createTheme', () => { const { render } = createRenderer(); const breakpointsValues = { xs: 0, @@ -15,7 +15,7 @@ describe('sx', () => { const round = (value) => Math.round(value * 1e5) / 1e5; - const theme = { + const theme = createTheme({ spacing: (val) => `${val * 10}px`, breakpoints: { keys: ['xs', 'sm', 'md', 'lg', 'xl'], @@ -52,7 +52,7 @@ describe('sx', () => { lineHeight: 1.43, }, }, - }; + }); describe('system', () => { it('resolves system when used inside styled()', function test() { @@ -60,8 +60,8 @@ describe('sx', () => { this.skip(); } - const Test = styled('div')( - sx({ + const Test = styled('div')(({ theme: t }) => + t.unstable_sx({ color: 'primary.main', bgcolor: 'secondary.main', m: 2, @@ -105,22 +105,23 @@ describe('sx', () => { variants: [ { props: {}, // all props - style: sx({ - color: 'primary.main', - bgcolor: 'secondary.main', - m: 2, - p: 1, - fontSize: 'fontSize', - maxWidth: 'sm', - }), + style: ({ theme: t }) => + t.unstable_sx({ + color: 'primary.main', + bgcolor: 'secondary.main', + m: 2, + p: 1, + fontSize: 'fontSize', + maxWidth: 'sm', + }), }, ], }, }, }; - const Test = styled('div', { name: 'MuiTest', slot: 'Root' })( - sx({ + const Test = styled('div', { name: 'MuiTest', slot: 'Root' })(({ theme: t }) => + t.unstable_sx({ color: 'primary.main', bgcolor: 'secondary.main', m: 2, @@ -154,8 +155,8 @@ describe('sx', () => { }); it('does not throw if used without ThemeProvider', function test() { - const Test = styled('div')( - sx({ + const Test = styled('div')(({ theme: t }) => + t.unstable_sx({ color: 'primary.main', bgcolor: 'secondary.main', m: 2, diff --git a/packages/mui-system/src/index.d.ts b/packages/mui-system/src/index.d.ts index a89703928d4a5a..2f2a9d6b838bdb 100644 --- a/packages/mui-system/src/index.d.ts +++ b/packages/mui-system/src/index.d.ts @@ -119,11 +119,10 @@ export { default as unstable_styleFunctionSx, unstable_createStyleFunctionSx, extendSxProp as unstable_extendSxProp, + unstable_defaultSxConfig, } from './styleFunctionSx'; export * from './styleFunctionSx'; -export { default as experimental_sx } from './sx'; - export { default as Box } from './Box'; export * from './Box'; diff --git a/packages/mui-system/src/index.js b/packages/mui-system/src/index.js index 62c21b57d11bef..a3bf2528a8cc89 100644 --- a/packages/mui-system/src/index.js +++ b/packages/mui-system/src/index.js @@ -29,8 +29,8 @@ export { default as unstable_styleFunctionSx, unstable_createStyleFunctionSx, extendSxProp as unstable_extendSxProp, + unstable_defaultSxConfig, } from './styleFunctionSx'; -export { default as experimental_sx } from './sx'; export { default as unstable_getThemeValue } from './getThemeValue'; export { default as Box } from './Box'; export { default as createBox } from './createBox'; diff --git a/packages/mui-system/src/palette.js b/packages/mui-system/src/palette.js index 8b9d7e83944ac7..10a49c9ffb3d26 100644 --- a/packages/mui-system/src/palette.js +++ b/packages/mui-system/src/palette.js @@ -1,7 +1,7 @@ import style from './style'; import compose from './compose'; -function transform(value, userValue) { +export function paletteTransform(value, userValue) { if (userValue === 'grey') { return userValue; } @@ -11,20 +11,20 @@ function transform(value, userValue) { export const color = style({ prop: 'color', themeKey: 'palette', - transform, + transform: paletteTransform, }); export const bgcolor = style({ prop: 'bgcolor', cssProperty: 'backgroundColor', themeKey: 'palette', - transform, + transform: paletteTransform, }); export const backgroundColor = style({ prop: 'backgroundColor', themeKey: 'palette', - transform, + transform: paletteTransform, }); const palette = compose(color, bgcolor, backgroundColor); diff --git a/packages/mui-system/src/sizing.js b/packages/mui-system/src/sizing.js index 57e75c9cf7bcc9..0454dfb1702845 100644 --- a/packages/mui-system/src/sizing.js +++ b/packages/mui-system/src/sizing.js @@ -2,13 +2,13 @@ import style from './style'; import compose from './compose'; import { handleBreakpoints, values as breakpointsValues } from './breakpoints'; -function transform(value) { +export function sizingTransform(value) { return value <= 1 && value !== 0 ? `${value * 100}%` : value; } export const width = style({ prop: 'width', - transform, + transform: sizingTransform, }); export const maxWidth = (props) => { @@ -17,7 +17,7 @@ export const maxWidth = (props) => { const breakpoint = props.theme?.breakpoints?.values?.[propValue] || breakpointsValues[propValue]; return { - maxWidth: breakpoint || transform(propValue), + maxWidth: breakpoint || sizingTransform(propValue), }; }; return handleBreakpoints(props, props.maxWidth, styleFromPropValue); @@ -28,34 +28,34 @@ maxWidth.filterProps = ['maxWidth']; export const minWidth = style({ prop: 'minWidth', - transform, + transform: sizingTransform, }); export const height = style({ prop: 'height', - transform, + transform: sizingTransform, }); export const maxHeight = style({ prop: 'maxHeight', - transform, + transform: sizingTransform, }); export const minHeight = style({ prop: 'minHeight', - transform, + transform: sizingTransform, }); export const sizeWidth = style({ prop: 'size', cssProperty: 'width', - transform, + transform: sizingTransform, }); export const sizeHeight = style({ prop: 'size', cssProperty: 'height', - transform, + transform: sizingTransform, }); export const boxSizing = style({ diff --git a/packages/mui-system/src/spacing.js b/packages/mui-system/src/spacing.js index 9307f5b5c808c5..f22063fdfd1229 100644 --- a/packages/mui-system/src/spacing.js +++ b/packages/mui-system/src/spacing.js @@ -44,7 +44,7 @@ const getCssProperties = memoize((prop) => { return Array.isArray(direction) ? direction.map((dir) => property + dir) : [property + direction]; }); -const marginKeys = [ +export const marginKeys = [ 'm', 'mt', 'mr', @@ -67,7 +67,7 @@ const marginKeys = [ 'marginBlockEnd', ]; -const paddingKeys = [ +export const paddingKeys = [ 'p', 'pt', 'pr', diff --git a/packages/mui-system/src/style.d.ts b/packages/mui-system/src/style.d.ts index a631aa6c57d4a0..2f004defba6e59 100644 --- a/packages/mui-system/src/style.d.ts +++ b/packages/mui-system/src/style.d.ts @@ -1,6 +1,11 @@ import { CSSObject } from '@mui/styled-engine'; import { StyleFunction } from './Box'; +export type TransformFunction = ( + cssValue: unknown, + userValue: unknown, +) => number | string | React.CSSProperties | CSSObject; + export interface StyleOptions { cssProperty?: PropKey | keyof React.CSSProperties | false; prop: PropKey; @@ -8,18 +13,15 @@ export interface StyleOptions { * dot access in `Theme` */ themeKey?: string; - transform?: ( - cssValue: unknown, - userValue: unknown, - ) => number | string | React.CSSProperties | CSSObject; + transform?: TransformFunction; } export function style( options: StyleOptions, ): StyleFunction<{ [K in PropKey]?: unknown } & { theme?: Theme }> & { filterProps: string[] }; export function getPath(obj: T, path: string | undefined, checkVars?: boolean): null | unknown; export function getStyleValue( - themeMapping: object | ((val: any) => any), - transform?: (val: any, userVal: any) => any, - propValueFinal?: any, - userValue?: any, + themeMapping: object | ((arg: any) => any), + transform: TransformFunction | null, + propValueFinal: unknown, + userValue?: unknown, ): any; diff --git a/packages/mui-system/src/style.js b/packages/mui-system/src/style.js index a07880366b47f2..b88928a526909e 100644 --- a/packages/mui-system/src/style.js +++ b/packages/mui-system/src/style.js @@ -36,7 +36,7 @@ export function getStyleValue(themeMapping, transform, propValueFinal, userValue } if (transform) { - value = transform(value, userValue); + value = transform(value, userValue, themeMapping); } return value; diff --git a/packages/mui-system/src/styleFunctionSx/defaultSxConfig.d.ts b/packages/mui-system/src/styleFunctionSx/defaultSxConfig.d.ts new file mode 100644 index 00000000000000..7b65306ec8afb5 --- /dev/null +++ b/packages/mui-system/src/styleFunctionSx/defaultSxConfig.d.ts @@ -0,0 +1,20 @@ +import { StyleFunction } from '../Box'; +import { TransformFunction } from '../style'; + +type SimpleStyleFunction = StyleFunction>>; + +export interface SxConfigRecord { + cssProperty?: keyof React.CSSProperties | false; + /** + * dot access in `Theme` + */ + themeKey?: string; + transform?: TransformFunction; + style?: SimpleStyleFunction; +} + +export type SxConfig = Record; + +declare const defaultSxConfig: SxConfig; + +export default defaultSxConfig; diff --git a/packages/mui-system/src/styleFunctionSx/defaultSxConfig.js b/packages/mui-system/src/styleFunctionSx/defaultSxConfig.js new file mode 100644 index 00000000000000..7087c424593b5d --- /dev/null +++ b/packages/mui-system/src/styleFunctionSx/defaultSxConfig.js @@ -0,0 +1,306 @@ +import { padding, margin } from '../spacing'; +import { borderRadius, borderTransform } from '../borders'; +import { gap, rowGap, columnGap } from '../cssGrid'; +import { paletteTransform } from '../palette'; +import { maxWidth, sizingTransform } from '../sizing'; + +const defaultSxConfig = { + // borders + border: { + themeKey: 'borders', + transform: borderTransform, + }, + + borderTop: { + themeKey: 'borders', + transform: borderTransform, + }, + + borderRight: { + themeKey: 'borders', + transform: borderTransform, + }, + + borderBottom: { + themeKey: 'borders', + transform: borderTransform, + }, + + borderLeft: { + themeKey: 'borders', + transform: borderTransform, + }, + + borderColor: { + themeKey: 'palette', + }, + + borderTopColor: { + themeKey: 'palette', + }, + + borderRightColor: { + themeKey: 'palette', + }, + + borderBottomColor: { + themeKey: 'palette', + }, + + borderLeftColor: { + themeKey: 'palette', + }, + + borderRadius: { + themeKey: 'shape.borderRadius', + style: borderRadius, + }, + + // palette + color: { + themeKey: 'palette', + transform: paletteTransform, + }, + bgcolor: { + themeKey: 'palette', + cssProperty: 'backgroundColor', + transform: paletteTransform, + }, + backgroundColor: { + themeKey: 'palette', + transform: paletteTransform, + }, + + // spacing + p: { + style: padding, + }, + pt: { + style: padding, + }, + pr: { + style: padding, + }, + pb: { + style: padding, + }, + pl: { + style: padding, + }, + px: { + style: padding, + }, + py: { + style: padding, + }, + padding: { + style: padding, + }, + paddingTop: { + style: padding, + }, + paddingRight: { + style: padding, + }, + paddingBottom: { + style: padding, + }, + paddingLeft: { + style: padding, + }, + paddingX: { + style: padding, + }, + paddingY: { + style: padding, + }, + paddingInline: { + style: padding, + }, + paddingInlineStart: { + style: padding, + }, + paddingInlineEnd: { + style: padding, + }, + paddingBlock: { + style: padding, + }, + paddingBlockStart: { + style: padding, + }, + paddingBlockEnd: { + style: padding, + }, + + m: { + style: margin, + }, + mt: { + style: margin, + }, + mr: { + style: margin, + }, + mb: { + style: margin, + }, + ml: { + style: margin, + }, + mx: { + style: margin, + }, + my: { + style: margin, + }, + margin: { + style: margin, + }, + marginTop: { + style: margin, + }, + marginRight: { + style: margin, + }, + marginBottom: { + style: margin, + }, + marginLeft: { + style: margin, + }, + marginX: { + style: margin, + }, + marginY: { + style: margin, + }, + marginInline: { + style: margin, + }, + marginInlineStart: { + style: margin, + }, + marginInlineEnd: { + style: margin, + }, + marginBlock: { + style: margin, + }, + marginBlockStart: { + style: margin, + }, + marginBlockEnd: { + style: margin, + }, + + // display + displayPrint: { + cssProperty: false, + transform: (value) => ({ + '@media print': { + display: value, + }, + }), + }, + display: {}, + overflow: {}, + textOverflow: {}, + visibility: {}, + whiteSpace: {}, + + // flexbox + flexBasis: {}, + flexDirection: {}, + flexWrap: {}, + justifyContent: {}, + alignItems: {}, + alignContent: {}, + order: {}, + flex: {}, + flexGrow: {}, + flexShrink: {}, + alignSelf: {}, + justifyItems: {}, + justifySelf: {}, + + // grid + gap: { + style: gap, + }, + rowGap: { + style: rowGap, + }, + columnGap: { + style: columnGap, + }, + gridColumn: {}, + gridRow: {}, + gridAutoFlow: {}, + gridAutoColumns: {}, + gridAutoRows: {}, + gridTemplateColumns: {}, + gridTemplateRows: {}, + gridTemplateAreas: {}, + gridArea: {}, + + // positions + position: {}, + zIndex: { + themeKey: 'zIndex', + }, + top: {}, + right: {}, + bottom: {}, + left: {}, + + // shadows + boxShadow: { + themeKey: 'shadows', + }, + + // sizing + width: { + transform: sizingTransform, + }, + maxWidth: { + style: maxWidth, + }, + minWidth: { + transform: sizingTransform, + }, + height: { + transform: sizingTransform, + }, + maxHeight: { + transform: sizingTransform, + }, + minHeight: { + transform: sizingTransform, + }, + boxSizing: {}, + + // typography + fontFamily: { + themeKey: 'typography', + }, + fontSize: { + themeKey: 'typography', + }, + fontStyle: { + themeKey: 'typography', + }, + fontWeight: { + themeKey: 'typography', + }, + letterSpacing: {}, + textTransform: {}, + lineHeight: {}, + textAlign: {}, + typography: { + cssProperty: false, + themeKey: 'typography', + }, +}; + +export default defaultSxConfig; diff --git a/packages/mui-system/src/styleFunctionSx/extendSxProp.js b/packages/mui-system/src/styleFunctionSx/extendSxProp.js index c01ed5046faa17..773172783f79c2 100644 --- a/packages/mui-system/src/styleFunctionSx/extendSxProp.js +++ b/packages/mui-system/src/styleFunctionSx/extendSxProp.js @@ -1,5 +1,5 @@ import { isPlainObject } from '@mui/utils'; -import { propToStyleFunction } from '../getThemeValue'; +import defaultSxConfig from './defaultSxConfig'; const splitProps = (props) => { const result = { @@ -7,8 +7,10 @@ const splitProps = (props) => { otherProps: {}, }; + const config = props?.theme?.unstable_sxConfig ?? defaultSxConfig; + Object.keys(props).forEach((prop) => { - if (propToStyleFunction[prop]) { + if (config[prop]) { result.systemProps[prop] = props[prop]; } else { result.otherProps[prop] = props[prop]; diff --git a/packages/mui-system/src/styleFunctionSx/index.d.ts b/packages/mui-system/src/styleFunctionSx/index.d.ts index 7dd890cdebd973..cfce74e073b682 100644 --- a/packages/mui-system/src/styleFunctionSx/index.d.ts +++ b/packages/mui-system/src/styleFunctionSx/index.d.ts @@ -6,4 +6,8 @@ export * from './OverwriteCSSProperties'; export * from './StandardCssProperties'; export { default as extendSxProp } from './extendSxProp'; + +export { default as unstable_defaultSxConfig } from './defaultSxConfig'; +export * from './defaultSxConfig'; + export * from './extendSxProp'; diff --git a/packages/mui-system/src/styleFunctionSx/index.js b/packages/mui-system/src/styleFunctionSx/index.js index ec677c0b0fa342..1b08c2e61dd050 100644 --- a/packages/mui-system/src/styleFunctionSx/index.js +++ b/packages/mui-system/src/styleFunctionSx/index.js @@ -1,3 +1,4 @@ export { default } from './styleFunctionSx'; export { unstable_createStyleFunctionSx } from './styleFunctionSx'; export { default as extendSxProp } from './extendSxProp'; +export { default as unstable_defaultSxConfig } from './defaultSxConfig'; diff --git a/packages/mui-system/src/styleFunctionSx/styleFunctionSx.d.ts b/packages/mui-system/src/styleFunctionSx/styleFunctionSx.d.ts index e86dcfc67e200e..929177b4cd99ee 100644 --- a/packages/mui-system/src/styleFunctionSx/styleFunctionSx.d.ts +++ b/packages/mui-system/src/styleFunctionSx/styleFunctionSx.d.ts @@ -1,4 +1,5 @@ import * as CSS from 'csstype'; +import { CSSObject } from '@mui/styled-engine'; import { StandardCSSProperties } from './StandardCssProperties'; import { AliasesCSSProperties } from './AliasesCSSProperties'; import { OverwriteCSSProperties } from './OverwriteCSSProperties'; @@ -74,7 +75,7 @@ export type SxProps = >; export interface StyleFunctionSx { - (props: object): object; + (props: object): CSSObject; filterProps?: string[]; } diff --git a/packages/mui-system/src/styleFunctionSx/styleFunctionSx.js b/packages/mui-system/src/styleFunctionSx/styleFunctionSx.js index 084b3550890a1e..c675671f7abc0b 100644 --- a/packages/mui-system/src/styleFunctionSx/styleFunctionSx.js +++ b/packages/mui-system/src/styleFunctionSx/styleFunctionSx.js @@ -1,10 +1,12 @@ +import { unstable_capitalize as capitalize } from '@mui/utils'; import merge from '../merge'; -import { styleFunctionMapping as defaultStyleFunctionMapping } from '../getThemeValue'; +import { getPath, getStyleValue as getValue } from '../style'; import { handleBreakpoints, createEmptyBreakpointObject, removeUnusedBreakpoints, } from '../breakpoints'; +import defaultSxConfig from './defaultSxConfig'; function objectsHaveSameKeys(...objects) { const allKeys = objects.reduce((keys, object) => keys.concat(Object.keys(object)), []); @@ -17,31 +19,65 @@ function callIfFn(maybeFn, arg) { } // eslint-disable-next-line @typescript-eslint/naming-convention -export function unstable_createStyleFunctionSx(styleFunctionMapping = defaultStyleFunctionMapping) { - const propToStyleFunction = Object.keys(styleFunctionMapping).reduce((acc, styleFnName) => { - styleFunctionMapping[styleFnName].filterProps.forEach((propName) => { - acc[propName] = styleFunctionMapping[styleFnName]; - }); - - return acc; - }, {}); - - function getThemeValue(prop, value, theme) { - const inputProps = { - [prop]: value, +export function unstable_createStyleFunctionSx() { + function getThemeValue(prop, val, theme, config) { + const props = { + [prop]: val, theme, }; - const styleFunction = propToStyleFunction[prop]; - return styleFunction ? styleFunction(inputProps) : { [prop]: value }; + const options = config[prop]; + + if (!options) { + return { [prop]: val }; + } + + const { cssProperty = prop, themeKey, transform, style } = options; + + if (val == null) { + return null; + } + + const themeMapping = getPath(theme, themeKey) || {}; + + if (style) { + return style(props); + } + + const styleFromPropValue = (propValueFinal) => { + let value = getValue(themeMapping, transform, propValueFinal); + + if (propValueFinal === value && typeof propValueFinal === 'string') { + // Haven't found value + value = getValue( + themeMapping, + transform, + `${prop}${propValueFinal === 'default' ? '' : capitalize(propValueFinal)}`, + propValueFinal, + ); + } + + if (cssProperty === false) { + return value; + } + + return { + [cssProperty]: value, + }; + }; + + return handleBreakpoints(props, val, styleFromPropValue); } function styleFunctionSx(props) { const { sx, theme = {} } = props || {}; + if (!sx) { return null; // Emotion & styled-components will neglect null } + const config = theme.unstable_sxConfig ?? defaultSxConfig; + /* * Receive `sxInput` as object or callback * and then recursively check keys & values to create media query object styles. @@ -67,8 +103,8 @@ export function unstable_createStyleFunctionSx(styleFunctionMapping = defaultSty const value = callIfFn(sxObject[styleKey], theme); if (value !== null && value !== undefined) { if (typeof value === 'object') { - if (propToStyleFunction[styleKey]) { - css = merge(css, getThemeValue(styleKey, value, theme)); + if (config[styleKey]) { + css = merge(css, getThemeValue(styleKey, value, theme, config)); } else { const breakpointsValues = handleBreakpoints({ theme }, value, (x) => ({ [styleKey]: x, @@ -81,7 +117,7 @@ export function unstable_createStyleFunctionSx(styleFunctionMapping = defaultSty } } } else { - css = merge(css, getThemeValue(styleKey, value, theme)); + css = merge(css, getThemeValue(styleKey, value, theme, config)); } } }); diff --git a/packages/mui-system/src/styled.test.js b/packages/mui-system/src/styled.test.js index 444aaa9bf1917c..995c4a7fabe95c 100644 --- a/packages/mui-system/src/styled.test.js +++ b/packages/mui-system/src/styled.test.js @@ -482,6 +482,47 @@ describe('styled', () => { }); }); + it('should resolve the theme.unstable_sx when used in an array styles', () => { + const TestComponent = styled('div')( + ({ theme: userTheme }) => + userTheme.unstable_sx({ + mt: 2, + }), + ({ theme: userTheme }) => + userTheme.unstable_sx({ + mb: 2, + }), + ); + const { container } = render( + + Test + , + ); + + expect(container.firstChild).toHaveComputedStyle({ + marginTop: '16px', + marginBottom: '16px', + }); + }); + + it('should resolve the theme.unstable_sx when used in an pseudo object', () => { + const TestComponent = styled('div')(({ theme: userTheme }) => ({ + '&.test-classname': userTheme.unstable_sx({ + mt: 2, + }), + })); + + const { container } = render( + + Test + , + ); + + expect(container.firstChild).toHaveComputedStyle({ + marginTop: '16px', + }); + }); + it('should respect the skipSx option', () => { const testOverridesResolver = (props, styles) => ({ ...styles.root, diff --git a/packages/mui-system/src/sx/index.d.ts b/packages/mui-system/src/sx/index.d.ts deleted file mode 100644 index 4232fe22d6b4bb..00000000000000 --- a/packages/mui-system/src/sx/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './sx'; diff --git a/packages/mui-system/src/sx/index.js b/packages/mui-system/src/sx/index.js deleted file mode 100644 index 4232fe22d6b4bb..00000000000000 --- a/packages/mui-system/src/sx/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './sx'; diff --git a/packages/mui-system/src/sx/sx.d.ts b/packages/mui-system/src/sx/sx.d.ts deleted file mode 100644 index d17929c4ee803a..00000000000000 --- a/packages/mui-system/src/sx/sx.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { CSSObject } from '@mui/styled-engine'; -import { SxProps } from '../styleFunctionSx'; - -export default function sx(styles: SxProps): CSSObject; diff --git a/packages/mui-system/src/sx/sx.js b/packages/mui-system/src/sx/sx.js deleted file mode 100644 index 770503fa5136e5..00000000000000 --- a/packages/mui-system/src/sx/sx.js +++ /dev/null @@ -1,7 +0,0 @@ -import styleFunctionSx from '../styleFunctionSx'; - -function sx(styles) { - return ({ theme }) => styleFunctionSx({ sx: styles, theme }); -} - -export default sx; diff --git a/packages/mui-system/src/sx/sx.spec.ts b/packages/mui-system/src/sx/sx.spec.ts deleted file mode 100644 index faca7d15ad7d7a..00000000000000 --- a/packages/mui-system/src/sx/sx.spec.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { experimental_sx as sx, styled } from '@mui/system'; - -// Can be used in the styled() utility -const Test = styled('div')( - sx({ - color: 'primary.main', - bgcolor: 'primary.light', - m: 2, - }), -);