Skip to content

Commit

Permalink
[CssVarsProvider][Material UI] Exclude dark mode variables from `:roo…
Browse files Browse the repository at this point in the history
…t` stylesheet (#34131)
  • Loading branch information
siriwatknp committed Sep 22, 2022
1 parent 29fd59e commit 0ec69e7
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 1 deletion.
2 changes: 2 additions & 0 deletions packages/mui-material/src/styles/CssVarsProvider.tsx
@@ -1,6 +1,7 @@
import { unstable_createCssVarsProvider as createCssVarsProvider } from '@mui/system';
import experimental_extendTheme, { SupportedColorScheme } from './experimental_extendTheme';
import createTypography from './createTypography';
import excludeVariablesFromRoot from './excludeVariablesFromRoot';

const shouldSkipGeneratingVar = (keys: string[]) =>
!!keys[0].match(/(typography|mixins|breakpoints|direction|transitions)/) ||
Expand All @@ -27,6 +28,7 @@ const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } =
return newTheme;
},
shouldSkipGeneratingVar,
excludeVariablesFromRoot,
});

export {
Expand Down
41 changes: 41 additions & 0 deletions packages/mui-material/src/styles/excludeVariablesFromRoot.test.ts
@@ -0,0 +1,41 @@
import { expect } from 'chai';
import excludeVariablesFromRoot from './excludeVariablesFromRoot';

describe('excludeVariablesFromRoot', () => {
it('should return true', () => {
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-1`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-2`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-3`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-4`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-5`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-6`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-7`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-8`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-9`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-10`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-11`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-12`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-13`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-14`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-15`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-16`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-17`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-18`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-19`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-20`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-21`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-22`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-23`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-overlays-24`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-palette-AppBar-darkBg`)).to.equal(true);
expect(excludeVariablesFromRoot('mui').includes(`--mui-palette-AppBar-darkColor`)).to.equal(
true,
);
});

it('should return true for custom prefix', () => {
expect(excludeVariablesFromRoot('').includes(`--overlays-1`)).to.equal(true);
expect(excludeVariablesFromRoot('').includes(`--palette-AppBar-darkBg`)).to.equal(true);
expect(excludeVariablesFromRoot('').includes(`--palette-AppBar-darkColor`)).to.equal(true);
});
});
12 changes: 12 additions & 0 deletions packages/mui-material/src/styles/excludeVariablesFromRoot.ts
@@ -0,0 +1,12 @@
/**
* @internal These variables should not appear in the :root stylesheet when the `defaultMode="dark"`
*/
const excludeVariablesFromRoot = (cssVarPrefix: string) => [
...[...Array(24)].map(
(_, index) => `--${cssVarPrefix ? `${cssVarPrefix}-` : ''}overlays-${index + 1}`,
),
`--${cssVarPrefix ? `${cssVarPrefix}-` : ''}palette-AppBar-darkBg`,
`--${cssVarPrefix ? `${cssVarPrefix}-` : ''}palette-AppBar-darkColor`,
];

export default excludeVariablesFromRoot;
Expand Up @@ -247,6 +247,7 @@ describe('experimental_extendTheme', () => {
expect(theme.colorSchemes.light.overlays).to.have.length(0);
expect(theme.colorSchemes.dark.overlays).to.have.length(25);

expect(theme.colorSchemes.dark.overlays[0]).to.equal(undefined);
expect(theme.colorSchemes.dark.overlays[24]).to.equal(
'linear-gradient(rgba(255 255 255 / 0.16), rgba(255 255 255 / 0.16))',
);
Expand Down
8 changes: 8 additions & 0 deletions packages/mui-system/src/cssVars/createCssVarsProvider.d.ts
Expand Up @@ -124,6 +124,14 @@ export default function createCssVarsProvider<ColorScheme extends string>(
* variants from those tokens.
*/
resolveTheme?: (theme: any) => any; // the type is any because it depends on the design system.
/**
* @internal
* A function that returns a list of variables that will be excluded from the `colorSchemeSelector` (:root by default)
*
* Some variables are intended to be used in a specific color scheme only. They should be excluded when the default mode is set to the color scheme.
* This is introduced to fix https://github.com/mui/material-ui/issues/34084
*/
excludeVariablesFromRoot?: (cssVarPrefix: string) => string[];
},
): CreateCssVarsProviderResult<ColorScheme>;

Expand Down
9 changes: 9 additions & 0 deletions packages/mui-system/src/cssVars/createCssVarsProvider.js
Expand Up @@ -27,6 +27,7 @@ export default function createCssVarsProvider(options) {
enableColorScheme: designSystemEnableColorScheme = true,
shouldSkipGeneratingVar: designSystemShouldSkipGeneratingVar,
resolveTheme,
excludeVariablesFromRoot,
} = options;

if (
Expand Down Expand Up @@ -156,6 +157,14 @@ export default function createCssVarsProvider(options) {
return defaultColorScheme.light;
})();
if (key === resolvedDefaultColorScheme) {
if (excludeVariablesFromRoot) {
const excludedVariables = {};
excludeVariablesFromRoot(cssVarPrefix).forEach((cssVar) => {
excludedVariables[cssVar] = css[cssVar];
delete css[cssVar];
});
defaultColorSchemeStyleSheet[`[${attribute}="${key}"]`] = excludedVariables;
}
defaultColorSchemeStyleSheet[`${colorSchemeSelector}, [${attribute}="${key}"]`] = css;
} else {
otherColorSchemesStyleSheet[
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-system/src/cssVars/cssVarsParser.ts
Expand Up @@ -128,7 +128,7 @@ export default function cssVarsParser<T extends Record<string, any>>(
},
) {
const { prefix, shouldSkipGeneratingVar } = options || {};
const css = {} as NestedRecord<string>;
const css = {} as Record<string, string | number>;
const vars = {} as NestedRecord<string>;
const parsedTheme = {} as T;

Expand Down
33 changes: 33 additions & 0 deletions test/regressions/fixtures/CssVarsProvider/MaterialUIDefaultDark.js
@@ -0,0 +1,33 @@
import * as React from 'react';
import { Experimental_CssVarsProvider as CssVarsProvider } from '@mui/material/styles';
import AppBar from '@mui/material/AppBar';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
import Toolbar from '@mui/material/Toolbar';

export default function MaterialUIDefaultDark() {
return (
<CssVarsProvider defaultMode="dark">
<Box
sx={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(256px, 1fr))',
gridAutoRows: 'minmax(160px, auto)',
gap: 2,
'& > div': {
placeSelf: 'center',
},
}}
>
<AppBar position="static" color="secondary" elevation={12}>
<Toolbar>The color should be `palette.AppBar.darkBg`</Toolbar>
</AppBar>
<Box sx={{ bgcolor: '#121212', p: 4 }}>
<Paper elevation={24} sx={{ bgcolor: '#121212', p: 2, color: '#fff' }}>
You should see overlay.
</Paper>
</Box>
</Box>
</CssVarsProvider>
);
}
@@ -0,0 +1,45 @@
import * as React from 'react';
import {
Experimental_CssVarsProvider as CssVarsProvider,
useColorScheme,
} from '@mui/material/styles';
import AppBar from '@mui/material/AppBar';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
import Toolbar from '@mui/material/Toolbar';

const LightMode = () => {
const { setMode } = useColorScheme();
React.useEffect(() => {
setMode('light');
}, [setMode]);
return null;
};

export default function MaterialUIDefaultDark() {
return (
<CssVarsProvider defaultMode="dark">
<LightMode />
<Box
sx={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(256px, 1fr))',
gridAutoRows: 'minmax(160px, auto)',
gap: 2,
'& > div': {
placeSelf: 'center',
},
}}
>
<AppBar position="static" color="secondary" elevation={12}>
<Toolbar>The color should be secondary.</Toolbar>
</AppBar>
<Box sx={{ bgcolor: '#121212', p: 4 }}>
<Paper elevation={24} sx={{ bgcolor: '#121212', p: 2, color: '#fff' }}>
You <em>should not</em> see overlay.
</Paper>
</Box>
</Box>
</CssVarsProvider>
);
}

0 comments on commit 0ec69e7

Please sign in to comment.