Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[system] Support callback value in styleOverrides slot #30524

Merged
merged 30 commits into from
Jan 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
14c0324
pass ownerState as props to styleOverrides callback
siriwatknp Jan 6, 2022
9eba2cf
add callback types to styleOverrides
siriwatknp Jan 6, 2022
b02f6cb
add styleOverrides callback type support for lab
siriwatknp Jan 6, 2022
13838ea
add styleOverrides callback docs
siriwatknp Jan 6, 2022
27e330f
add deprecation
siriwatknp Jan 7, 2022
1fab8ca
fix useThemeProps type
siriwatknp Jan 7, 2022
d83b76f
fix browser test
siriwatknp Jan 7, 2022
6d626e8
shut off auto exporting
siriwatknp Jan 7, 2022
943e3cb
add additional unknown props to ease customization
siriwatknp Jan 7, 2022
08bee1b
add more tests
siriwatknp Jan 11, 2022
43956fe
fix typo
siriwatknp Jan 11, 2022
1925f48
Merge branch 'master' of https://github.com/mui-org/material-ui into …
siriwatknp Jan 12, 2022
19cb837
Merge branch 'master' of https://github.com/mui-org/material-ui into …
siriwatknp Jan 13, 2022
de46f74
use ownerState
siriwatknp Jan 13, 2022
052dcf2
remove unnecessary comment
siriwatknp Jan 13, 2022
925abcf
Apply suggestions from code review
siriwatknp Jan 13, 2022
296327b
add module augmentation test
siriwatknp Jan 14, 2022
14502fa
add comments
siriwatknp Jan 14, 2022
dafe8d7
fix lint
siriwatknp Jan 14, 2022
8d7fc2e
Merge branch 'master' of https://github.com/mui-org/material-ui into …
siriwatknp Jan 16, 2022
d8bf232
support styleOverridesCallback for Joy
siriwatknp Jan 16, 2022
03db4af
add sx support test
siriwatknp Jan 16, 2022
b018e67
add using with sx docs
siriwatknp Jan 16, 2022
b85903e
call if styleOverrides is a function in nested class
siriwatknp Jan 16, 2022
90701bb
yarn docs formatted
siriwatknp Jan 16, 2022
373e566
remove non-slot from Joy components
siriwatknp Jan 17, 2022
5b1721a
remove test variant from Joy component tests
siriwatknp Jan 17, 2022
cf9227a
Revert "call if styleOverrides is a function in nested class"
siriwatknp Jan 17, 2022
4791add
make nested class works with callback
siriwatknp Jan 17, 2022
2122360
Update docs/src/pages/customization/theme-components/theme-components.md
siriwatknp Jan 17, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import * as React from 'react';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Slider, { sliderClasses } from '@mui/material/Slider';

const finalTheme = createTheme({
components: {
MuiSlider: {
styleOverrides: {
valueLabel: ({ ownerState, theme }) => ({
...(ownerState.orientation === 'vertical' && {
backgroundColor: 'transparent',
color: theme.palette.grey[500],
fontWeight: 700,
padding: 0,
left: '2rem',
}),
[`&.${sliderClasses.valueLabelOpen}`]: {
transform: 'none',
top: 'initial',
},
}),
},
},
},
});

function valuetext(value) {
return `${value}°C`;
}

export default function GlobalThemeOverride() {
return (
<ThemeProvider theme={finalTheme}>
<Box sx={{ height: 180, display: 'inline-block' }}>
<Slider
getAriaLabel={() => 'Temperature'}
orientation="vertical"
getAriaValueText={valuetext}
defaultValue={[25, 50]}
marks={[
{ value: 0 },
{ value: 25 },
{ value: 50 },
{ value: 75 },
{ value: 100 },
]}
valueLabelFormat={valuetext}
valueLabelDisplay="on"
/>
</Box>
</ThemeProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import * as React from 'react';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Slider, { sliderClasses } from '@mui/material/Slider';

const finalTheme = createTheme({
components: {
MuiSlider: {
styleOverrides: {
valueLabel: ({ ownerState, theme }) => ({
...(ownerState.orientation === 'vertical' && {
backgroundColor: 'transparent',
color: theme.palette.grey[500],
fontWeight: 700,
padding: 0,
left: '2rem',
}),
[`&.${sliderClasses.valueLabelOpen}`]: {
transform: 'none',
top: 'initial',
},
}),
},
},
},
});

function valuetext(value: number) {
return `${value}°C`;
}

export default function GlobalThemeOverride() {
return (
<ThemeProvider theme={finalTheme}>
<Box sx={{ height: 180, display: 'inline-block' }}>
<Slider
getAriaLabel={() => 'Temperature'}
orientation="vertical"
getAriaValueText={valuetext}
defaultValue={[25, 50]}
marks={[
{ value: 0 },
{ value: 25 },
{ value: 50 },
{ value: 75 },
{ value: 100 },
]}
valueLabelFormat={valuetext}
valueLabelDisplay="on"
/>
</Box>
</ThemeProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import * as React from 'react';
import {
ThemeProvider,
createTheme,
experimental_sx as sx,
} from '@mui/material/styles';
import Chip from '@mui/material/Chip';
import Check from '@mui/icons-material/Check';

const finalTheme = createTheme({
components: {
MuiChip: {
styleOverrides: {
root: sx({
// https://mui.com/system/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',
}),
},
},
},
});

export default function GlobalThemeOverride() {
return (
<ThemeProvider theme={finalTheme}>
<Chip
color="success"
label={
<span>
<b>Status:</b> Completed
</span>
}
icon={<Check fontSize="small" />}
/>
</ThemeProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import * as React from 'react';
import {
ThemeProvider,
createTheme,
experimental_sx as sx,
} from '@mui/material/styles';
import Chip from '@mui/material/Chip';
import Check from '@mui/icons-material/Check';

const finalTheme = createTheme({
components: {
MuiChip: {
styleOverrides: {
root: sx({
// https://mui.com/system/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',
}),
},
},
},
});

export default function GlobalThemeOverride() {
return (
<ThemeProvider theme={finalTheme}>
<Chip
color="success"
label={
<span>
<b>Status:</b> Completed
</span>
}
icon={<Check fontSize="small" />}
/>
</ThemeProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<ThemeProvider theme={finalTheme}>
<Chip
color="success"
label={
<span>
<b>Status:</b> Completed
</span>
}
icon={<Check fontSize="small" />}
/>
</ThemeProvider>
59 changes: 48 additions & 11 deletions docs/src/pages/customization/theme-components/theme-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,29 @@

<p class="description">The theme's components key allows you to customize a component without wrapping it in another component. You can change the styles, the default props, and more.</p>

## Default props
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved Default props up


You can change the default of every prop of a MUI component.
A `defaultProps` key is exposed in the theme's `components` key for this use case.

```js
const theme = createTheme({
components: {
// Name of the component
MuiButtonBase: {
defaultProps: {
// The props to change the default for.
disableRipple: true, // No more ripple!
},
},
},
});
```

{{"demo": "pages/customization/theme-components/DefaultProps.js"}}

To override lab component styles with TypeScript, check [this page](/components/about-the-lab/#typescript).

## Global style overrides

You can use the theme's `styleOverrides` key to potentially change every single style injected by MUI into the DOM.
Expand Down Expand Up @@ -29,31 +52,45 @@ The list of each component's classes is documented under the **CSS** section of

To override a lab component's styles with TypeScript, check [this section of the documentation](/components/about-the-lab/#typescript).

## Default props
### Overrides based on props

You can change the default of every prop of a MUI component.
A `defaultProps` key is exposed in the theme's `components` key for this use case.
You can pass a callback as a value in each slot of the component's `styleOverrides` to apply styles based on props.

The `ownerState` prop is a combination of public props that you pass to the component + internal state of the component.

```js
const theme = createTheme({
const finalTheme = createTheme({
components: {
// Name of the component
MuiButtonBase: {
defaultProps: {
// The props to change the default for.
disableRipple: true, // No more ripple!
MuiSlider: {
styleOverrides: {
valueLabel: ({ ownerState, theme }) => ({
...(ownerState.orientation === 'vertical' && {
backgroundColor: 'transparent',
color: theme.palette.grey[500],
}),
}),
},
},
},
});
```

{{"demo": "pages/customization/theme-components/DefaultProps.js"}}
{{"demo": "pages/customization/theme-components/GlobalThemeOverrideCallback.js"}}

To override lab component styles with TypeScript, check [this page](/components/about-the-lab/#typescript).
### Using `sx` (experimental) syntax

If you are not familiar `sx`, first check out [the concept](/system/the-sx-prop) and [the difference with the `styled`](/system/styled/#difference-with-the-sx-prop).

`sx` is also compatible with theme style overrides if you prefer the shorthand notation.

{{"demo": "pages/customization/theme-components/GlobalThemeOverrideSx.js"}}

## Adding new component variants

> ⚠️ This API has been **deprecated** and will likely be removed in the next major release. If you want to apply styles based on props, take a look at [Overrides based on props](#overrides-based-on-props) instead.
Copy link
Member

@oliviertassinari oliviertassinari Jan 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I landed here after seeing the notion of deprecation in #30668.

We might be jumping one step head too quickly on this one. I will add a new comment on why we added the "variant" API in the first place, it's true purpose doesn't seem covered in #30412 or in #28107 (from my perspective on why we added it in the first place, it wasn't because of JSS, when we added it we were already adding emotion from what I recall, we knew this PR was going to be possible).

Edit: done #30412 (comment)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I will remove the deprecation section for now and update the #30412.

>
> If you are interested to see the reasoning behind this change, check out [issue #30412](https://github.com/mui-org/material-ui/issues/30412)
You can use the `variants` key in the theme's `components` section to add new variants to MUI components. These new variants can specify what styles the component should have when specific props are applied.

The definitions are specified in an array, under the component's name. For each of them a CSS class is added to the HTML `<head>`. The order is important, so make sure that the styles that should win are specified last.
Expand Down
1 change: 0 additions & 1 deletion packages/mui-joy/src/Button/Button.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ describe('Joy <Button />', () => {
refInstanceof: window.HTMLButtonElement,
muiName: 'MuiButton',
testVariantProps: { variant: 'contained', fullWidth: true },
testStateOverrides: { prop: 'size', value: 'sm', styleKey: 'sizeSm' },
skip: ['propsSpread', 'componentsProp', 'classesRoot'],
}));

Expand Down
12 changes: 1 addition & 11 deletions packages/mui-joy/src/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,7 @@ const useUtilityClasses = (ownerState: ButtonProps & { focusVisible: boolean })
const ButtonRoot = styled('button', {
name: 'MuiButton',
slot: 'Root',
overridesResolver: (props, styles) => {
const { ownerState } = props;

return [
styles.root,
styles[`variant${capitalize(ownerState.variant)}`],
styles[`color${capitalize(ownerState.color)}`],
ownerState.size && styles[`size${capitalize(ownerState.size)}`],
ownerState.fullWidth && styles.fullWidth,
];
},
overridesResolver: (props, styles) => styles.root,
})<{ ownerState: ButtonProps }>(({ theme, ownerState }) => {
return [
{
Expand Down
2 changes: 2 additions & 0 deletions packages/mui-joy/src/Button/ButtonProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {
import { SxProps } from '../styles/defaultTheme';
import { ColorPaletteProp, VariantProp } from '../styles/types';

export type ButtonSlot = 'root';

export interface ButtonPropsVariantOverrides {}

export interface ButtonPropsColorOverrides {}
Expand Down
10 changes: 1 addition & 9 deletions packages/mui-joy/src/SvgIcon/SvgIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,7 @@ const useUtilityClasses = (ownerState: SvgIconProps) => {
const SvgIconRoot = styled('svg', {
name: 'MuiSvgIcon',
slot: 'Root',
overridesResolver: (props, styles) => {
const { ownerState } = props;

return [
styles.root,
styles[`color${capitalize(ownerState.color)}`],
styles[`fontSize${capitalize(ownerState.fontSize)}`],
];
},
overridesResolver: (props, styles) => styles.root,
})<{ ownerState: SvgIconProps }>(({ theme, ownerState }) => {
return [
{
Expand Down
2 changes: 2 additions & 0 deletions packages/mui-joy/src/SvgIcon/SvgIconProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { SxProps } from '../styles/defaultTheme';
import { ColorPaletteProp, FontSize } from '../styles/types';
import { SvgIconClasses } from './svgIconClasses';

export type SvgIconSlot = 'root';

export interface SvgIconPropsSizeOverrides {}

export interface SvgIconPropsColorOverrides {}
Expand Down
1 change: 1 addition & 0 deletions packages/mui-joy/src/Switch/Switch.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ describe('<Switch />', () => {
testDeepOverrides: [
{ slotName: 'track', slotClassName: classes.track },
{ slotName: 'input', slotClassName: classes.input },
{ slotName: 'thumb', slotClassName: classes.thumb },
],
refInstanceof: window.HTMLSpanElement,
skip: [
Expand Down
2 changes: 2 additions & 0 deletions packages/mui-joy/src/Switch/SwitchProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { SwitchClasses } from './switchClasses';
import { SxProps } from '../styles/defaultTheme';
import { ColorPaletteProp } from '../styles/types';

export type SwitchSlot = 'root' | 'input' | 'track' | 'thumb';

export interface SwitchPropsColorOverrides {}

export interface SwitchPropsSizeOverrides {}
Expand Down
1 change: 0 additions & 1 deletion packages/mui-joy/src/Typography/Typography.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ describe('<Typography />', () => {
render,
refInstanceof: window.HTMLParagraphElement,
muiName: 'MuiTypography',
testStateOverrides: { prop: 'level', value: 'h2', styleKey: 'h2' },
skip: ['componentsProp', 'classesRoot', 'themeVariants'],
}));

Expand Down
Loading