Skip to content

Commit

Permalink
[core] Generate vars in extendTheme (#35739)
Browse files Browse the repository at this point in the history
  • Loading branch information
mnajdova committed Mar 3, 2023
1 parent b1b9ef7 commit 1eddf71
Show file tree
Hide file tree
Showing 39 changed files with 1,089 additions and 806 deletions.
23 changes: 16 additions & 7 deletions packages/mui-joy/src/Box/Box.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,28 @@ describe('Joy <Box />', () => {
refInstanceof: window.HTMLDivElement,
}));

it('respects theme from context', () => {
const { container } = render(
<ThemeProvider
theme={{
it('respects theme from context', function test() {
const isJSDOM = /jsdom/.test(window.navigator.userAgent);

if (isJSDOM) {
this.skip();
}

const theme = extendTheme({
colorSchemes: {
light: {
palette: {
primary: {
main: 'rgb(255, 0, 0)',
},
},
}}
>
},
},
});
const { container } = render(
<CssVarsProvider theme={theme}>
<Box color="primary.main" />
</ThemeProvider>,
</CssVarsProvider>,
);

expect(container.firstChild).toHaveComputedStyle({
Expand Down
2 changes: 2 additions & 0 deletions packages/mui-joy/src/CssBaseline/CssBaseline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import { GlobalStyles } from '@mui/system';
import { Theme, DefaultColorScheme, ColorSystem } from '../styles/types';
import { Components } from '../styles/components';
import defaultTheme from '../styles/defaultTheme';
import { CssBaselineProps } from './CssBaselineProps';

/**
Expand Down Expand Up @@ -71,6 +72,7 @@ function CssBaseline(props: CssBaselineProps) {
...colorSchemeStyles,
};
}}
defaultTheme={defaultTheme}
/>
{children}
</React.Fragment>
Expand Down
9 changes: 8 additions & 1 deletion packages/mui-joy/src/styles/ColorInversion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,14 @@ interface ColorInversionProviderProps {
export function ColorInversionProvider({ children, variant }: ColorInversionProviderProps) {
const theme = useSystemTheme(defaultTheme);
return (
<ColorInversion.Provider value={variant ? theme.colorInversionConfig[variant] : undefined}>
<ColorInversion.Provider
value={
variant
? // `theme` could come from other emotion/styled-components context.
(theme.colorInversionConfig ?? defaultTheme.colorInversionConfig)[variant]
: undefined
}
>
{children}
</ColorInversion.Provider>
);
Expand Down
14 changes: 4 additions & 10 deletions packages/mui-joy/src/styles/CssVarsProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
import { deepmerge } from '@mui/utils';
import { unstable_createCssVarsProvider as createCssVarsProvider } from '@mui/system';
import extendTheme, { CssVarsThemeOptions } from './extendTheme';
import defaultTheme from './defaultTheme';
import { CssVarsThemeOptions } from './extendTheme';
import { createSoftInversion, createSolidInversion } from './variantUtils';
import type { Theme, DefaultColorScheme, ExtendedColorScheme } from './types';

const shouldSkipGeneratingVar = (keys: string[]) =>
!!keys[0].match(/^(typography|variants|breakpoints|colorInversion|colorInversionConfig)$/) ||
!!keys[0].match(/sxConfig$/) || // ends with sxConfig
(keys[0] === 'palette' && !!keys[1]?.match(/^(mode)$/)) ||
(keys[0] === 'focus' && keys[1] !== 'thickness');

const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssVarsProvider<
DefaultColorScheme | ExtendedColorScheme
>({
theme: extendTheme(),
theme: defaultTheme,
attribute: 'data-joy-color-scheme',
modeStorageKey: 'joy-mode',
colorSchemeStorageKey: 'joy-color-scheme',
Expand All @@ -35,7 +30,6 @@ const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssV
);
return mergedTheme;
},
shouldSkipGeneratingVar,
});

export { CssVarsProvider, useColorScheme, getInitColorSchemeScript, shouldSkipGeneratingVar };
export { CssVarsProvider, useColorScheme, getInitColorSchemeScript };
2 changes: 1 addition & 1 deletion packages/mui-joy/src/styles/ThemeProvider.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ describe('[Joy] ThemeProvider', () => {
</ThemeProvider>,
);

expect(container.firstChild?.textContent).to.equal('100rem');
expect(container.firstChild?.textContent).to.equal('var(--joy-fontSize-md, 100rem)');
});
});
5 changes: 3 additions & 2 deletions packages/mui-joy/src/styles/ThemeProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from 'react';
import { ThemeProvider as SystemThemeProvider, useTheme as useSystemTheme } from '@mui/system';
import defaultTheme, { getThemeWithVars } from './defaultTheme';
import defaultTheme from './defaultTheme';
import extendTheme from './extendTheme';
import type { CssVarsThemeOptions } from './extendTheme';

export const useTheme = () => {
Expand All @@ -14,7 +15,7 @@ export default function ThemeProvider({
theme?: CssVarsThemeOptions;
}>) {
return (
<SystemThemeProvider theme={themeInput ? getThemeWithVars(themeInput) : defaultTheme}>
<SystemThemeProvider theme={themeInput ? extendTheme(themeInput) : defaultTheme}>
{children}
</SystemThemeProvider>
);
Expand Down
27 changes: 6 additions & 21 deletions packages/mui-joy/src/styles/defaultTheme.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { expect } from 'chai';
import { getThemeWithVars } from './defaultTheme';
import defaultTheme from './defaultTheme';

describe('defaultTheme', () => {
it('the output contains required fields', () => {
const result = getThemeWithVars();
Object.keys(result).forEach((field) => {
Object.keys(defaultTheme).forEach((field) => {
expect([
'breakpoints',
'components',
Expand Down Expand Up @@ -32,28 +31,14 @@ describe('defaultTheme', () => {
'getColorSchemeSelector',
'unstable_sxConfig',
'unstable_sx',
'shouldSkipGeneratingVar',
'generateCssVars',
]).to.includes(field);
});
});

it('the generated palette has correct colorChannel', () => {
const result = getThemeWithVars({
colorSchemes: {
light: {
palette: {
primary: {
mainChannel: '12 12 12',
},
},
},
},
});
expect(result.palette.primary.mainChannel).to.equal('12 12 12');
});

it('the generated palette always has mode and color scheme as `light`', () => {
const result = getThemeWithVars();
expect(result.palette.mode).to.equal('light');
expect(result.palette.colorScheme).to.equal('light');
expect(defaultTheme.palette.mode).to.equal('light');
expect(defaultTheme.palette.colorScheme).to.equal('light');
});
});
79 changes: 1 addition & 78 deletions packages/mui-joy/src/styles/defaultTheme.ts
Original file line number Diff line number Diff line change
@@ -1,82 +1,5 @@
import { deepmerge } from '@mui/utils';
import extendTheme from './extendTheme';
import type { CssVarsThemeOptions, ColorSystemOptions } from './extendTheme';
import type { Theme, RuntimeColorSystem } from './types';
import { createSoftInversion, createSolidInversion } from './variantUtils';

export const getThemeWithVars = (
themeInput?: Omit<CssVarsThemeOptions, 'colorSchemes'> & ColorSystemOptions,
) => {
const {
colorSchemes,
focus,
fontFamily,
fontSize,
fontWeight,
letterSpacing,
lineHeight,
radius,
shadow,
zIndex,
palette: paletteInput,
colorInversion: colorInversionInput,
...restTheme
} = extendTheme(themeInput);
const colorSchemePalette = deepmerge(
colorSchemes[paletteInput?.colorScheme || 'light'].palette,
paletteInput,
);
const {
mode = 'light',
colorScheme = 'light',
...palette
} = colorSchemePalette as RuntimeColorSystem['palette'];

const theme = {
focus,
fontFamily,
fontSize,
fontWeight,
letterSpacing,
lineHeight,
radius,
shadow,
zIndex,
...restTheme,
colorSchemes: {
...colorSchemes,
[colorScheme]: palette,
},
palette: {
...palette,
mode,
colorScheme,
},
vars: {
focus,
fontFamily,
fontSize,
fontWeight,
letterSpacing,
lineHeight,
radius,
shadow,
palette,
zIndex,
},
getColorSchemeSelector: () => '&',
} as unknown as Theme;

theme.colorInversion = deepmerge(
{
soft: createSoftInversion(theme),
solid: createSolidInversion(theme),
},
colorInversionInput,
);
return theme;
};

const defaultTheme = getThemeWithVars();
const defaultTheme = extendTheme();

export default defaultTheme;
40 changes: 37 additions & 3 deletions packages/mui-joy/src/styles/extendTheme.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,61 @@ describe('extendTheme', () => {
'colorInversionConfig',
'variants',
'cssVarPrefix',
'palette',
'vars',
'getColorSchemeSelector',
'colorInversion',
'unstable_sxConfig',
'unstable_sx',
'shouldSkipGeneratingVar',
'generateCssVars',
]).to.includes(field);
});
});

it('should have the vars object', () => {
const theme = extendTheme();
const keys = [
'radius',
'shadow',
'focus',
'fontFamily',
'fontSize',
'fontWeight',
'lineHeight',
'letterSpacing',
'palette',
'shadowRing',
'shadowChannel',
];

Object.keys(keys).forEach((key) => {
expect(theme[key]).to.deep.equal(theme.vars[key]);
});
});

it('should have joy default css var prefix', () => {
const theme = extendTheme();
expect(theme.cssVarPrefix).to.equal('joy');
expect(theme.typography.body1.fontSize).to.equal('var(--joy-fontSize-md)');
expect(theme.typography.body1.fontSize).to.equal('var(--joy-fontSize-md, 1rem)');
});

it('should have custom css var prefix', () => {
const theme = extendTheme({ cssVarPrefix: 'foo' });
expect(theme.cssVarPrefix).to.equal('foo');
expect(theme.typography.body1.fontSize).to.equal('var(--foo-fontSize-md)');
expect(theme.typography.body1.fontSize).to.equal('var(--foo-fontSize-md, 1rem)');
});

it('should have no css var prefix', () => {
const theme = extendTheme({ cssVarPrefix: '' });
expect(theme.cssVarPrefix).to.equal('');
expect(theme.typography.body1.fontSize).to.equal('var(--fontSize-md)');
expect(theme.typography.body1.fontSize).to.equal('var(--fontSize-md, 1rem)');
});

it('should accept custom fontSize value', () => {
const theme = extendTheme({ fontSize: { md: '2rem' } });
expect(theme.cssVarPrefix).to.equal('joy');
expect(theme.typography.body1.fontSize).to.equal('var(--joy-fontSize-md, 2rem)');
});

it('should have custom --variant-borderWidth', () => {
Expand Down Expand Up @@ -133,6 +166,7 @@ describe('extendTheme', () => {
);

expect(styles).to.deep.equal({
// No default value as the CssVarsProvider is used
borderRadius: 'var(--joy-radius-md)',
});
});
Expand Down

0 comments on commit 1eddf71

Please sign in to comment.