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,
- }),
-);