Skip to content

Commit

Permalink
[system] Move stylesheet generator to extendTheme (mui#41446)
Browse files Browse the repository at this point in the history
  • Loading branch information
siriwatknp authored and pluvio72 committed Mar 28, 2024
1 parent 8f5efee commit bedf79a
Show file tree
Hide file tree
Showing 24 changed files with 571 additions and 226 deletions.
32 changes: 10 additions & 22 deletions apps/pigment-css-next-app/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,32 +81,20 @@ const theme = extendTheme({
},
},
},
getSelector: function getSelector(colorScheme, css) {
if (colorScheme) {
return {
[`@media (prefers-color-scheme: ${colorScheme})`]: {
':root': css,
},
};
}
return ':root';
},
});

// TODO: Fix this from the Material UI side in a separate PR
theme.palette = theme.colorSchemes.light.palette;
theme.getColorSchemeSelector = (colorScheme) => {
return `@media (prefers-color-scheme: ${colorScheme})`;
};
const { css: rootCss } = theme.generateCssVars();
const { css: lightCss } = theme.generateCssVars('light');
const { css: darkCss } = theme.generateCssVars('dark');
theme.generateCssVars = (colorScheme) => {
if (colorScheme === 'dark') {
return {
css: darkCss,
selector: {
'@media (prefers-color-scheme: dark)': {
':root': darkCss,
},
},
};
}
if (colorScheme === 'light') {
return { css: lightCss, selector: ':root' };
}
return { css: rootCss, selector: ':root' };
};

/**
* @type {PigmentOptions}
Expand Down
35 changes: 12 additions & 23 deletions apps/pigment-css-vite-app/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,21 @@ import Pages from 'vite-plugin-pages';
import { pigment } from '@pigment-css/vite-plugin';
import { experimental_extendTheme as extendTheme } from '@mui/material/styles';

const theme = extendTheme();

// TODO: Fix this from the Material UI side in a separate PR
theme.palette = theme.colorSchemes.light.palette;
const theme = extendTheme({
getSelector: function getSelector(colorScheme, css) {
if (colorScheme) {
return {
[`@media (prefers-color-scheme: ${colorScheme})`]: {
':root': css,
},
};
}
return ':root';
},
});
theme.getColorSchemeSelector = (colorScheme) => {
return `@media (prefers-color-scheme: ${colorScheme})`;
};
const { css: rootCss } = theme.generateCssVars();
const { css: lightCss } = theme.generateCssVars('light');
const { css: darkCss } = theme.generateCssVars('dark');
theme.generateCssVars = (colorScheme) => {
if (colorScheme === 'dark') {
return {
css: darkCss,
selector: {
'@media (prefers-color-scheme: dark)': {
':root': darkCss,
},
},
};
}
if (colorScheme === 'light') {
return { css: lightCss, selector: ':root' };
}
return { css: rootCss, selector: ':root' };
};

export default defineConfig({
plugins: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const darkColorScheme = {
};

function extendTheme({ cssVarPrefix = 'system-demo' } = {}) {
const { vars: themeVars, generateCssVars } = prepareCssVars(
const { vars: themeVars, ...params } = prepareCssVars(
{
colorSchemes: {
light: lightColorScheme,
Expand All @@ -54,11 +54,11 @@ function extendTheme({ cssVarPrefix = 'system-demo' } = {}) {
// ... any other objects independent of color-scheme,
// like fontSizes, spacing etc
vars: themeVars,
generateCssVars,
palette: {
...lightColorScheme.palette,
colorScheme: 'light',
},
...params,
};

return theme;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ type Theme = {
palette: {
colorScheme: 'light' | 'dark';
} & (typeof lightColorScheme)['palette'];
vars: ReturnType<typeof prepareCssVars>['vars'];
generateCssVars: ReturnType<typeof prepareCssVars>['generateCssVars'];
};
} & ReturnType<typeof prepareCssVars>;

const lightColorScheme = {
palette: {
Expand Down Expand Up @@ -47,7 +45,7 @@ const darkColorScheme = {
};

function extendTheme({ cssVarPrefix = 'system-demo' } = {}) {
const { vars: themeVars, generateCssVars } = prepareCssVars(
const { vars: themeVars, ...params } = prepareCssVars(
{
colorSchemes: {
light: lightColorScheme,
Expand All @@ -66,11 +64,11 @@ function extendTheme({ cssVarPrefix = 'system-demo' } = {}) {
// ... any other objects independent of color-scheme,
// like fontSizes, spacing etc
vars: themeVars,
generateCssVars,
palette: {
...lightColorScheme.palette,
colorScheme: 'light',
},
...params,
};

return theme;
Expand Down
7 changes: 6 additions & 1 deletion packages/mui-joy/src/styles/defaultTheme.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ describe('defaultTheme', () => {
it('the output contains required fields', () => {
Object.keys(defaultTheme).forEach((field) => {
expect([
'attribute',
'colorSchemeSelector',
'defaultColorScheme',
'breakpoints',
'components',
'colorSchemes',
Expand All @@ -17,6 +20,7 @@ describe('defaultTheme', () => {
'palette',
'shadowRing',
'shadowChannel',
'shadowOpacity',
'getCssVar',
'spacing',
'radius',
Expand All @@ -30,7 +34,8 @@ describe('defaultTheme', () => {
'unstable_sxConfig',
'unstable_sx',
'shouldSkipGeneratingVar',
'generateCssVars',
'generateStyleSheets',
'generateThemeVars',
'applyStyles',
]).to.includes(field);
});
Expand Down
9 changes: 8 additions & 1 deletion packages/mui-joy/src/styles/extendTheme.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ describe('extendTheme', () => {
const result = extendTheme();
Object.keys(result).forEach((field) => {
expect([
'attribute',
'breakpoints',
'colorSchemeSelector',
'components',
'colorSchemes',
'defaultColorScheme',
'focus',
'fontSize',
'fontFamily',
Expand All @@ -20,6 +23,9 @@ describe('extendTheme', () => {
'spacing',
'radius',
'shadow',
'shadowRing',
'shadowChannel',
'shadowOpacity',
'zIndex',
'typography',
'variants',
Expand All @@ -30,7 +36,8 @@ describe('extendTheme', () => {
'unstable_sxConfig',
'unstable_sx',
'shouldSkipGeneratingVar',
'generateCssVars',
'generateStyleSheets',
'generateThemeVars',
'applyStyles',
]).to.includes(field);
});
Expand Down
52 changes: 45 additions & 7 deletions packages/mui-joy/src/styles/extendTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,26 @@ export interface CssVarsThemeOptions extends Partial2Level<ThemeScalesOptions> {
* value = 'var(--test)'
*/
shouldSkipGeneratingVar?: (keys: string[], value: string | number) => boolean;
/**
* If provided, it will be used to create a selector for the color scheme.
* This is useful if you want to use class or data-* attributes to apply the color scheme.
*
* The callback receives the colorScheme with the possible values of:
* - undefined: the selector for tokens that are not color scheme dependent
* - string: the selector for the color scheme
*
* @example
* // class selector
* (colorScheme) => colorScheme !== 'light' ? `.theme-${colorScheme}` : ":root"
*
* @example
* // data-* attribute selector
* (colorScheme) => colorScheme !== 'light' ? `[data-theme="${colorScheme}"`] : ":root"
*/
getSelector?: (
colorScheme: SupportedColorScheme | undefined,
css: Record<string, any>,
) => string | Record<string, any>;
}

export const createGetCssVar = (cssVarPrefix = 'joy') =>
Expand All @@ -94,6 +114,7 @@ export default function extendTheme(themeOptions?: CssVarsThemeOptions): Theme {
components: componentsInput,
variants: variantsInput,
shouldSkipGeneratingVar = defaultShouldSkipGeneratingVar,
getSelector,
...scalesInput
} = themeOptions || {};
const getCssVar = createGetCssVar(cssVarPrefix);
Expand Down Expand Up @@ -523,6 +544,7 @@ export default function extendTheme(themeOptions?: CssVarsThemeOptions): Theme {

const theme = {
colorSchemes,
defaultColorScheme: 'light',
...mergedScales,
breakpoints: createBreakpoints(breakpoints ?? {}),
components: deepmerge(
Expand Down Expand Up @@ -565,7 +587,7 @@ export default function extendTheme(themeOptions?: CssVarsThemeOptions): Theme {
cssVarPrefix,
getCssVar,
spacing: createSpacing(spacing),
} as unknown as Theme; // Need type casting due to module augmentation inside the repo
} as unknown as Theme & { attribute: string; colorSchemeSelector: string }; // Need type casting due to module augmentation inside the repo

/**
Color channels generation
Expand Down Expand Up @@ -610,15 +632,29 @@ export default function extendTheme(themeOptions?: CssVarsThemeOptions): Theme {
const parserConfig = {
prefix: cssVarPrefix,
shouldSkipGeneratingVar,
getSelector:
getSelector ||
((colorScheme) => {
if (theme.defaultColorScheme === colorScheme) {
return `${theme.colorSchemeSelector}, [${theme.attribute}="${colorScheme}"]`;
}
if (colorScheme) {
return `[${theme.attribute}="${colorScheme}"]`;
}
return theme.colorSchemeSelector;
}),
};

const { vars: themeVars, generateCssVars } = prepareCssVars<Theme, ThemeVars>(
const { vars, generateThemeVars, generateStyleSheets } = prepareCssVars<Theme, ThemeVars>(
// @ts-ignore property truDark is missing from colorSchemes
{ colorSchemes, ...mergedScales },
parserConfig,
);
theme.vars = themeVars;
theme.generateCssVars = generateCssVars;
theme.attribute = 'data-joy-color-scheme';
theme.colorSchemeSelector = ':root';
theme.vars = vars;
theme.generateThemeVars = generateThemeVars;
theme.generateStyleSheets = generateStyleSheets;
theme.unstable_sxConfig = {
...defaultSxConfig,
...themeOptions?.unstable_sxConfig,
Expand All @@ -630,9 +666,7 @@ export default function extendTheme(themeOptions?: CssVarsThemeOptions): Theme {
});
};
theme.getColorSchemeSelector = (colorScheme: SupportedColorScheme) =>
colorScheme === 'light'
? '&'
: `&[data-joy-color-scheme="${colorScheme}"], [data-joy-color-scheme="${colorScheme}"] &`;
`[${theme.attribute}="${colorScheme}"] &`;

const createVariantInput = { getCssVar, palette: theme.colorSchemes.light.palette };
theme.variants = deepmerge(
Expand All @@ -657,6 +691,10 @@ export default function extendTheme(themeOptions?: CssVarsThemeOptions): Theme {
variantsInput,
);

Object.entries(theme.colorSchemes[theme.defaultColorScheme]).forEach(([key, value]) => {
// @ts-ignore
theme[key] = value;
});
theme.palette = {
...theme.colorSchemes.light.palette,
colorScheme: 'light',
Expand Down
7 changes: 3 additions & 4 deletions packages/mui-joy/src/styles/types/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export type ThemeCssVar = OverridableStringUnion<NormalizeVars<ThemeVars>, Theme

export interface Theme extends ThemeScales, RuntimeColorSystem {
colorSchemes: Record<DefaultColorScheme | ExtendedColorScheme, ColorSystem>;
defaultColorScheme: DefaultColorScheme | ExtendedColorScheme;
focus: Focus;
typography: TypographySystem;
variants: Variants;
Expand All @@ -106,10 +107,8 @@ export interface Theme extends ThemeScales, RuntimeColorSystem {
vars: ThemeVars;
getCssVar: (field: ThemeCssVar, ...vars: ThemeCssVar[]) => string;
getColorSchemeSelector: (colorScheme: DefaultColorScheme | ExtendedColorScheme) => string;
generateCssVars: (colorScheme?: DefaultColorScheme | ExtendedColorScheme) => {
css: Record<string, string | number>;
vars: ThemeVars;
};
generateThemeVars: () => ThemeVars;
generateStyleSheets: () => Record<string, any>[];
/**
* A function to determine if the key, value should be attached as CSS Variable
* `keys` is an array that represents the object path keys.
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-material/src/styles/CssVarsProvider.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,9 @@ describe('[Material UI] CssVarsProvider', () => {
primary: 'var(--mui-palette-text-primary)',
secondary: 'var(--mui-palette-text-secondary)',
disabled: 'var(--mui-palette-text-disabled)',
icon: 'var(--mui-palette-text-icon)',
primaryChannel: 'var(--mui-palette-text-primaryChannel)',
secondaryChannel: 'var(--mui-palette-text-secondaryChannel)',
icon: 'var(--mui-palette-text-icon)',
}),
);
expect(screen.getByTestId('palette-divider').textContent).to.equal(
Expand Down
2 changes: 0 additions & 2 deletions packages/mui-material/src/styles/CssVarsProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import experimental_extendTheme, {
CssVarsTheme,
} from './experimental_extendTheme';
import createTypography from './createTypography';
import excludeVariablesFromRoot from './excludeVariablesFromRoot';
import THEME_ID from './identifier';

const defaultTheme = experimental_extendTheme();
Expand Down Expand Up @@ -40,7 +39,6 @@ const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssV

return newTheme;
},
excludeVariablesFromRoot,
});

export {
Expand Down
33 changes: 33 additions & 0 deletions packages/mui-material/src/styles/createGetSelector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import excludeVariablesFromRoot from './excludeVariablesFromRoot';

export default <
T extends {
attribute: string;
colorSchemeSelector: string;
colorSchemes?: Record<string, any>;
defaultColorScheme?: string;
cssVarPrefix?: string;
},
>(
theme: T,
) =>
(colorScheme: keyof T['colorSchemes'] | undefined, css: Record<string, any>) => {
if (theme.defaultColorScheme === colorScheme) {
if (colorScheme === 'dark') {
const excludedVariables: typeof css = {};
excludeVariablesFromRoot(theme.cssVarPrefix).forEach((cssVar) => {
excludedVariables[cssVar] = css[cssVar];
delete css[cssVar];
});
return {
[`[${theme.attribute}="${String(colorScheme)}"]`]: excludedVariables,
[theme.colorSchemeSelector!]: css,
};
}
return `${theme.colorSchemeSelector}, [${theme.attribute}="${String(colorScheme)}"]`;
}
if (colorScheme) {
return `[${theme.attribute}="${String(colorScheme)}"]`;
}
return theme.colorSchemeSelector;
};
Loading

0 comments on commit bedf79a

Please sign in to comment.