Skip to content

Commit

Permalink
[TypeScript] Add CSS vars type augmentation for Material UI (#33211)
Browse files Browse the repository at this point in the history
  • Loading branch information
siriwatknp committed Jun 23, 2022
1 parent 76e2ef6 commit 9cfcd8c
Show file tree
Hide file tree
Showing 16 changed files with 471 additions and 187 deletions.
Expand Up @@ -27,7 +27,7 @@ The structure of this object is nearly identical to the theme structure, the onl

## Usage

`Experimental_CssVarsProvider` is a new experimental provider that attaches all generated CSS variables to the theme and puts them in React's context. Children elements under this provider will also be able to read the CSS variables from the theme.
`Experimental_CssVarsProvider` is a new experimental provider that attaches all generated CSS variables to the theme and puts them in React's context. Children elements under this provider will also be able to read the CSS variables from the `theme.vars`.

```js
import { Experimental_CssVarsProvider as CssVarsProvider } from '@mui/material/styles';
Expand All @@ -37,6 +37,8 @@ function App() {
}
```

If you use TypeScript, check out the [theme types setup](#typescript).

### Customizing components

Because the CSS variables API is an experimental feature, it is currently only supported by the `Button` component.
Expand Down Expand Up @@ -196,6 +198,26 @@ export function onRenderBody({ setPreBodyComponents }) {
}
```

### TypeScript

You need to import the theme augmentation to include `theme.vars` and other utilities related to CSS variables to the theme:

```ts
// this can be the root file of you application
import type {} from '@mui/material/themeCssVarsAugmentation';
```

Then, you will be able to access `theme.vars` in any of the styling APIs, for example the `styled`:

```ts
import { styled } from '@mui/material/styles';

const StyledComponent = styled('button')(({ theme }) => ({
// typed-safe
color: theme.vars.palette.primary.main,
}));
```

## API

### `<CssVarsProvider>` props
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-material/src/FilledInput/FilledInput.js
Expand Up @@ -98,7 +98,7 @@ const FilledInputRoot = styled(InputBaseRoot, {
'&:before': {
borderBottom: `1px solid ${
theme.vars
? `rgba(${theme.vars.palette.common.onBackgroundChannel} / ${theme.vars.opacity.inputTouchBottomLine})`
? `rgba(${theme.vars.palette.common.onBackgroundChannel} / ${theme.vars.opacity.inputUnderline})`
: bottomLineColor
}`,
left: 0,
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-material/src/Input/Input.js
Expand Up @@ -45,7 +45,7 @@ const InputRoot = styled(InputBaseRoot, {
const light = theme.palette.mode === 'light';
let bottomLineColor = light ? 'rgba(0, 0, 0, 0.42)' : 'rgba(255, 255, 255, 0.7)';
if (theme.vars) {
bottomLineColor = `rgba(${theme.vars.palette.common.onBackgroundChannel} / ${theme.vars.opacity.inputTouchBottomLine})`;
bottomLineColor = `rgba(${theme.vars.palette.common.onBackgroundChannel} / ${theme.vars.opacity.inputUnderline})`;
}
return {
position: 'relative',
Expand Down
28 changes: 0 additions & 28 deletions packages/mui-material/src/styles/CssVarsProvider.d.ts

This file was deleted.

72 changes: 72 additions & 0 deletions packages/mui-material/src/styles/CssVarsProvider.spec.tsx
@@ -0,0 +1,72 @@
import * as React from 'react';
import {
experimental_extendTheme as extendTheme,
Experimental_CssVarsProvider as CssVarsProvider,
styled,
useTheme,
Overlays,
} from '@mui/material/styles';
import type {} from '@mui/material/themeCssVarsAugmentation';

const customTheme = extendTheme({
colorSchemes: {
light: {
opacity: {
inputPlaceholder: 0.1,
inputUnderline: 0.1,
},
overlays: Array(25).fill('') as Overlays,
palette: {
AppBar: {
darkBg: '',
darkColor: '',
defaultBg: '',
},
// @ts-expect-error
mode: '',
getContrastText: () => '',
tonalOffset: 1,
},
},
dark: {
opacity: {},
palette: {},
},
},
components: {
MuiButton: {
styleOverrides: {
root: ({ theme }) => ({
color: theme.vars.palette.primary.main,
}),
},
},
},
});

const TestStyled = styled('div')(({ theme }) => ({
// test that `theme.vars` works
color: theme.vars.palette.primary.main,
// test that `theme.getColorSchemeSelector` works
[theme.getColorSchemeSelector('dark')]: {
color: theme.vars.palette.common.onBackground,
},
}));

const TestUseTheme = () => {
const theme = useTheme();
// test that `theme` from useTheme has access to CSS vars
return <div style={{ background: theme.vars.palette.common.background }}>test</div>;
};

<CssVarsProvider theme={customTheme}>
<TestStyled
sx={(theme) => ({
// test that `theme` in sx has access to CSS vars
[theme.getColorSchemeSelector('dark')]: {
border: '1px solid',
borderColor: theme.vars.palette.divider,
},
})}
/>
</CssVarsProvider>;
2 changes: 1 addition & 1 deletion packages/mui-material/src/styles/CssVarsProvider.test.js
Expand Up @@ -200,7 +200,7 @@ describe('[Material UI] CssVarsProvider', () => {
expect(screen.getByTestId('opacity').textContent).to.equal(
JSON.stringify({
inputPlaceholder: 'var(--mui-opacity-inputPlaceholder)',
inputTouchBottomLine: 'var(--mui-opacity-inputTouchBottomLine)',
inputUnderline: 'var(--mui-opacity-inputUnderline)',
switchTrackDisabled: 'var(--mui-opacity-switchTrackDisabled)',
switchTrack: 'var(--mui-opacity-switchTrack)',
}),
Expand Down
@@ -1,6 +1,9 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { unstable_createCssVarsProvider as createCssVarsProvider } from '@mui/system';
import experimental_extendTheme from './experimental_extendTheme';
import experimental_extendTheme, {
SupportedColorScheme,
CssVarsTheme,
} from './experimental_extendTheme';
import createTypography from './createTypography';

const defaultTheme = experimental_extendTheme();
Expand All @@ -9,7 +12,7 @@ const {
CssVarsProvider: Experimental_CssVarsProvider,
useColorScheme,
getInitColorSchemeScript,
} = createCssVarsProvider({
} = createCssVarsProvider<SupportedColorScheme, CssVarsTheme>({
theme: defaultTheme,
attribute: 'data-mui-color-scheme',
modeStorageKey: 'mui-mode',
Expand All @@ -28,7 +31,8 @@ const {
return newTheme;
},
shouldSkipGeneratingVar: (keys) =>
!!keys[0].match(/(typography|mixins|breakpoints|direction|transitions)/),
!!keys[0].match(/(typography|mixins|breakpoints|direction|transitions)/) ||
(keys[0] === 'palette' && !!keys[1]?.match(/(mode|contrastThreshold|tonalOffset)/)),
});

export { useColorScheme, getInitColorSchemeScript, Experimental_CssVarsProvider };
107 changes: 0 additions & 107 deletions packages/mui-material/src/styles/createPalette.d.ts
Expand Up @@ -105,113 +105,6 @@ export interface Channels {
contrastTextChannel: string;
}

export interface PaletteWithChannels {
common: CommonColors & {
background: string;
onBackground: string;
backgroundChannel: string;
onBackgroundChannel: string;
};
mode: PaletteMode;
contrastThreshold: number;
tonalOffset: PaletteTonalOffset;
primary: PaletteColor & Channels;
secondary: PaletteColor & Channels;
error: PaletteColor & Channels;
warning: PaletteColor & Channels;
info: PaletteColor & Channels;
success: PaletteColor & Channels;
grey: Color & { darkChannel: string };
text: TypeText & { primaryChannel: string; secondaryChannel: string };
divider: TypeDivider;
dividerChannel: TypeDivider;
action: TypeAction & { activeChannel: string; selectedChannel: string };
background: TypeBackground;
getContrastText: (background: string) => string;
augmentColor: (options: PaletteAugmentColorOptions) => PaletteColor;
// component tokens
Alert: {
errorColor: string;
infoColor: string;
successColor: string;
warningColor: string;
errorFilledBg: string;
infoFilledBg: string;
successFilledBg: string;
warningFilledBg: string;
errorStandardBg: string;
infoStandardBg: string;
successStandardBg: string;
warningStandardBg: string;
errorIconColor: string;
infoIconColor: string;
successIconColor: string;
warningIconColor: string;
};
AppBar: {
defaultBg: string;
darkBg: string;
darkColor: string;
};
Avatar: {
defaultBg: string;
};
Chip: {
defaultBorder: string;
defaultAvatarColor: string;
defaultIconColor: string;
};
FilledInput: {
bg: string;
hoverBg: string;
disabledBg: string;
};
LinearProgress: {
primaryBg: string;
secondaryBg: string;
errorBg: string;
infoBg: string;
successBg: string;
warningBg: string;
};
Slider: {
primaryTrack: string;
secondaryTrack: string;
errorTrack: string;
infoTrack: string;
successTrack: string;
warningTrack: string;
};
SnackbarContent: {
bg: string;
};
SpeedDialAction: {
fabHoverBg: string;
};
StepConnector: {
border: string;
};
StepContent: {
border: string;
};
Switch: {
defaultColor: string;
defaultDisabledColor: string;
primaryDisabledColor: string;
secondaryDisabledColor: string;
errorDisabledColor: string;
infoDisabledColor: string;
successDisabledColor: string;
warningDisabledColor: string;
};
TableCell: {
border: string;
};
Tooltip: {
bg: string;
};
}

export type PartialTypeObject = { [P in keyof TypeObject]?: Partial<TypeObject[P]> };

export interface PaletteOptions {
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-material/src/styles/createPalette.spec.ts
Expand Up @@ -17,5 +17,5 @@ import { createTheme, Theme } from '@mui/material/styles';
}

{
const themeCommons: Theme['palette']['common'] = common;
const themeCommons: Pick<Theme['palette']['common'], 'black' | 'white'> = common;
}

0 comments on commit 9cfcd8c

Please sign in to comment.