Skip to content

Commit

Permalink
[system] Add experimental_sx utility (#29833)
Browse files Browse the repository at this point in the history
  • Loading branch information
mnajdova committed Nov 25, 2021
1 parent 037166f commit 8c0f63e
Show file tree
Hide file tree
Showing 15 changed files with 292 additions and 0 deletions.
33 changes: 33 additions & 0 deletions docs/src/pages/system/styled/UsingWithSx.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as React from 'react';
import {
styled,
createTheme,
ThemeProvider,
experimental_sx as sx,
} from '@mui/system';

const customTheme = createTheme({
palette: {
primary: {
main: '#1976d2',
contrastText: 'white',
},
},
});

const MyThemeComponent = styled('div')(
sx({
color: 'primary.contrastText',
backgroundColor: 'primary.main',
padding: 1,
borderRadius: 1,
}),
);

export default function ThemeUsage() {
return (
<ThemeProvider theme={customTheme}>
<MyThemeComponent>Styled div with theme</MyThemeComponent>
</ThemeProvider>
);
}
33 changes: 33 additions & 0 deletions docs/src/pages/system/styled/UsingWithSx.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as React from 'react';
import {
styled,
createTheme,
ThemeProvider,
experimental_sx as sx,
} from '@mui/system';

const customTheme = createTheme({
palette: {
primary: {
main: '#1976d2',
contrastText: 'white',
},
},
});

const MyThemeComponent = styled('div')(
sx({
color: 'primary.contrastText',
backgroundColor: 'primary.main',
padding: 1,
borderRadius: 1,
}),
);

export default function ThemeUsage() {
return (
<ThemeProvider theme={customTheme}>
<MyThemeComponent>Styled div with theme</MyThemeComponent>
</ThemeProvider>
);
}
3 changes: 3 additions & 0 deletions docs/src/pages/system/styled/UsingWithSx.tsx.preview
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<ThemeProvider theme={customTheme}>
<MyThemeComponent>Styled div with theme</MyThemeComponent>
</ThemeProvider>
10 changes: 10 additions & 0 deletions docs/src/pages/system/styled/styled.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,16 @@ 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`:

{{"demo": "pages/system/styled/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.

> Note: You can use `experimental_sx` outside of the `styled()` utility, too; e.g., for defining `variants` in your custom theme.
## How to use components selector API

If you've ever used the `styled()` API of either [`emotion`](https://emotion.sh/docs/styled#targeting-another-emotion-component) or [`styled-components`](https://styled-components.com/docs/advanced#referring-to-other-components), you should have been able to use components as selectors.
Expand Down
1 change: 1 addition & 0 deletions packages/mui-material/src/styles/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export {
lighten,
ColorFormat,
ColorObject,
experimental_sx,
} from '@mui/system';
export { default as useTheme } from './useTheme';
export { default as useThemeProps } from './useThemeProps';
Expand Down
1 change: 1 addition & 0 deletions packages/mui-material/src/styles/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export {
lighten,
css,
keyframes,
experimental_sx,
} from '@mui/system';
export { default as createTheme, createMuiTheme } from './createTheme';
export { default as unstable_createMuiStrictModeTheme } from './createMuiStrictModeTheme';
Expand Down
27 changes: 27 additions & 0 deletions packages/mui-material/src/styles/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { experimental_sx as sx, styled, createTheme } from '@mui/material/styles';

// Can use the experimental_sx in the styled() utility
const Test = styled('div')(
sx({
color: 'primary.main',
bgcolor: 'primary.light',
m: 2,
}),
);

// Can use the experimental_sx in the theme's variants
const customTheme = createTheme({
components: {
MuiButton: {
variants: [
{
props: {},
style: sx({
m: 2,
p: 1,
}),
},
],
},
},
});
2 changes: 2 additions & 0 deletions packages/mui-system/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ export {
} from './styleFunctionSx';
export * from './styleFunctionSx';

export { default as experimental_sx } from './sx';

export { default as Box } from './Box';
export * from './Box';

Expand Down
1 change: 1 addition & 0 deletions packages/mui-system/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export {
default as unstable_styleFunctionSx,
extendSxProp as unstable_extendSxProp,
} 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';
Expand Down
1 change: 1 addition & 0 deletions packages/mui-system/src/sx/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './sx';
1 change: 1 addition & 0 deletions packages/mui-system/src/sx/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './sx';
4 changes: 4 additions & 0 deletions packages/mui-system/src/sx/sx.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { CSSObject } from '@mui/styled-engine';
import { SxProps } from '../styleFunctionSx';

export default function sx<T extends object = {}>(styles: SxProps<T>): CSSObject;
7 changes: 7 additions & 0 deletions packages/mui-system/src/sx/sx.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import styleFunctionSx from '../styleFunctionSx';

function sx(styles) {
return ({ theme }) => styleFunctionSx({ sx: styles, theme });
}

export default sx;
10 changes: 10 additions & 0 deletions packages/mui-system/src/sx/sx.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
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,
}),
);
158 changes: 158 additions & 0 deletions packages/mui-system/src/sx/sx.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import * as React from 'react';
import { expect } from 'chai';
import { createRenderer } from 'test/utils';
import { experimental_sx as sx, styled, ThemeProvider } from '@mui/system';

describe('sx', () => {
const { render } = createRenderer();
const breakpointsValues = {
xs: 0,
sm: 600,
md: 960,
lg: 1280,
xl: 1920,
};

const round = (value) => Math.round(value * 1e5) / 1e5;

const theme = {
spacing: (val) => `${val * 10}px`,
breakpoints: {
keys: ['xs', 'sm', 'md', 'lg', 'xl'],
values: breakpointsValues,
up: (key) => {
return `@media (min-width:${breakpointsValues[key]}px)`;
},
},
unit: 'px',
palette: {
primary: {
main: 'rgb(0, 0, 255)',
},
secondary: {
main: 'rgb(0, 255, 0)',
},
},
typography: {
fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
fontWeightLight: 300,
fontSize: 14,
body1: {
fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
fontSize: '1rem',
letterSpacing: `${round(0.15 / 16)}em`,
fontWeight: 400,
lineHeight: 1.5,
},
body2: {
fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
fontSize: `${14 / 16}rem`,
letterSpacing: `${round(0.15 / 14)}em`,
fontWeight: 400,
lineHeight: 1.43,
},
},
};

describe('system', () => {
it('resolves system when used inside styled()', function test() {
if (/jsdom/.test(window.navigator.userAgent)) {
this.skip();
}

const Test = styled('div')(
sx({
color: 'primary.main',
bgcolor: 'secondary.main',
m: 2,
p: 1,
fontSize: 'fontSize',
maxWidth: 'sm',
}),
);

const { container } = render(
<ThemeProvider theme={theme}>
<Test />
</ThemeProvider>,
);

expect(container.firstChild).toHaveComputedStyle({
color: 'rgb(0, 0, 255)',
backgroundColor: 'rgb(0, 255, 0)',
margin: '20px',
padding: '10px',
fontSize: '14px',
maxWidth: '600px',
});
});

it('resolves system when used inside variants', function test() {
if (/jsdom/.test(window.navigator.userAgent)) {
this.skip();
}

const themeWithVariants = {
...theme,
components: {
MuiTest: {
variants: [
{
props: {}, // all props
style: sx({
color: 'primary.main',
bgcolor: 'secondary.main',
m: 2,
p: 1,
fontSize: 'fontSize',
maxWidth: 'sm',
}),
},
],
},
},
};

const Test = styled('div', { name: 'MuiTest', slot: 'Root' })(
sx({
color: 'primary.main',
bgcolor: 'secondary.main',
m: 2,
p: 1,
fontSize: 'fontSize',
maxWidth: 'sm',
}),
);

const { container } = render(
<ThemeProvider theme={themeWithVariants}>
<Test />
</ThemeProvider>,
);

expect(container.firstChild).toHaveComputedStyle({
color: 'rgb(0, 0, 255)',
backgroundColor: 'rgb(0, 255, 0)',
margin: '20px',
padding: '10px',
fontSize: '14px',
maxWidth: '600px',
});
});
});

it('does not throw if used without ThemeProvider', function test() {
const Test = styled('div')(
sx({
color: 'primary.main',
bgcolor: 'secondary.main',
m: 2,
p: 1,
fontSize: 'fontSize',
maxWidth: 'sm',
}),
);

expect(() => render(<Test />)).not.to.throw();
});
});

0 comments on commit 8c0f63e

Please sign in to comment.