From 037f62be48bce64a4627864d6369d9a40873b5bc Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Mon, 29 Jul 2024 14:42:13 +0700 Subject: [PATCH 01/82] wip --- .../src/styles/ThemeProvider2.tsx | 0 .../styles/createTheme/createTheme.test.ts | 38 ++ .../src/styles/createTheme/createTheme.ts | 119 ++++ .../createTheme/createThemeWithVars.d.ts | 476 ++++++++++++++++ .../styles/createTheme/createThemeWithVars.js | 514 ++++++++++++++++++ .../createTheme/createThemeWithoutVars.d.ts | 58 ++ .../createTheme/createThemeWithoutVars.js | 125 +++++ .../src/styles/createTransitions.d.ts | 2 + .../mui-material/src/styles/extendTheme.d.ts | 3 +- 9 files changed, 1334 insertions(+), 1 deletion(-) create mode 100644 packages/mui-material/src/styles/ThemeProvider2.tsx create mode 100644 packages/mui-material/src/styles/createTheme/createTheme.test.ts create mode 100644 packages/mui-material/src/styles/createTheme/createTheme.ts create mode 100644 packages/mui-material/src/styles/createTheme/createThemeWithVars.d.ts create mode 100644 packages/mui-material/src/styles/createTheme/createThemeWithVars.js create mode 100644 packages/mui-material/src/styles/createTheme/createThemeWithoutVars.d.ts create mode 100644 packages/mui-material/src/styles/createTheme/createThemeWithoutVars.js diff --git a/packages/mui-material/src/styles/ThemeProvider2.tsx b/packages/mui-material/src/styles/ThemeProvider2.tsx new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/mui-material/src/styles/createTheme/createTheme.test.ts b/packages/mui-material/src/styles/createTheme/createTheme.test.ts new file mode 100644 index 00000000000000..36313f431135eb --- /dev/null +++ b/packages/mui-material/src/styles/createTheme/createTheme.test.ts @@ -0,0 +1,38 @@ +import { expect } from 'chai'; +import { deepOrange } from '@mui/material/colors'; +import createTheme from './createTheme'; + +describe('createTheme2', () => { + it('should not have custom properties', () => { + const theme = createTheme({ customProperties: false }); + expect(theme.customProperties).to.equal(false); + expect('vars' in theme).to.equal(false); + }); + + it('should have a light as a default colorScheme if only `palette` is provided', () => { + const theme = createTheme({ + palette: { + primary: { main: deepOrange[500] }, + }, + }); + expect(theme.defaultColorScheme).to.equal('light'); + expect(theme.palette.primary.main).to.equal(deepOrange[500]); + expect(theme.vars.palette.primary.main).to.equal( + `var(--mui-palette-primary-main, ${deepOrange[500]})`, + ); + }); + + it('should have a dark as a default colorScheme if only `palette` is provided', () => { + const theme = createTheme({ + palette: { + mode: 'dark', + primary: { main: deepOrange[500] }, + }, + }); + expect(theme.defaultColorScheme).to.equal('dark'); + expect(theme.palette.primary.main).to.equal(deepOrange[500]); + expect(theme.vars.palette.primary.main).to.equal( + `var(--mui-palette-primary-main, ${deepOrange[500]})`, + ); + }); +}); diff --git a/packages/mui-material/src/styles/createTheme/createTheme.ts b/packages/mui-material/src/styles/createTheme/createTheme.ts new file mode 100644 index 00000000000000..a8bddee8d1fb46 --- /dev/null +++ b/packages/mui-material/src/styles/createTheme/createTheme.ts @@ -0,0 +1,119 @@ +import { + ThemeOptions as SystemThemeOptions, + Theme as SystemTheme, + SxProps, + CSSObject, + SxConfig, +} from '@mui/system'; +import { Mixins, MixinsOptions } from '../createMixins'; +import { Palette, PaletteOptions } from '../createPalette'; +import { Typography, TypographyOptions } from '../createTypography'; +import { Shadows } from '../shadows'; +import { Transitions, TransitionsOptions } from '../createTransitions'; +import { ZIndex, ZIndexOptions } from '../zIndex'; +import { Components } from '../components'; +import createThemeWithoutVars from './createThemeWithoutVars'; +import createThemeWithVars, { + CssVarsThemeOptions, + ColorSystemOptions, + CssVarsPalette, + ThemeVars, + SupportedColorScheme, +} from './createThemeWithVars'; + +/** + * To disable custom properties, use module augmentation + * + * declare module '@mui/material/styles' { + * interface ThemeCustomProperties { + * disabled: true; + * } + * } + */ +export interface ThemeCustomProperties {} + +type CssVarsOptions = ThemeCustomProperties extends { disabled: true } ? {} : ColorSystemOptions; + +export interface ThemeOptions extends Omit, CssVarsOptions { + mixins?: MixinsOptions; + components?: Components>; + palette?: PaletteOptions; + shadows?: Shadows; + transitions?: TransitionsOptions; + typography?: TypographyOptions | ((palette: Palette) => TypographyOptions); + zIndex?: ZIndexOptions; + unstable_strictMode?: boolean; + unstable_sxConfig?: SxConfig; +} + +interface BaseTheme extends SystemTheme { + mixins: Mixins; + palette: Palette & (ThemeCustomProperties extends { disabled: true } ? {} : CssVarsPalette); + shadows: Shadows; + transitions: Transitions; + typography: Typography; + zIndex: ZIndex; + unstable_strictMode?: boolean; + vars: ThemeCustomProperties extends { disabled: true } ? undefined : ThemeVars; +} + +export interface Theme extends BaseTheme { + customProperties?: false; + defaultColorScheme: SupportedColorScheme; + components?: Components; + unstable_sx: (props: SxProps) => CSSObject; + unstable_sxConfig: SxConfig; +} + +export default function createTheme( + options: Omit & + Pick & { + customProperties?: + | boolean + | Pick< + CssVarsThemeOptions, + | 'colorSchemeSelector' + | 'disableCssColorScheme' + | 'cssVarPrefix' + | 'shouldSkipGeneratingVar' + >; + } = {}, + ...args: object[] +): Theme { + if (options.customProperties === false) { + // @ts-expect-error `vars` can be undefined + return createThemeWithoutVars(options, ...args); + } + + const { + palette, + colorSchemes: initialColorSchemes = !palette ? { light: true } : undefined, + defaultColorScheme: initialDefaultColorScheme = palette?.mode, + customProperties, + ...rest + } = options; + const defaultColorSchemeInput = initialDefaultColorScheme || 'light'; + const colorSchemesInput = { + ...initialColorSchemes, + ...(palette + ? { + [defaultColorSchemeInput]: { + ...(initialColorSchemes as undefined | Record<'light' | 'dark', any>)?.[ + defaultColorSchemeInput + ], + palette, + }, + } + : undefined), + }; + + return createThemeWithVars( + { + ...rest, + colorSchemes: colorSchemesInput, + defaultColorScheme: defaultColorSchemeInput, + ...(typeof customProperties !== 'boolean' ? customProperties : undefined), + }, + ...args, + ); +} diff --git a/packages/mui-material/src/styles/createTheme/createThemeWithVars.d.ts b/packages/mui-material/src/styles/createTheme/createThemeWithVars.d.ts new file mode 100644 index 00000000000000..e02f54d4e7eeaf --- /dev/null +++ b/packages/mui-material/src/styles/createTheme/createThemeWithVars.d.ts @@ -0,0 +1,476 @@ +import { OverridableStringUnion } from '@mui/types'; +import { SxConfig, SxProps, CSSObject, ApplyStyles } from '@mui/system'; +import { ExtractTypographyTokens } from '@mui/system/cssVars'; +import { ThemeOptions, Theme } from './createThemeWithoutVars'; +import { Palette, PaletteOptions } from '../createPalette'; +import { Shadows } from '../shadows'; +import { ZIndex } from '../zIndex'; +import { Components } from '../components'; + +/** + * default MD color-schemes + */ +export type DefaultColorScheme = 'light' | 'dark'; + +/** + * The application can add more color-scheme by extending this interface via module augmentation + * + * Ex. + * declare module @mui/material/styles { + * interface ColorSchemeOverrides { + * foo: true; + * } + * } + * + * // SupportedColorScheme = 'light' | 'dark' | 'foo'; + */ +export interface ColorSchemeOverrides {} +export type ExtendedColorScheme = OverridableStringUnion; + +/** + * All color-schemes that the application has + */ +export type SupportedColorScheme = DefaultColorScheme | ExtendedColorScheme; + +export interface Opacity { + inputPlaceholder: number; + inputUnderline: number; + switchTrackDisabled: number; + switchTrack: number; +} + +export type Overlays = [ + string | undefined, + string | undefined, + string | undefined, + string | undefined, + string | undefined, + string | undefined, + string | undefined, + string | undefined, + string | undefined, + string | undefined, + string | undefined, + string | undefined, + string | undefined, + string | undefined, + string | undefined, + string | undefined, + string | undefined, + string | undefined, + string | undefined, + string | undefined, + string | undefined, + string | undefined, + string | undefined, + string | undefined, + string | undefined, +]; + +export interface PaletteBackgroundChannel { + defaultChannel: string; + paperChannel: string; +} + +export interface PaletteCommonChannel { + background: string; + backgroundChannel: string; + onBackground: string; + onBackgroundChannel: string; +} + +export interface PaletteColorChannel { + mainChannel: string; + lightChannel: string; + darkChannel: string; + contrastTextChannel: string; +} + +export interface PaletteActionChannel { + activeChannel: string; + selectedChannel: string; +} + +export interface PaletteTextChannel { + primaryChannel: string; + secondaryChannel: string; +} + +export interface PaletteAlert { + errorColor: string; + infoColor: string; + successColor: string; + warningColor: string; + errorFilledBg: string; + infoFilledBg: string; + successFilledBg: string; + warningFilledBg: string; + errorFilledColor: string; + infoFilledColor: string; + successFilledColor: string; + warningFilledColor: string; + errorStandardBg: string; + infoStandardBg: string; + successStandardBg: string; + warningStandardBg: string; + errorIconColor: string; + infoIconColor: string; + successIconColor: string; + warningIconColor: string; +} + +export interface PaletteAppBar { + defaultBg: string; + darkBg: string; + darkColor: string; +} + +export interface PaletteAvatar { + defaultBg: string; +} + +export interface PaletteButton { + inheritContainedBg: string; + inheritContainedHoverBg: string; +} + +export interface PaletteChip { + defaultBorder: string; + defaultAvatarColor: string; + defaultIconColor: string; +} + +export interface PaletteFilledInput { + bg: string; + hoverBg: string; + disabledBg: string; +} + +export interface PaletteLinearProgress { + primaryBg: string; + secondaryBg: string; + errorBg: string; + infoBg: string; + successBg: string; + warningBg: string; +} + +export interface PaletteSkeleton { + bg: string; +} + +export interface PaletteSlider { + primaryTrack: string; + secondaryTrack: string; + errorTrack: string; + infoTrack: string; + successTrack: string; + warningTrack: string; +} + +export interface PaletteSnackbarContent { + bg: string; + color: string; +} + +export interface PaletteSpeedDialAction { + fabHoverBg: string; +} + +export interface PaletteStepConnector { + border: string; +} + +export interface PaletteStepContent { + border: string; +} + +export interface PaletteSwitch { + defaultColor: string; + defaultDisabledColor: string; + primaryDisabledColor: string; + secondaryDisabledColor: string; + errorDisabledColor: string; + infoDisabledColor: string; + successDisabledColor: string; + warningDisabledColor: string; +} + +export interface PaletteTableCell { + border: string; +} + +export interface PaletteTooltip { + bg: string; +} + +// The Palette should be sync with `../themeCssVarsAugmentation/index.d.ts` +export interface ColorSystemOptions { + palette?: PaletteOptions & { + background?: Partial; + common?: Partial; + primary?: Partial; + secondary?: Partial; + error?: Partial; + info?: Partial; + success?: Partial; + text?: Partial; + dividerChannel?: Partial; + action?: Partial; + Alert?: Partial; + AppBar?: Partial; + Avatar?: Partial; + Button?: Partial; + Chip?: Partial; + FilledInput?: Partial; + LinearProgress?: Partial; + Skeleton?: Partial; + Slider?: Partial; + SnackbarContent?: Partial; + SpeedDialAction?: Partial; + StepConnector?: Partial; + StepContent?: Partial; + Switch?: Partial; + TableCell?: Partial; + Tooltip?: Partial; + }; + opacity?: Partial; + overlays?: Overlays; +} + +export interface CssVarsPalette { + colorScheme: SupportedColorScheme; // TODO: remove + common: PaletteCommonChannel; + primary: PaletteColorChannel; + secondary: PaletteColorChannel; + error: PaletteColorChannel; + info: PaletteColorChannel; + success: PaletteColorChannel; + warning: PaletteColorChannel; + text: PaletteTextChannel; + background: PaletteBackgroundChannel; + dividerChannel: string; + action: PaletteActionChannel; + Alert: PaletteAlert; + AppBar: PaletteAppBar; + Avatar: PaletteAvatar; + Button: PaletteButton; + Chip: PaletteChip; + FilledInput: PaletteFilledInput; + LinearProgress: PaletteLinearProgress; + Skeleton: PaletteSkeleton; + Slider: PaletteSlider; + SnackbarContent: PaletteSnackbarContent; + SpeedDialAction: PaletteSpeedDialAction; + StepConnector: PaletteStepConnector; + StepContent: PaletteStepContent; + Switch: PaletteSwitch; + TableCell: PaletteTableCell; + Tooltip: PaletteTooltip; +} + +export interface ColorSystem { + palette: Palette & CssVarsPalette; + opacity: Opacity; + overlays: Overlays; +} + +export interface CssVarsThemeOptions extends Omit { + /** + * @default 'light' + */ + defaultColorScheme?: SupportedColorScheme; + /** + * Prefix of the generated CSS variables + * @default 'mui' + */ + cssVarPrefix?: string; + /** + * Theme components + */ + components?: Components & CssVarsTheme>; + /** + * Color schemes configuration + */ + colorSchemes?: Partial> & + (ExtendedColorScheme extends string ? Record : {}); + /** + * The strategy to generate CSS variables + * + * @example 'media' + * Generate CSS variables using [prefers-color-scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) + * + * @example '.mode-%s' + * Generate CSS variables within a class .mode-light, .mode-dark + * + * @example '[data-mode-%s]' + * Generate CSS variables within a data attribute [data-mode-light], [data-mode-dark] + */ + colorSchemeSelector?: 'media' | 'class' | 'data' | string; + /** + * If `true`, the CSS color-scheme will not be set. + * https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme + * @default false + */ + disableCssColorScheme?: boolean; + /** + * A function to determine if the key, value should be attached as CSS Variable + * `keys` is an array that represents the object path keys. + * Ex, if the theme is { foo: { bar: 'var(--test)' } } + * then, keys = ['foo', 'bar'] + * value = 'var(--test)' + */ + shouldSkipGeneratingVar?: (keys: string[], value: string | number) => boolean; +} + +// should not include keys defined in `shouldSkipGeneratingVar` and have value typeof function +export interface ThemeVars { + font: ExtractTypographyTokens; + palette: Omit< + ColorSystem['palette'], + | 'colorScheme' + | 'mode' + | 'contrastThreshold' + | 'tonalOffset' + | 'getContrastText' + | 'augmentColor' + >; + opacity: Opacity; + overlays: Overlays; + shadows: Shadows; + shape: Theme['shape']; + spacing: string; + zIndex: ZIndex; +} + +type Split = K extends string | number + ? { [k in K]: Exclude } + : never; + +type ConcatDeep = + T extends Record + ? keyof T extends string | number + ? V extends string | number + ? keyof T + : keyof V extends string | number + ? `${keyof T}-${ConcatDeep>}` + : never + : never + : never; + +/** + * Does not work for these cases: + * - { borderRadius: string | number } // the value can't be a union + * - { shadows: [string, string, ..., string] } // the value can't be an array + */ +type NormalizeVars = ConcatDeep>; + +// shut off automatic exporting for the Generics above +export {}; + +export interface ThemeCssVarOverrides {} + +export type ThemeCssVar = OverridableStringUnion< + | NormalizeVars> + | 'shape-borderRadius' + | 'shadows-0' + | 'shadows-1' + | 'shadows-2' + | 'shadows-3' + | 'shadows-4' + | 'shadows-5' + | 'shadows-6' + | 'shadows-7' + | 'shadows-8' + | 'shadows-9' + | 'shadows-10' + | 'shadows-11' + | 'shadows-12' + | 'shadows-13' + | 'shadows-14' + | 'shadows-15' + | 'shadows-16' + | 'shadows-17' + | 'shadows-18' + | 'shadows-19' + | 'shadows-20' + | 'shadows-21' + | 'shadows-22' + | 'shadows-23' + | 'shadows-24' + | 'overlays-0' + | 'overlays-1' + | 'overlays-2' + | 'overlays-3' + | 'overlays-4' + | 'overlays-5' + | 'overlays-6' + | 'overlays-7' + | 'overlays-8' + | 'overlays-9' + | 'overlays-10' + | 'overlays-11' + | 'overlays-12' + | 'overlays-13' + | 'overlays-14' + | 'overlays-15' + | 'overlays-16' + | 'overlays-17' + | 'overlays-18' + | 'overlays-19' + | 'overlays-20' + | 'overlays-21' + | 'overlays-22' + | 'overlays-23' + | 'overlays-24', + ThemeCssVarOverrides +>; + +/** + * Theme properties generated by extendTheme and CssVarsProvider + */ +export interface CssVarsTheme extends ColorSystem { + colorSchemes: Record; + colorSchemeSelector: 'media' | 'class' | 'data' | string; + cssVarPrefix: string; + defaultColorScheme: SupportedColorScheme; + vars: ThemeVars; + getCssVar: (field: ThemeCssVar, ...vars: ThemeCssVar[]) => string; + getColorSchemeSelector: (colorScheme: SupportedColorScheme) => string; + generateThemeVars: () => ThemeVars; + generateStyleSheets: () => Array>; + generateSpacing: () => Theme['spacing']; + + // Default theme tokens + spacing: Theme['spacing']; + breakpoints: Theme['breakpoints']; + shape: Theme['shape']; + typography: Theme['typography']; + transitions: Theme['transitions']; + shadows: Theme['shadows']; + mixins: Theme['mixins']; + zIndex: Theme['zIndex']; + direction: Theme['direction']; + /** + * A function to determine if the key, value should be attached as CSS Variable + * `keys` is an array that represents the object path keys. + * Ex, if the theme is { foo: { bar: 'var(--test)' } } + * then, keys = ['foo', 'bar'] + * value = 'var(--test)' + */ + shouldSkipGeneratingVar: (keys: string[], value: string | number) => boolean; + unstable_sxConfig: SxConfig; + unstable_sx: (props: SxProps) => CSSObject; + applyStyles: ApplyStyles; +} + +/** + * Generate a theme base on the options received. + * @param options Takes an incomplete theme object and adds the missing parts. + * @param args Deep merge the arguments with the about to be returned theme. + * @returns A complete, ready-to-use theme object. + */ +export default function createThemeWithVars( + options?: CssVarsThemeOptions, + ...args: object[] +): Omit & CssVarsTheme; diff --git a/packages/mui-material/src/styles/createTheme/createThemeWithVars.js b/packages/mui-material/src/styles/createTheme/createThemeWithVars.js new file mode 100644 index 00000000000000..70c01e76b3caaf --- /dev/null +++ b/packages/mui-material/src/styles/createTheme/createThemeWithVars.js @@ -0,0 +1,514 @@ +import MuiError from '@mui/internal-babel-macros/MuiError.macro'; +import deepmerge from '@mui/utils/deepmerge'; +import { unstable_createGetCssVar as systemCreateGetCssVar, createSpacing } from '@mui/system'; +import { createUnarySpacing } from '@mui/system/spacing'; +import { + prepareCssVars, + prepareTypographyVars, + createGetColorSchemeSelector, +} from '@mui/system/cssVars'; +import styleFunctionSx, { + unstable_defaultSxConfig as defaultSxConfig, +} from '@mui/system/styleFunctionSx'; + +import { + private_safeColorChannel as safeColorChannel, + private_safeAlpha as safeAlpha, + private_safeDarken as safeDarken, + private_safeLighten as safeLighten, + private_safeEmphasize as safeEmphasize, + hslToRgb, +} from '@mui/system/colorManipulator'; + +import createThemeWithoutVars from './createThemeWithoutVars'; +import defaultShouldSkipGeneratingVar from '../shouldSkipGeneratingVar'; +import getOverlayAlpha from '../getOverlayAlpha'; +import defaultGetSelector from '../createGetSelector'; +import { stringifyTheme } from '../stringifyTheme'; + +const defaultDarkOverlays = [...Array(25)].map((_, index) => { + if (index === 0) { + return undefined; + } + const overlay = getOverlayAlpha(index); + return `linear-gradient(rgba(255 255 255 / ${overlay}), rgba(255 255 255 / ${overlay}))`; +}); + +function assignNode(obj, keys) { + keys.forEach((k) => { + if (!obj[k]) { + obj[k] = {}; + } + }); +} + +function setColor(obj, key, defaultValue) { + if (!obj[key] && defaultValue) { + obj[key] = defaultValue; + } +} + +function toRgb(color) { + if (!color || !color.startsWith('hsl')) { + return color; + } + return hslToRgb(color); +} + +function setColorChannel(obj, key) { + if (!(`${key}Channel` in obj)) { + // custom channel token is not provided, generate one. + // if channel token can't be generated, show a warning. + obj[`${key}Channel`] = safeColorChannel( + toRgb(obj[key]), + `MUI: Can't create \`palette.${key}Channel\` because \`palette.${key}\` is not one of these formats: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla(), color().` + + '\n' + + `To suppress this warning, you need to explicitly provide the \`palette.${key}Channel\` as a string (in rgb format, for example "12 12 12") or undefined if you want to remove the channel token.`, + ); + } +} + +function getSpacingVal(spacingInput) { + if (typeof spacingInput === 'number') { + return `${spacingInput}px`; + } + if (typeof spacingInput === 'string') { + return spacingInput; + } + if (typeof spacingInput === 'function') { + return getSpacingVal(spacingInput(1)); + } + if (Array.isArray(spacingInput)) { + return spacingInput; + } + return '8px'; +} + +const silent = (fn) => { + try { + return fn(); + } catch (error) { + // ignore error + } + return undefined; +}; + +export const createGetCssVar = (cssVarPrefix = 'mui') => systemCreateGetCssVar(cssVarPrefix); + +function getOpacity(mode) { + return { + inputPlaceholder: mode === 'dark' ? 0.5 : 0.42, + inputUnderline: mode === 'dark' ? 0.7 : 0.42, + switchTrackDisabled: mode === 'dark' ? 0.2 : 0.12, + switchTrack: mode === 'dark' ? 0.3 : 0.38, + }; +} +function getOverlays(mode) { + return mode === 'dark' ? defaultDarkOverlays : []; +} + +function attachColorScheme(colorSchemes, scheme, restTheme, colorScheme) { + if (!scheme) { + return undefined; + } + scheme = scheme === true ? {} : scheme; + const mode = colorScheme === 'dark' ? 'dark' : 'light'; + const { palette, ...muiTheme } = createThemeWithoutVars({ + ...restTheme, + palette: { + mode, + ...scheme?.palette, + }, + }); + colorSchemes[colorScheme] = { + ...scheme, + palette, + opacity: { + ...getOpacity(mode), + ...scheme?.opacity, + }, + overlays: scheme?.overlays || getOverlays(mode), + }; + return muiTheme; +} + +/** + * A default `extendTheme` comes with a single color scheme, either `light` or `dark` based on the `defaultColorScheme`. + * This is better suited for apps that only need a single color scheme. + * + * To enable built-in `light` and `dark` color schemes, either: + * 1. provide a `colorSchemeSelector` to define how the color schemes will change. + * 2. provide `colorSchemes.dark` will set `colorSchemeSelector: 'media'` by default. + */ +export default function extendTheme(options = {}, ...args) { + const { + colorSchemes: colorSchemesInput = { light: true }, + defaultColorScheme: defaultColorSchemeInput, + disableCssColorScheme = false, + cssVarPrefix = 'mui', + shouldSkipGeneratingVar = defaultShouldSkipGeneratingVar, + colorSchemeSelector: selector = colorSchemesInput.light && colorSchemesInput.dark + ? 'media' + : undefined, + ...input + } = options; + const firstColorScheme = Object.keys(colorSchemesInput)[0]; + const defaultColorScheme = + defaultColorSchemeInput || + (colorSchemesInput.light && firstColorScheme !== 'light' ? 'light' : firstColorScheme); + const getCssVar = createGetCssVar(cssVarPrefix); + const { + [defaultColorScheme]: defaultSchemeInput, + light: builtInLight, + dark: builtInDark, + ...customColorSchemes + } = colorSchemesInput; + const colorSchemes = { ...customColorSchemes }; + let defaultScheme = defaultSchemeInput; + + // For built-in light and dark color schemes, ensure that the value is valid if they are the default color scheme. + if ( + (defaultColorScheme === 'dark' && !('dark' in colorSchemesInput)) || + (defaultColorScheme === 'light' && !('light' in colorSchemesInput)) + ) { + defaultScheme = true; + } + + if (!defaultScheme) { + throw new MuiError( + 'MUI: The provided `colorSchemes.%s` to the `extendTheme` function is either missing or invalid.', + defaultColorScheme, + ); + } + + // Create the palette for the default color scheme, either `light`, `dark`, or custom color scheme. + const muiTheme = attachColorScheme(colorSchemes, defaultScheme, input, defaultColorScheme); + + if (builtInLight && !colorSchemes.light) { + attachColorScheme(colorSchemes, builtInLight, undefined, 'light'); + } + + if (builtInDark && !colorSchemes.dark) { + attachColorScheme(colorSchemes, builtInDark, undefined, 'dark'); + } + + let theme = { + defaultColorScheme, + ...muiTheme, + cssVarPrefix, + colorSchemeSelector: selector, + getCssVar, + colorSchemes, + font: { ...prepareTypographyVars(muiTheme.typography), ...muiTheme.font }, + spacing: getSpacingVal(input.spacing), + }; + + Object.keys(theme.colorSchemes).forEach((key) => { + const palette = theme.colorSchemes[key].palette; + + const setCssVarColor = (cssVar) => { + const tokens = cssVar.split('-'); + const color = tokens[1]; + const colorToken = tokens[2]; + return getCssVar(cssVar, palette[color][colorToken]); + }; + + // attach black & white channels to common node + if (palette.mode === 'light') { + setColor(palette.common, 'background', '#fff'); + setColor(palette.common, 'onBackground', '#000'); + } + if (palette.mode === 'dark') { + setColor(palette.common, 'background', '#000'); + setColor(palette.common, 'onBackground', '#fff'); + } + + // assign component variables + assignNode(palette, [ + 'Alert', + 'AppBar', + 'Avatar', + 'Button', + 'Chip', + 'FilledInput', + 'LinearProgress', + 'Skeleton', + 'Slider', + 'SnackbarContent', + 'SpeedDialAction', + 'StepConnector', + 'StepContent', + 'Switch', + 'TableCell', + 'Tooltip', + ]); + if (palette.mode === 'light') { + setColor(palette.Alert, 'errorColor', safeDarken(palette.error.light, 0.6)); + setColor(palette.Alert, 'infoColor', safeDarken(palette.info.light, 0.6)); + setColor(palette.Alert, 'successColor', safeDarken(palette.success.light, 0.6)); + setColor(palette.Alert, 'warningColor', safeDarken(palette.warning.light, 0.6)); + setColor(palette.Alert, 'errorFilledBg', setCssVarColor('palette-error-main')); + setColor(palette.Alert, 'infoFilledBg', setCssVarColor('palette-info-main')); + setColor(palette.Alert, 'successFilledBg', setCssVarColor('palette-success-main')); + setColor(palette.Alert, 'warningFilledBg', setCssVarColor('palette-warning-main')); + setColor( + palette.Alert, + 'errorFilledColor', + silent(() => palette.getContrastText(palette.error.main)), + ); + setColor( + palette.Alert, + 'infoFilledColor', + silent(() => palette.getContrastText(palette.info.main)), + ); + setColor( + palette.Alert, + 'successFilledColor', + silent(() => palette.getContrastText(palette.success.main)), + ); + setColor( + palette.Alert, + 'warningFilledColor', + silent(() => palette.getContrastText(palette.warning.main)), + ); + setColor(palette.Alert, 'errorStandardBg', safeLighten(palette.error.light, 0.9)); + setColor(palette.Alert, 'infoStandardBg', safeLighten(palette.info.light, 0.9)); + setColor(palette.Alert, 'successStandardBg', safeLighten(palette.success.light, 0.9)); + setColor(palette.Alert, 'warningStandardBg', safeLighten(palette.warning.light, 0.9)); + setColor(palette.Alert, 'errorIconColor', setCssVarColor('palette-error-main')); + setColor(palette.Alert, 'infoIconColor', setCssVarColor('palette-info-main')); + setColor(palette.Alert, 'successIconColor', setCssVarColor('palette-success-main')); + setColor(palette.Alert, 'warningIconColor', setCssVarColor('palette-warning-main')); + setColor(palette.AppBar, 'defaultBg', setCssVarColor('palette-grey-100')); + setColor(palette.Avatar, 'defaultBg', setCssVarColor('palette-grey-400')); + setColor(palette.Button, 'inheritContainedBg', setCssVarColor('palette-grey-300')); + setColor(palette.Button, 'inheritContainedHoverBg', setCssVarColor('palette-grey-A100')); + setColor(palette.Chip, 'defaultBorder', setCssVarColor('palette-grey-400')); + setColor(palette.Chip, 'defaultAvatarColor', setCssVarColor('palette-grey-700')); + setColor(palette.Chip, 'defaultIconColor', setCssVarColor('palette-grey-700')); + setColor(palette.FilledInput, 'bg', 'rgba(0, 0, 0, 0.06)'); + setColor(palette.FilledInput, 'hoverBg', 'rgba(0, 0, 0, 0.09)'); + setColor(palette.FilledInput, 'disabledBg', 'rgba(0, 0, 0, 0.12)'); + setColor(palette.LinearProgress, 'primaryBg', safeLighten(palette.primary.main, 0.62)); + setColor(palette.LinearProgress, 'secondaryBg', safeLighten(palette.secondary.main, 0.62)); + setColor(palette.LinearProgress, 'errorBg', safeLighten(palette.error.main, 0.62)); + setColor(palette.LinearProgress, 'infoBg', safeLighten(palette.info.main, 0.62)); + setColor(palette.LinearProgress, 'successBg', safeLighten(palette.success.main, 0.62)); + setColor(palette.LinearProgress, 'warningBg', safeLighten(palette.warning.main, 0.62)); + setColor( + palette.Skeleton, + 'bg', + `rgba(${setCssVarColor('palette-text-primaryChannel')} / 0.11)`, + ); + setColor(palette.Slider, 'primaryTrack', safeLighten(palette.primary.main, 0.62)); + setColor(palette.Slider, 'secondaryTrack', safeLighten(palette.secondary.main, 0.62)); + setColor(palette.Slider, 'errorTrack', safeLighten(palette.error.main, 0.62)); + setColor(palette.Slider, 'infoTrack', safeLighten(palette.info.main, 0.62)); + setColor(palette.Slider, 'successTrack', safeLighten(palette.success.main, 0.62)); + setColor(palette.Slider, 'warningTrack', safeLighten(palette.warning.main, 0.62)); + const snackbarContentBackground = safeEmphasize(palette.background.default, 0.8); + setColor(palette.SnackbarContent, 'bg', snackbarContentBackground); + setColor( + palette.SnackbarContent, + 'color', + silent(() => palette.getContrastText(snackbarContentBackground)), + ); + setColor( + palette.SpeedDialAction, + 'fabHoverBg', + safeEmphasize(palette.background.paper, 0.15), + ); + setColor(palette.StepConnector, 'border', setCssVarColor('palette-grey-400')); + setColor(palette.StepContent, 'border', setCssVarColor('palette-grey-400')); + setColor(palette.Switch, 'defaultColor', setCssVarColor('palette-common-white')); + setColor(palette.Switch, 'defaultDisabledColor', setCssVarColor('palette-grey-100')); + setColor(palette.Switch, 'primaryDisabledColor', safeLighten(palette.primary.main, 0.62)); + setColor(palette.Switch, 'secondaryDisabledColor', safeLighten(palette.secondary.main, 0.62)); + setColor(palette.Switch, 'errorDisabledColor', safeLighten(palette.error.main, 0.62)); + setColor(palette.Switch, 'infoDisabledColor', safeLighten(palette.info.main, 0.62)); + setColor(palette.Switch, 'successDisabledColor', safeLighten(palette.success.main, 0.62)); + setColor(palette.Switch, 'warningDisabledColor', safeLighten(palette.warning.main, 0.62)); + setColor(palette.TableCell, 'border', safeLighten(safeAlpha(palette.divider, 1), 0.88)); + setColor(palette.Tooltip, 'bg', safeAlpha(palette.grey[700], 0.92)); + } + if (palette.mode === 'dark') { + setColor(palette.Alert, 'errorColor', safeLighten(palette.error.light, 0.6)); + setColor(palette.Alert, 'infoColor', safeLighten(palette.info.light, 0.6)); + setColor(palette.Alert, 'successColor', safeLighten(palette.success.light, 0.6)); + setColor(palette.Alert, 'warningColor', safeLighten(palette.warning.light, 0.6)); + setColor(palette.Alert, 'errorFilledBg', setCssVarColor('palette-error-dark')); + setColor(palette.Alert, 'infoFilledBg', setCssVarColor('palette-info-dark')); + setColor(palette.Alert, 'successFilledBg', setCssVarColor('palette-success-dark')); + setColor(palette.Alert, 'warningFilledBg', setCssVarColor('palette-warning-dark')); + setColor( + palette.Alert, + 'errorFilledColor', + silent(() => palette.getContrastText(palette.error.dark)), + ); + setColor( + palette.Alert, + 'infoFilledColor', + silent(() => palette.getContrastText(palette.info.dark)), + ); + setColor( + palette.Alert, + 'successFilledColor', + silent(() => palette.getContrastText(palette.success.dark)), + ); + setColor( + palette.Alert, + 'warningFilledColor', + silent(() => palette.getContrastText(palette.warning.dark)), + ); + setColor(palette.Alert, 'errorStandardBg', safeDarken(palette.error.light, 0.9)); + setColor(palette.Alert, 'infoStandardBg', safeDarken(palette.info.light, 0.9)); + setColor(palette.Alert, 'successStandardBg', safeDarken(palette.success.light, 0.9)); + setColor(palette.Alert, 'warningStandardBg', safeDarken(palette.warning.light, 0.9)); + setColor(palette.Alert, 'errorIconColor', setCssVarColor('palette-error-main')); + setColor(palette.Alert, 'infoIconColor', setCssVarColor('palette-info-main')); + setColor(palette.Alert, 'successIconColor', setCssVarColor('palette-success-main')); + setColor(palette.Alert, 'warningIconColor', setCssVarColor('palette-warning-main')); + setColor(palette.AppBar, 'defaultBg', setCssVarColor('palette-grey-900')); + setColor(palette.AppBar, 'darkBg', setCssVarColor('palette-background-paper')); // specific for dark mode + setColor(palette.AppBar, 'darkColor', setCssVarColor('palette-text-primary')); // specific for dark mode + setColor(palette.Avatar, 'defaultBg', setCssVarColor('palette-grey-600')); + setColor(palette.Button, 'inheritContainedBg', setCssVarColor('palette-grey-800')); + setColor(palette.Button, 'inheritContainedHoverBg', setCssVarColor('palette-grey-700')); + setColor(palette.Chip, 'defaultBorder', setCssVarColor('palette-grey-700')); + setColor(palette.Chip, 'defaultAvatarColor', setCssVarColor('palette-grey-300')); + setColor(palette.Chip, 'defaultIconColor', setCssVarColor('palette-grey-300')); + setColor(palette.FilledInput, 'bg', 'rgba(255, 255, 255, 0.09)'); + setColor(palette.FilledInput, 'hoverBg', 'rgba(255, 255, 255, 0.13)'); + setColor(palette.FilledInput, 'disabledBg', 'rgba(255, 255, 255, 0.12)'); + setColor(palette.LinearProgress, 'primaryBg', safeDarken(palette.primary.main, 0.5)); + setColor(palette.LinearProgress, 'secondaryBg', safeDarken(palette.secondary.main, 0.5)); + setColor(palette.LinearProgress, 'errorBg', safeDarken(palette.error.main, 0.5)); + setColor(palette.LinearProgress, 'infoBg', safeDarken(palette.info.main, 0.5)); + setColor(palette.LinearProgress, 'successBg', safeDarken(palette.success.main, 0.5)); + setColor(palette.LinearProgress, 'warningBg', safeDarken(palette.warning.main, 0.5)); + setColor( + palette.Skeleton, + 'bg', + `rgba(${setCssVarColor('palette-text-primaryChannel')} / 0.13)`, + ); + setColor(palette.Slider, 'primaryTrack', safeDarken(palette.primary.main, 0.5)); + setColor(palette.Slider, 'secondaryTrack', safeDarken(palette.secondary.main, 0.5)); + setColor(palette.Slider, 'errorTrack', safeDarken(palette.error.main, 0.5)); + setColor(palette.Slider, 'infoTrack', safeDarken(palette.info.main, 0.5)); + setColor(palette.Slider, 'successTrack', safeDarken(palette.success.main, 0.5)); + setColor(palette.Slider, 'warningTrack', safeDarken(palette.warning.main, 0.5)); + const snackbarContentBackground = safeEmphasize(palette.background.default, 0.98); + setColor(palette.SnackbarContent, 'bg', snackbarContentBackground); + setColor( + palette.SnackbarContent, + 'color', + silent(() => palette.getContrastText(snackbarContentBackground)), + ); + setColor( + palette.SpeedDialAction, + 'fabHoverBg', + safeEmphasize(palette.background.paper, 0.15), + ); + setColor(palette.StepConnector, 'border', setCssVarColor('palette-grey-600')); + setColor(palette.StepContent, 'border', setCssVarColor('palette-grey-600')); + setColor(palette.Switch, 'defaultColor', setCssVarColor('palette-grey-300')); + setColor(palette.Switch, 'defaultDisabledColor', setCssVarColor('palette-grey-600')); + setColor(palette.Switch, 'primaryDisabledColor', safeDarken(palette.primary.main, 0.55)); + setColor(palette.Switch, 'secondaryDisabledColor', safeDarken(palette.secondary.main, 0.55)); + setColor(palette.Switch, 'errorDisabledColor', safeDarken(palette.error.main, 0.55)); + setColor(palette.Switch, 'infoDisabledColor', safeDarken(palette.info.main, 0.55)); + setColor(palette.Switch, 'successDisabledColor', safeDarken(palette.success.main, 0.55)); + setColor(palette.Switch, 'warningDisabledColor', safeDarken(palette.warning.main, 0.55)); + setColor(palette.TableCell, 'border', safeDarken(safeAlpha(palette.divider, 1), 0.68)); + setColor(palette.Tooltip, 'bg', safeAlpha(palette.grey[700], 0.92)); + } + + // MUI X - DataGrid needs this token. + setColorChannel(palette.background, 'default'); + + // added for consistency with the `background.default` token + setColorChannel(palette.background, 'paper'); + + setColorChannel(palette.common, 'background'); + setColorChannel(palette.common, 'onBackground'); + + setColorChannel(palette, 'divider'); + + Object.keys(palette).forEach((color) => { + const colors = palette[color]; + + // The default palettes (primary, secondary, error, info, success, and warning) errors are handled by the above `createTheme(...)`. + + if (colors && typeof colors === 'object') { + // Silent the error for custom palettes. + if (colors.main) { + setColor(palette[color], 'mainChannel', safeColorChannel(toRgb(colors.main))); + } + if (colors.light) { + setColor(palette[color], 'lightChannel', safeColorChannel(toRgb(colors.light))); + } + if (colors.dark) { + setColor(palette[color], 'darkChannel', safeColorChannel(toRgb(colors.dark))); + } + if (colors.contrastText) { + setColor( + palette[color], + 'contrastTextChannel', + safeColorChannel(toRgb(colors.contrastText)), + ); + } + + if (color === 'text') { + // Text colors: text.primary, text.secondary + setColorChannel(palette[color], 'primary'); + setColorChannel(palette[color], 'secondary'); + } + + if (color === 'action') { + // Action colors: action.active, action.selected + if (colors.active) { + setColorChannel(palette[color], 'active'); + } + if (colors.selected) { + setColorChannel(palette[color], 'selected'); + } + } + } + }); + }); + + theme = args.reduce((acc, argument) => deepmerge(acc, argument), theme); + + const parserConfig = { + prefix: cssVarPrefix, + disableCssColorScheme, + shouldSkipGeneratingVar, + getSelector: defaultGetSelector(theme), + }; + const { vars, generateThemeVars, generateStyleSheets } = prepareCssVars(theme, parserConfig); + theme.vars = vars; + Object.entries(theme.colorSchemes[theme.defaultColorScheme]).forEach(([key, value]) => { + theme[key] = value; + }); + theme.generateThemeVars = generateThemeVars; + theme.generateStyleSheets = generateStyleSheets; + theme.generateSpacing = function generateSpacing() { + return createSpacing(input.spacing, createUnarySpacing(this)); + }; + theme.getColorSchemeSelector = createGetColorSchemeSelector(selector); + theme.spacing = theme.generateSpacing(); + theme.shouldSkipGeneratingVar = shouldSkipGeneratingVar; + theme.unstable_sxConfig = { + ...defaultSxConfig, + ...input?.unstable_sxConfig, + }; + theme.unstable_sx = function sx(props) { + return styleFunctionSx({ + sx: props, + theme: this, + }); + }; + theme.toRuntimeSource = stringifyTheme; // for Pigment CSS integration + + return theme; +} diff --git a/packages/mui-material/src/styles/createTheme/createThemeWithoutVars.d.ts b/packages/mui-material/src/styles/createTheme/createThemeWithoutVars.d.ts new file mode 100644 index 00000000000000..8ed1df73eea338 --- /dev/null +++ b/packages/mui-material/src/styles/createTheme/createThemeWithoutVars.d.ts @@ -0,0 +1,58 @@ +import { + ThemeOptions as SystemThemeOptions, + Theme as SystemTheme, + SxProps, + CSSObject, + SxConfig, +} from '@mui/system'; +import { Mixins, MixinsOptions } from '../createMixins'; +import { Palette, PaletteOptions } from '../createPalette'; +import { Typography, TypographyOptions } from '../createTypography'; +import { Shadows } from '../shadows'; +import { Transitions, TransitionsOptions } from '../createTransitions'; +import { ZIndex, ZIndexOptions } from '../zIndex'; +import { Components } from '../components'; + +export interface ThemeOptions extends Omit { + mixins?: MixinsOptions; + components?: Components>; + palette?: PaletteOptions; + shadows?: Shadows; + transitions?: TransitionsOptions; + typography?: TypographyOptions | ((palette: Palette) => TypographyOptions); + zIndex?: ZIndexOptions; + unstable_strictMode?: boolean; + unstable_sxConfig?: SxConfig; +} + +interface BaseTheme extends SystemTheme { + mixins: Mixins; + palette: Palette; + shadows: Shadows; + transitions: Transitions; + typography: Typography; + zIndex: ZIndex; + unstable_strictMode?: boolean; + vars: undefined; +} + +// shut off automatic exporting for the `BaseTheme` above +export {}; + +/** + * Our [TypeScript guide on theme customization](https://mui.com/material-ui/guides/typescript/#customization-of-theme) explains in detail how you would add custom properties. + */ +export interface Theme extends BaseTheme { + defaultColorScheme: 'light' | 'dark'; + components?: Components; + unstable_sx: (props: SxProps) => CSSObject; + unstable_sxConfig: SxConfig; +} + +/** + * Generate a theme base on the options received. + * @param options Takes an incomplete theme object and adds the missing parts. + * @param args Deep merge the arguments with the about to be returned theme. + * @returns A complete, ready-to-use theme object. + */ +export default function createThemeWithoutVars(options?: ThemeOptions, ...args: object[]): Theme; diff --git a/packages/mui-material/src/styles/createTheme/createThemeWithoutVars.js b/packages/mui-material/src/styles/createTheme/createThemeWithoutVars.js new file mode 100644 index 00000000000000..27bffe5070cb70 --- /dev/null +++ b/packages/mui-material/src/styles/createTheme/createThemeWithoutVars.js @@ -0,0 +1,125 @@ +import deepmerge from '@mui/utils/deepmerge'; +import styleFunctionSx, { + unstable_defaultSxConfig as defaultSxConfig, +} from '@mui/system/styleFunctionSx'; +import systemCreateTheme from '@mui/system/createTheme'; +import MuiError from '@mui/internal-babel-macros/MuiError.macro'; +import generateUtilityClass from '@mui/utils/generateUtilityClass'; +import createMixins from '../createMixins'; +import createPalette from '../createPalette'; +import createTypography from '../createTypography'; +import shadows from '../shadows'; +import createTransitions from '../createTransitions'; +import zIndex from '../zIndex'; + +function createThemeWithoutVars(options = {}, ...args) { + const { + breakpoints: breakpointsInput, + mixins: mixinsInput = {}, + spacing: spacingInput, + palette: paletteInput = {}, + transitions: transitionsInput = {}, + typography: typographyInput = {}, + shape: shapeInput, + ...other + } = options; + + if (options.vars) { + throw new MuiError( + 'MUI: `vars` is a private field used for CSS variables support.\n' + + 'Please use another name.', + ); + } + + const palette = createPalette(paletteInput); + const systemTheme = systemCreateTheme(options); + + let muiTheme = deepmerge(systemTheme, { + mixins: createMixins(systemTheme.breakpoints, mixinsInput), + palette, + // Don't use [...shadows] until you've verified its transpiled code is not invoking the iterator protocol. + shadows: shadows.slice(), + typography: createTypography(palette, typographyInput), + transitions: createTransitions(transitionsInput), + zIndex: { ...zIndex }, + }); + + muiTheme = deepmerge(muiTheme, other); + muiTheme = args.reduce((acc, argument) => deepmerge(acc, argument), muiTheme); + + if (process.env.NODE_ENV !== 'production') { + // TODO v6: Refactor to use globalStateClassesMapping from @mui/utils once `readOnly` state class is used in Rating component. + const stateClasses = [ + 'active', + 'checked', + 'completed', + 'disabled', + 'error', + 'expanded', + 'focused', + 'focusVisible', + 'required', + 'selected', + ]; + + const traverse = (node, component) => { + let key; + + // eslint-disable-next-line guard-for-in + for (key in node) { + const child = node[key]; + if (stateClasses.indexOf(key) !== -1 && Object.keys(child).length > 0) { + if (process.env.NODE_ENV !== 'production') { + const stateClass = generateUtilityClass('', key); + console.error( + [ + `MUI: The \`${component}\` component increases ` + + `the CSS specificity of the \`${key}\` internal state.`, + 'You can not override it like this: ', + JSON.stringify(node, null, 2), + '', + `Instead, you need to use the '&.${stateClass}' syntax:`, + JSON.stringify( + { + root: { + [`&.${stateClass}`]: child, + }, + }, + null, + 2, + ), + '', + 'https://mui.com/r/state-classes-guide', + ].join('\n'), + ); + } + // Remove the style to prevent global conflicts. + node[key] = {}; + } + } + }; + + Object.keys(muiTheme.components).forEach((component) => { + const styleOverrides = muiTheme.components[component].styleOverrides; + + if (styleOverrides && component.indexOf('Mui') === 0) { + traverse(styleOverrides, component); + } + }); + } + + muiTheme.unstable_sxConfig = { + ...defaultSxConfig, + ...other?.unstable_sxConfig, + }; + muiTheme.unstable_sx = function sx(props) { + return styleFunctionSx({ + sx: props, + theme: this, + }); + }; + + return muiTheme; +} + +export default createThemeWithoutVars; diff --git a/packages/mui-material/src/styles/createTransitions.d.ts b/packages/mui-material/src/styles/createTransitions.d.ts index 117a738424ff24..e3136ae0b3b4bd 100644 --- a/packages/mui-material/src/styles/createTransitions.d.ts +++ b/packages/mui-material/src/styles/createTransitions.d.ts @@ -49,3 +49,5 @@ export interface Transitions { create: typeof create; getAutoHeightDuration: typeof getAutoHeightDuration; } + +export default function createTransitions(inputTransitions: TransitionsOptions): Transitions; diff --git a/packages/mui-material/src/styles/extendTheme.d.ts b/packages/mui-material/src/styles/extendTheme.d.ts index c6eafa4422101e..ceec776d05b024 100644 --- a/packages/mui-material/src/styles/extendTheme.d.ts +++ b/packages/mui-material/src/styles/extendTheme.d.ts @@ -239,7 +239,7 @@ export interface ColorSystemOptions { } export interface CssVarsPalette { - colorScheme: SupportedColorScheme; + colorScheme: SupportedColorScheme; // TODO: remove common: PaletteCommonChannel; primary: PaletteColorChannel; secondary: PaletteColorChannel; @@ -433,6 +433,7 @@ export interface CssVarsTheme extends ColorSystem { colorSchemes: Record; colorSchemeSelector: 'media' | 'class' | 'data' | string; cssVarPrefix: string; + defaultColorScheme: SupportedColorScheme; vars: ThemeVars; getCssVar: (field: ThemeCssVar, ...vars: ThemeCssVar[]) => string; getColorSchemeSelector: (colorScheme: SupportedColorScheme) => string; From 2258db1a3096f8d8b09a31949f2a269bd3595f65 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Mon, 29 Jul 2024 16:28:20 +0700 Subject: [PATCH 02/82] rename type --- .../mui-material/src/styles/createTheme/createTheme.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/mui-material/src/styles/createTheme/createTheme.ts b/packages/mui-material/src/styles/createTheme/createTheme.ts index a8bddee8d1fb46..861f1979ab2e19 100644 --- a/packages/mui-material/src/styles/createTheme/createTheme.ts +++ b/packages/mui-material/src/styles/createTheme/createTheme.ts @@ -25,14 +25,14 @@ import createThemeWithVars, { * To disable custom properties, use module augmentation * * declare module '@mui/material/styles' { - * interface ThemeCustomProperties { + * interface CssThemeVariables { * disabled: true; * } * } */ -export interface ThemeCustomProperties {} +export interface CssThemeVariables {} -type CssVarsOptions = ThemeCustomProperties extends { disabled: true } ? {} : ColorSystemOptions; +type CssVarsOptions = CssThemeVariables extends { disabled: true } ? {} : ColorSystemOptions; export interface ThemeOptions extends Omit, CssVarsOptions { mixins?: MixinsOptions; @@ -48,13 +48,13 @@ export interface ThemeOptions extends Omit, CssVar interface BaseTheme extends SystemTheme { mixins: Mixins; - palette: Palette & (ThemeCustomProperties extends { disabled: true } ? {} : CssVarsPalette); + palette: Palette & (CssThemeVariables extends { disabled: true } ? {} : CssVarsPalette); shadows: Shadows; transitions: Transitions; typography: Typography; zIndex: ZIndex; unstable_strictMode?: boolean; - vars: ThemeCustomProperties extends { disabled: true } ? undefined : ThemeVars; + vars: CssThemeVariables extends { disabled: true } ? undefined : ThemeVars; } export interface Theme extends BaseTheme { From e22d06843a867510ce667734a8d07f492767535c Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Mon, 29 Jul 2024 16:39:23 +0700 Subject: [PATCH 03/82] only call extendTheme when CssVarsProvider is used --- .../mui-material/src/styles/CssVarsProvider.tsx | 4 +--- .../src/cssVars/createCssVarsProvider.js | 16 ++++++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/packages/mui-material/src/styles/CssVarsProvider.tsx b/packages/mui-material/src/styles/CssVarsProvider.tsx index bfbc6d12b6c33a..443c2bcf7099df 100644 --- a/packages/mui-material/src/styles/CssVarsProvider.tsx +++ b/packages/mui-material/src/styles/CssVarsProvider.tsx @@ -7,15 +7,13 @@ import createTypography from './createTypography'; import THEME_ID from './identifier'; import { defaultConfig } from '../InitColorSchemeScript/InitColorSchemeScript'; -const defaultTheme = extendTheme(); - const { CssVarsProvider, useColorScheme, getInitColorSchemeScript: deprecatedGetInitColorSchemeScript, } = createCssVarsProvider({ themeId: THEME_ID, - theme: defaultTheme, + theme: extendTheme, colorSchemeStorageKey: defaultConfig.colorSchemeStorageKey, modeStorageKey: defaultConfig.modeStorageKey, defaultColorScheme: { diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.js b/packages/mui-system/src/cssVars/createCssVarsProvider.js index 61b93ce8b14948..e8d62303bd8b79 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.js +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.js @@ -47,7 +47,7 @@ export default function createCssVarsProvider(options) { function CssVarsProvider(props) { const { children, - theme: themeProp = defaultTheme, + theme: themeProp, modeStorageKey = defaultModeStorageKey, colorSchemeStorageKey = defaultColorSchemeStorageKey, disableTransitionOnChange = designSystemTransitionOnChange, @@ -62,13 +62,13 @@ export default function createCssVarsProvider(options) { const ctx = React.useContext(ColorSchemeContext); const nested = !!ctx && !disableNestedContext; - const scopedTheme = themeProp[themeId]; - const { - colorSchemes = {}, - components = {}, - cssVarPrefix, - ...restThemeProp - } = scopedTheme || themeProp; + const scopedTheme = React.useMemo(() => { + if (themeProp) { + return themeProp[themeId] || themeProp; + } + return typeof defaultTheme === 'function' ? defaultTheme() : defaultTheme; + }, [themeProp]); + const { colorSchemes = {}, components = {}, cssVarPrefix, ...restThemeProp } = scopedTheme; const joinedColorSchemes = Object.keys(colorSchemes) .filter((k) => !!colorSchemes[k]) .join(','); From 5ba82d5313a9a8bbacb1a56df7407742016b8c4f Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Mon, 29 Jul 2024 20:21:20 +0700 Subject: [PATCH 04/82] create new ThemeProvider and createTheme --- .../src/CssBaseline/CssBaseline.js | 2 +- .../styles/ThemeProvider/ThemeProvider.tsx | 57 +++++++++ .../ThemeProvider/ThemeProviderNoVars.tsx | 23 ++++ .../ThemeProvider/ThemeProviderWithVars.tsx | 79 ++++++++++++ .../src/styles/ThemeProvider/index.ts | 2 + .../styles/createTheme/createTheme.test.ts | 34 +++++- .../src/styles/createTheme/createTheme.ts | 114 +++++++----------- ...ithoutVars.d.ts => createThemeNoVars.d.ts} | 50 ++++++-- ...emeWithoutVars.js => createThemeNoVars.js} | 4 +- .../createTheme/createThemeWithVars.d.ts | 2 +- .../styles/createTheme/createThemeWithVars.js | 4 +- .../src/styles/createTheme/index.ts | 2 + .../src/cssVars/createCssVarsProvider.d.ts | 1 + .../src/cssVars/createCssVarsProvider.js | 11 +- 14 files changed, 293 insertions(+), 92 deletions(-) create mode 100644 packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx create mode 100644 packages/mui-material/src/styles/ThemeProvider/ThemeProviderNoVars.tsx create mode 100644 packages/mui-material/src/styles/ThemeProvider/ThemeProviderWithVars.tsx create mode 100644 packages/mui-material/src/styles/ThemeProvider/index.ts rename packages/mui-material/src/styles/createTheme/{createThemeWithoutVars.d.ts => createThemeNoVars.d.ts} (53%) rename packages/mui-material/src/styles/createTheme/{createThemeWithoutVars.js => createThemeNoVars.js} (97%) create mode 100644 packages/mui-material/src/styles/createTheme/index.ts diff --git a/packages/mui-material/src/CssBaseline/CssBaseline.js b/packages/mui-material/src/CssBaseline/CssBaseline.js index 9caadb2ba5efb3..4dd736f771de5d 100644 --- a/packages/mui-material/src/CssBaseline/CssBaseline.js +++ b/packages/mui-material/src/CssBaseline/CssBaseline.js @@ -31,7 +31,7 @@ export const body = (theme) => ({ export const styles = (theme, enableColorScheme = false) => { const colorSchemeStyles = {}; - if (enableColorScheme && theme.colorSchemes) { + if (enableColorScheme && theme.vars) { Object.entries(theme.colorSchemes).forEach(([key, scheme]) => { const selector = theme.getColorSchemeSelector(key); if (selector.startsWith('@')) { diff --git a/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx b/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx new file mode 100644 index 00000000000000..389844e8f3e025 --- /dev/null +++ b/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx @@ -0,0 +1,57 @@ +import * as React from 'react'; +import { DefaultTheme } from '@mui/system'; +import ThemeProviderNoVars from './ThemeProviderNoVars'; +import { CssVarsProvider } from './ThemeProviderWithVars'; + +export interface ThemeProviderProps { + children?: React.ReactNode; + theme: Partial | ((outerTheme: Theme) => Theme); + /** + * [Configurable if `colorSchemes` is provided] + * The document used to perform `disableTransitionOnChange` feature + * @default document + */ + documentNode?: Document | null; + /** + * [Configurable if `colorSchemes` is provided] + * The node used to attach the color-scheme attribute + * @default document + */ + colorSchemeNode?: Element | null; + /** + * [Configurable if `colorSchemes` is provided] + * The window that attaches the 'storage' event listener + * @default window + */ + storageWindow?: Window | null; + /** + * [Configurable if `customProperties` is not `false`] + * If `true`, the provider creates its own context and generate stylesheet as if it is a root `CssVarsProvider`. + */ + disableNestedContext?: boolean; + /** + * [Configurable if `customProperties` is not `false`] + * If `true`, the style sheet won't be generated. + * + * This is useful for controlling nested CssVarsProvider behavior. + * @default false + */ + disableStyleSheetGeneration?: boolean; + /** + * [Configurable if `colorSchemes` is provided] + * Disable CSS transitions when switching between modes or color schemes + * @default false + */ + disableTransitionOnChange?: boolean; +} + +export default function ThemeProvider({ + theme, + ...props +}: ThemeProviderProps) { + if (!('colorSchemes' in theme)) { + return ; + } + // @ts-expect-error `theme` is created by `createTheme`, typing is handled there. + return ; +} diff --git a/packages/mui-material/src/styles/ThemeProvider/ThemeProviderNoVars.tsx b/packages/mui-material/src/styles/ThemeProvider/ThemeProviderNoVars.tsx new file mode 100644 index 00000000000000..f622137da91ed1 --- /dev/null +++ b/packages/mui-material/src/styles/ThemeProvider/ThemeProviderNoVars.tsx @@ -0,0 +1,23 @@ +'use client'; +import * as React from 'react'; +import { ThemeProvider as SystemThemeProvider, DefaultTheme } from '@mui/system'; +import THEME_ID from '../identifier'; + +export interface ThemeProviderNoVarsProps { + children?: React.ReactNode; + theme: Partial | ((outerTheme: Theme) => Theme); +} + +export default function ThemeProviderNoVars({ + theme: themeInput, + ...props +}: ThemeProviderNoVarsProps): React.ReactElement> { + const scopedTheme = THEME_ID in themeInput ? themeInput[THEME_ID] : themeInput; + return ( + + ); +} diff --git a/packages/mui-material/src/styles/ThemeProvider/ThemeProviderWithVars.tsx b/packages/mui-material/src/styles/ThemeProvider/ThemeProviderWithVars.tsx new file mode 100644 index 00000000000000..f9526dc8a9fe72 --- /dev/null +++ b/packages/mui-material/src/styles/ThemeProvider/ThemeProviderWithVars.tsx @@ -0,0 +1,79 @@ +'use client'; +import * as React from 'react'; +import { unstable_createCssVarsProvider as createCssVarsProvider, SxProps } from '@mui/system'; +import styleFunctionSx from '@mui/system/styleFunctionSx'; +import createThemeWithVars, { + SupportedColorScheme, + CssVarsTheme, +} from '../createTheme/createThemeWithVars'; +import createTypography from '../createTypography'; +import THEME_ID from '../identifier'; +import { defaultConfig } from '../../InitColorSchemeScript/InitColorSchemeScript'; + +const { + CssVarsProvider, + useColorScheme, + getInitColorSchemeScript: deprecatedGetInitColorSchemeScript, +} = createCssVarsProvider({ + themeId: THEME_ID, + theme: createThemeWithVars, + colorSchemeStorageKey: defaultConfig.colorSchemeStorageKey, + modeStorageKey: defaultConfig.modeStorageKey, + defaultColorScheme: { + light: defaultConfig.defaultLightColorScheme, + dark: defaultConfig.defaultDarkColorScheme, + }, + resolveTheme: (theme) => { + const newTheme = { + ...theme, + typography: createTypography(theme.palette, theme.typography), + }; + + newTheme.unstable_sx = function sx(props: SxProps) { + return styleFunctionSx({ sx: props, theme: this }); + }; + + return newTheme; + }, +}); + +let warnedOnce = false; + +// TODO: remove in v7 +// eslint-disable-next-line @typescript-eslint/naming-convention +function Experimental_CssVarsProvider(props: any) { + if (!warnedOnce) { + console.warn( + [ + 'MUI: The Experimental_CssVarsProvider component has been stabilized.', + '', + "You should use `import { CssVarsProvider } from '@mui/material/styles'`", + ].join('\n'), + ); + + warnedOnce = true; + } + + return ; +} + +let warnedInitScriptOnce = false; + +// TODO: remove in v7 +const getInitColorSchemeScript: typeof deprecatedGetInitColorSchemeScript = (params) => { + if (!warnedInitScriptOnce) { + console.warn( + [ + 'MUI: The getInitColorSchemeScript function has been deprecated.', + '', + "You should use `import InitColorSchemeScript from '@mui/material/InitColorSchemeScript'`", + 'and replace the function call with `` instead.', + ].join('\n'), + ); + + warnedInitScriptOnce = true; + } + return deprecatedGetInitColorSchemeScript(params); +}; + +export { useColorScheme, CssVarsProvider, getInitColorSchemeScript, Experimental_CssVarsProvider }; diff --git a/packages/mui-material/src/styles/ThemeProvider/index.ts b/packages/mui-material/src/styles/ThemeProvider/index.ts new file mode 100644 index 00000000000000..8774f170cc1f73 --- /dev/null +++ b/packages/mui-material/src/styles/ThemeProvider/index.ts @@ -0,0 +1,2 @@ +export { default } from './ThemeProvider'; +export type { ThemeProviderProps } from './ThemeProvider'; diff --git a/packages/mui-material/src/styles/createTheme/createTheme.test.ts b/packages/mui-material/src/styles/createTheme/createTheme.test.ts index 36313f431135eb..e0d97f17db1742 100644 --- a/packages/mui-material/src/styles/createTheme/createTheme.test.ts +++ b/packages/mui-material/src/styles/createTheme/createTheme.test.ts @@ -1,12 +1,36 @@ import { expect } from 'chai'; import { deepOrange } from '@mui/material/colors'; import createTheme from './createTheme'; +import createPalette from '../createPalette'; -describe('createTheme2', () => { - it('should not have custom properties', () => { - const theme = createTheme({ customProperties: false }); - expect(theme.customProperties).to.equal(false); - expect('vars' in theme).to.equal(false); +const lightPalette = createPalette({ mode: 'light' }); +const darkPalette = createPalette({ mode: 'dark' }); + +describe('createTheme', () => { + describe('Without custom properties', () => { + it('should not have custom properties', () => { + const theme = createTheme({ customProperties: false }); + expect(theme.customProperties).to.equal(false); + expect('vars' in theme).to.equal(false); + }); + + it('color schemes dark: true', () => { + const theme = createTheme({ customProperties: false, colorSchemes: { dark: true } }); + const { light, dark } = theme.colorSchemes || {}; + expect(light?.palette.primary.main).to.deep.equal(lightPalette.primary.main); + expect(dark?.palette.primary.main).to.deep.equal(darkPalette.primary.main); + }); + + it('color schemes light: true', () => { + const theme = createTheme({ + customProperties: false, + colorSchemes: { light: true }, + palette: { mode: 'dark' }, + }); + const { light, dark } = theme.colorSchemes || {}; + expect(light?.palette.primary.main).to.deep.equal(lightPalette.primary.main); + expect(dark?.palette.primary.main).to.deep.equal(darkPalette.primary.main); + }); }); it('should have a light as a default colorScheme if only `palette` is provided', () => { diff --git a/packages/mui-material/src/styles/createTheme/createTheme.ts b/packages/mui-material/src/styles/createTheme/createTheme.ts index 861f1979ab2e19..da15155aa3b5b5 100644 --- a/packages/mui-material/src/styles/createTheme/createTheme.ts +++ b/packages/mui-material/src/styles/createTheme/createTheme.ts @@ -1,68 +1,25 @@ -import { - ThemeOptions as SystemThemeOptions, - Theme as SystemTheme, - SxProps, - CSSObject, - SxConfig, -} from '@mui/system'; -import { Mixins, MixinsOptions } from '../createMixins'; -import { Palette, PaletteOptions } from '../createPalette'; -import { Typography, TypographyOptions } from '../createTypography'; -import { Shadows } from '../shadows'; -import { Transitions, TransitionsOptions } from '../createTransitions'; -import { ZIndex, ZIndexOptions } from '../zIndex'; -import { Components } from '../components'; -import createThemeWithoutVars from './createThemeWithoutVars'; -import createThemeWithVars, { - CssVarsThemeOptions, - ColorSystemOptions, - CssVarsPalette, - ThemeVars, - SupportedColorScheme, -} from './createThemeWithVars'; +import createPalette from '../createPalette'; +import createThemeWithVars, { CssVarsThemeOptions, ColorSystem } from './createThemeWithVars'; +import createThemeNoVars, { Theme, ThemeOptions } from './createThemeNoVars'; -/** - * To disable custom properties, use module augmentation - * - * declare module '@mui/material/styles' { - * interface CssThemeVariables { - * disabled: true; - * } - * } - */ -export interface CssThemeVariables {} - -type CssVarsOptions = CssThemeVariables extends { disabled: true } ? {} : ColorSystemOptions; - -export interface ThemeOptions extends Omit, CssVarsOptions { - mixins?: MixinsOptions; - components?: Components>; - palette?: PaletteOptions; - shadows?: Shadows; - transitions?: TransitionsOptions; - typography?: TypographyOptions | ((palette: Palette) => TypographyOptions); - zIndex?: ZIndexOptions; - unstable_strictMode?: boolean; - unstable_sxConfig?: SxConfig; -} - -interface BaseTheme extends SystemTheme { - mixins: Mixins; - palette: Palette & (CssThemeVariables extends { disabled: true } ? {} : CssVarsPalette); - shadows: Shadows; - transitions: Transitions; - typography: Typography; - zIndex: ZIndex; - unstable_strictMode?: boolean; - vars: CssThemeVariables extends { disabled: true } ? undefined : ThemeVars; -} - -export interface Theme extends BaseTheme { - customProperties?: false; - defaultColorScheme: SupportedColorScheme; - components?: Components; - unstable_sx: (props: SxProps) => CSSObject; - unstable_sxConfig: SxConfig; +// eslint-disable-next-line consistent-return +function attachColorScheme( + theme: { colorSchemes?: Partial> }, + scheme: 'light' | 'dark', + colorScheme: boolean | Record | undefined, +) { + if (!theme.colorSchemes) { + return undefined; + } + if (colorScheme) { + theme.colorSchemes[scheme] = { + ...(colorScheme !== true && colorScheme), + palette: createPalette({ + ...(colorScheme === true ? {} : colorScheme), + mode: scheme, + }), + }; + } } export default function createTheme( @@ -80,11 +37,6 @@ export default function createTheme( } = {}, ...args: object[] ): Theme { - if (options.customProperties === false) { - // @ts-expect-error `vars` can be undefined - return createThemeWithoutVars(options, ...args); - } - const { palette, colorSchemes: initialColorSchemes = !palette ? { light: true } : undefined, @@ -107,12 +59,34 @@ export default function createTheme( : undefined), }; + if (customProperties === false) { + // @ts-expect-error ignore mismatch types here + const theme = createThemeNoVars(options, ...args) as unknown as Theme; + if (!('colorSchemes' in options)) { + return theme; + } + + theme.colorSchemes = {}; + + if (theme.palette.mode === 'light') { + theme.colorSchemes = { light: { palette: theme.palette } as ColorSystem }; + attachColorScheme(theme, 'dark', colorSchemesInput.dark); + } + if (theme.palette.mode === 'dark') { + theme.colorSchemes = { dark: { palette: theme.palette } as ColorSystem }; + attachColorScheme(theme, 'light', colorSchemesInput.light); + } + + theme.defaultColorScheme = defaultColorSchemeInput; + return theme; + } + return createThemeWithVars( { ...rest, colorSchemes: colorSchemesInput, defaultColorScheme: defaultColorSchemeInput, - ...(typeof customProperties !== 'boolean' ? customProperties : undefined), + ...(typeof customProperties !== 'boolean' && customProperties), }, ...args, ); diff --git a/packages/mui-material/src/styles/createTheme/createThemeWithoutVars.d.ts b/packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts similarity index 53% rename from packages/mui-material/src/styles/createTheme/createThemeWithoutVars.d.ts rename to packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts index 8ed1df73eea338..0d4e1216e8874a 100644 --- a/packages/mui-material/src/styles/createTheme/createThemeWithoutVars.d.ts +++ b/packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts @@ -12,10 +12,37 @@ import { Shadows } from '../shadows'; import { Transitions, TransitionsOptions } from '../createTransitions'; import { ZIndex, ZIndexOptions } from '../zIndex'; import { Components } from '../components'; +import { + CssVarsPalette, + ColorSystemOptions, + ColorSystem, + ThemeVars, + SupportedColorScheme, +} from './createThemeWithVars'; + +/** + * To disable custom properties, use module augmentation + * + * @example + * declare module '@mui/material/styles' { + * interface CssThemeVariables { + * disabled: true; + * } + * } + */ +export interface CssThemeVariables {} + +type CssVarsOptions = CustomProperties extends { + disabled: true; +} + ? {} + : ColorSystemOptions; -export interface ThemeOptions extends Omit { +export interface ThemeOptions + extends Omit, + CssVarsOptions { mixins?: MixinsOptions; - components?: Components>; + components?: Components, 'components'>>; palette?: PaletteOptions; shadows?: Shadows; transitions?: TransitionsOptions; @@ -25,15 +52,15 @@ export interface ThemeOptions extends Omit { unstable_sxConfig?: SxConfig; } -interface BaseTheme extends SystemTheme { +interface BaseTheme extends SystemTheme { mixins: Mixins; - palette: Palette; + palette: Palette & (CustomProperties extends { disabled: true } ? {} : CssVarsPalette); shadows: Shadows; transitions: Transitions; typography: Typography; zIndex: ZIndex; unstable_strictMode?: boolean; - vars: undefined; + vars: CssThemeVariables extends { disabled: true } ? undefined : ThemeVars; } // shut off automatic exporting for the `BaseTheme` above @@ -42,8 +69,15 @@ export {}; /** * Our [TypeScript guide on theme customization](https://mui.com/material-ui/guides/typescript/#customization-of-theme) explains in detail how you would add custom properties. */ -export interface Theme extends BaseTheme { - defaultColorScheme: 'light' | 'dark'; +export interface Theme extends BaseTheme { + colorSchemes?: Partial< + Record< + SupportedColorScheme, + CustomProperties extends { disabled: true } ? { palette: Palette } : ColorSystem + > + >; + defaultColorScheme: SupportedColorScheme; + customProperties?: false; components?: Components; unstable_sx: (props: SxProps) => CSSObject; unstable_sxConfig: SxConfig; @@ -55,4 +89,4 @@ export interface Theme extends BaseTheme { * @param args Deep merge the arguments with the about to be returned theme. * @returns A complete, ready-to-use theme object. */ -export default function createThemeWithoutVars(options?: ThemeOptions, ...args: object[]): Theme; +export default function createThemeNoVars(options?: ThemeOptions, ...args: object[]): Theme; diff --git a/packages/mui-material/src/styles/createTheme/createThemeWithoutVars.js b/packages/mui-material/src/styles/createTheme/createThemeNoVars.js similarity index 97% rename from packages/mui-material/src/styles/createTheme/createThemeWithoutVars.js rename to packages/mui-material/src/styles/createTheme/createThemeNoVars.js index 27bffe5070cb70..8637b6ab669d81 100644 --- a/packages/mui-material/src/styles/createTheme/createThemeWithoutVars.js +++ b/packages/mui-material/src/styles/createTheme/createThemeNoVars.js @@ -12,7 +12,7 @@ import shadows from '../shadows'; import createTransitions from '../createTransitions'; import zIndex from '../zIndex'; -function createThemeWithoutVars(options = {}, ...args) { +function createThemeNoVars(options = {}, ...args) { const { breakpoints: breakpointsInput, mixins: mixinsInput = {}, @@ -122,4 +122,4 @@ function createThemeWithoutVars(options = {}, ...args) { return muiTheme; } -export default createThemeWithoutVars; +export default createThemeNoVars; diff --git a/packages/mui-material/src/styles/createTheme/createThemeWithVars.d.ts b/packages/mui-material/src/styles/createTheme/createThemeWithVars.d.ts index e02f54d4e7eeaf..c9cc55b25dd7c6 100644 --- a/packages/mui-material/src/styles/createTheme/createThemeWithVars.d.ts +++ b/packages/mui-material/src/styles/createTheme/createThemeWithVars.d.ts @@ -1,7 +1,7 @@ import { OverridableStringUnion } from '@mui/types'; import { SxConfig, SxProps, CSSObject, ApplyStyles } from '@mui/system'; import { ExtractTypographyTokens } from '@mui/system/cssVars'; -import { ThemeOptions, Theme } from './createThemeWithoutVars'; +import { ThemeOptions, Theme } from './createThemeNoVars'; import { Palette, PaletteOptions } from '../createPalette'; import { Shadows } from '../shadows'; import { ZIndex } from '../zIndex'; diff --git a/packages/mui-material/src/styles/createTheme/createThemeWithVars.js b/packages/mui-material/src/styles/createTheme/createThemeWithVars.js index 70c01e76b3caaf..015130c522df75 100644 --- a/packages/mui-material/src/styles/createTheme/createThemeWithVars.js +++ b/packages/mui-material/src/styles/createTheme/createThemeWithVars.js @@ -20,7 +20,7 @@ import { hslToRgb, } from '@mui/system/colorManipulator'; -import createThemeWithoutVars from './createThemeWithoutVars'; +import createThemeNoVars from './createThemeNoVars'; import defaultShouldSkipGeneratingVar from '../shouldSkipGeneratingVar'; import getOverlayAlpha from '../getOverlayAlpha'; import defaultGetSelector from '../createGetSelector'; @@ -113,7 +113,7 @@ function attachColorScheme(colorSchemes, scheme, restTheme, colorScheme) { } scheme = scheme === true ? {} : scheme; const mode = colorScheme === 'dark' ? 'dark' : 'light'; - const { palette, ...muiTheme } = createThemeWithoutVars({ + const { palette, ...muiTheme } = createThemeNoVars({ ...restTheme, palette: { mode, diff --git a/packages/mui-material/src/styles/createTheme/index.ts b/packages/mui-material/src/styles/createTheme/index.ts new file mode 100644 index 00000000000000..7a2d890e7d490a --- /dev/null +++ b/packages/mui-material/src/styles/createTheme/index.ts @@ -0,0 +1,2 @@ +export { default } from './createTheme'; +export type { CssThemeVariables, ThemeOptions, Theme } from './createThemeNoVars'; diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts b/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts index a0a5a44e84b6e6..b4eecc9c82816a 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts @@ -48,6 +48,7 @@ export interface CreateCssVarsProviderResult< theme?: Identify< Identifier, { + customProperties?: false; cssVarPrefix?: string; colorSchemes: Record>; colorSchemeSelector?: 'media' | 'class' | 'data' | string; diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.js b/packages/mui-system/src/cssVars/createCssVarsProvider.js index e8d62303bd8b79..aa2ae45597a11c 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.js +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.js @@ -83,7 +83,8 @@ export default function createCssVarsProvider(options) { const defaultMode = colorSchemes[defaultLightColorScheme] && colorSchemes[defaultDarkColorScheme] ? 'system' - : colorSchemes[restThemeProp.defaultColorScheme]?.palette?.mode; + : colorSchemes[restThemeProp.defaultColorScheme]?.palette?.mode || + restThemeProp.palette?.mode; // 1. Get the data about the `mode`, `colorScheme`, and setter functions. const { @@ -239,7 +240,11 @@ export default function createCssVarsProvider(options) { ); let shouldGenerateStyleSheet = true; - if (disableStyleSheetGeneration || (nested && upperTheme?.cssVarPrefix === cssVarPrefix)) { + if ( + disableStyleSheetGeneration || + restThemeProp.customProperties === false || + (nested && upperTheme?.cssVarPrefix === cssVarPrefix) + ) { shouldGenerateStyleSheet = false; } @@ -261,7 +266,7 @@ export default function createCssVarsProvider(options) { ); - if (nested) { + if (nested && restThemeProp.customProperties !== false) { return element; } From 3106aa9bd5497a2b2c1547bdae3ad5a6eedac409 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 30 Jul 2024 09:47:49 +0700 Subject: [PATCH 05/82] finish first step --- .../src/styles/ThemeProvider/ThemeProvider.tsx | 12 ++++++------ .../src/styles/createTheme/createTheme.test.ts | 8 ++++---- .../src/styles/createTheme/createTheme.ts | 8 ++++---- .../styles/createTheme/createThemeNoVars.d.ts | 16 ++++++++-------- .../src/cssVars/createCssVarsProvider.d.ts | 2 +- .../src/cssVars/createCssVarsProvider.js | 6 +++--- .../src/cssVars/useCurrentColorScheme.ts | 11 ++++++++++- 7 files changed, 36 insertions(+), 27 deletions(-) diff --git a/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx b/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx index 389844e8f3e025..7507de2d4c3455 100644 --- a/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx +++ b/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx @@ -7,30 +7,30 @@ export interface ThemeProviderProps { children?: React.ReactNode; theme: Partial | ((outerTheme: Theme) => Theme); /** - * [Configurable if `colorSchemes` is provided] + * [Configurable if `theme.colorSchemes` is provided] * The document used to perform `disableTransitionOnChange` feature * @default document */ documentNode?: Document | null; /** - * [Configurable if `colorSchemes` is provided] + * [Configurable if `theme.colorSchemes` is provided] * The node used to attach the color-scheme attribute * @default document */ colorSchemeNode?: Element | null; /** - * [Configurable if `colorSchemes` is provided] + * [Configurable if `theme.colorSchemes` is provided] * The window that attaches the 'storage' event listener * @default window */ storageWindow?: Window | null; /** - * [Configurable if `customProperties` is not `false`] + * [Configurable if `cssVariables` is not `false`] * If `true`, the provider creates its own context and generate stylesheet as if it is a root `CssVarsProvider`. */ disableNestedContext?: boolean; /** - * [Configurable if `customProperties` is not `false`] + * [Configurable if `cssVariables` is not `false`] * If `true`, the style sheet won't be generated. * * This is useful for controlling nested CssVarsProvider behavior. @@ -38,7 +38,7 @@ export interface ThemeProviderProps { */ disableStyleSheetGeneration?: boolean; /** - * [Configurable if `colorSchemes` is provided] + * [Configurable if `theme.colorSchemes` is provided] * Disable CSS transitions when switching between modes or color schemes * @default false */ diff --git a/packages/mui-material/src/styles/createTheme/createTheme.test.ts b/packages/mui-material/src/styles/createTheme/createTheme.test.ts index e0d97f17db1742..551bbb1dfee491 100644 --- a/packages/mui-material/src/styles/createTheme/createTheme.test.ts +++ b/packages/mui-material/src/styles/createTheme/createTheme.test.ts @@ -9,13 +9,13 @@ const darkPalette = createPalette({ mode: 'dark' }); describe('createTheme', () => { describe('Without custom properties', () => { it('should not have custom properties', () => { - const theme = createTheme({ customProperties: false }); - expect(theme.customProperties).to.equal(false); + const theme = createTheme({ cssVariables: false }); + expect(theme.cssVariables).to.equal(false); expect('vars' in theme).to.equal(false); }); it('color schemes dark: true', () => { - const theme = createTheme({ customProperties: false, colorSchemes: { dark: true } }); + const theme = createTheme({ cssVariables: false, colorSchemes: { dark: true } }); const { light, dark } = theme.colorSchemes || {}; expect(light?.palette.primary.main).to.deep.equal(lightPalette.primary.main); expect(dark?.palette.primary.main).to.deep.equal(darkPalette.primary.main); @@ -23,7 +23,7 @@ describe('createTheme', () => { it('color schemes light: true', () => { const theme = createTheme({ - customProperties: false, + cssVariables: false, colorSchemes: { light: true }, palette: { mode: 'dark' }, }); diff --git a/packages/mui-material/src/styles/createTheme/createTheme.ts b/packages/mui-material/src/styles/createTheme/createTheme.ts index da15155aa3b5b5..0aeb3f33d47918 100644 --- a/packages/mui-material/src/styles/createTheme/createTheme.ts +++ b/packages/mui-material/src/styles/createTheme/createTheme.ts @@ -25,7 +25,7 @@ function attachColorScheme( export default function createTheme( options: Omit & Pick & { - customProperties?: + cssVariables?: | boolean | Pick< CssVarsThemeOptions, @@ -41,7 +41,7 @@ export default function createTheme( palette, colorSchemes: initialColorSchemes = !palette ? { light: true } : undefined, defaultColorScheme: initialDefaultColorScheme = palette?.mode, - customProperties, + cssVariables, ...rest } = options; const defaultColorSchemeInput = initialDefaultColorScheme || 'light'; @@ -59,7 +59,7 @@ export default function createTheme( : undefined), }; - if (customProperties === false) { + if (cssVariables === false) { // @ts-expect-error ignore mismatch types here const theme = createThemeNoVars(options, ...args) as unknown as Theme; if (!('colorSchemes' in options)) { @@ -86,7 +86,7 @@ export default function createTheme( ...rest, colorSchemes: colorSchemesInput, defaultColorScheme: defaultColorSchemeInput, - ...(typeof customProperties !== 'boolean' && customProperties), + ...(typeof cssVariables !== 'boolean' && cssVariables), }, ...args, ); diff --git a/packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts b/packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts index 0d4e1216e8874a..9b37f6f48e68f1 100644 --- a/packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts +++ b/packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts @@ -32,17 +32,17 @@ import { */ export interface CssThemeVariables {} -type CssVarsOptions = CustomProperties extends { +type CssVarsOptions = CssVariables extends { disabled: true; } ? {} : ColorSystemOptions; -export interface ThemeOptions +export interface ThemeOptions extends Omit, CssVarsOptions { mixins?: MixinsOptions; - components?: Components, 'components'>>; + components?: Components, 'components'>>; palette?: PaletteOptions; shadows?: Shadows; transitions?: TransitionsOptions; @@ -52,9 +52,9 @@ export interface ThemeOptions unstable_sxConfig?: SxConfig; } -interface BaseTheme extends SystemTheme { +interface BaseTheme extends SystemTheme { mixins: Mixins; - palette: Palette & (CustomProperties extends { disabled: true } ? {} : CssVarsPalette); + palette: Palette & (CssVariables extends { disabled: true } ? {} : CssVarsPalette); shadows: Shadows; transitions: Transitions; typography: Typography; @@ -69,15 +69,15 @@ export {}; /** * Our [TypeScript guide on theme customization](https://mui.com/material-ui/guides/typescript/#customization-of-theme) explains in detail how you would add custom properties. */ -export interface Theme extends BaseTheme { +export interface Theme extends BaseTheme { colorSchemes?: Partial< Record< SupportedColorScheme, - CustomProperties extends { disabled: true } ? { palette: Palette } : ColorSystem + CssVariables extends { disabled: true } ? { palette: Palette } : ColorSystem > >; defaultColorScheme: SupportedColorScheme; - customProperties?: false; + cssVariables?: false; components?: Components; unstable_sx: (props: SxProps) => CSSObject; unstable_sxConfig: SxConfig; diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts b/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts index b4eecc9c82816a..8b79fbebd43f6c 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts @@ -48,7 +48,7 @@ export interface CreateCssVarsProviderResult< theme?: Identify< Identifier, { - customProperties?: false; + cssVariables?: false; cssVarPrefix?: string; colorSchemes: Record>; colorSchemeSelector?: 'media' | 'class' | 'data' | string; diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.js b/packages/mui-system/src/cssVars/createCssVarsProvider.js index aa2ae45597a11c..8f0fea7b81e01b 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.js +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.js @@ -113,7 +113,7 @@ export default function createCssVarsProvider(options) { colorScheme = ctx.colorScheme; } - // `colorScheme` is undefined on the server + // `colorScheme` is undefined on the server and hydration phase const calculatedColorScheme = colorScheme || restThemeProp.defaultColorScheme; // 2. get the `vars` object that refers to the CSS custom properties @@ -242,7 +242,7 @@ export default function createCssVarsProvider(options) { let shouldGenerateStyleSheet = true; if ( disableStyleSheetGeneration || - restThemeProp.customProperties === false || + restThemeProp.cssVariables === false || (nested && upperTheme?.cssVarPrefix === cssVarPrefix) ) { shouldGenerateStyleSheet = false; @@ -266,7 +266,7 @@ export default function createCssVarsProvider(options) { ); - if (nested && restThemeProp.customProperties !== false) { + if (nested && restThemeProp.cssVariables !== false) { return element; } diff --git a/packages/mui-system/src/cssVars/useCurrentColorScheme.ts b/packages/mui-system/src/cssVars/useCurrentColorScheme.ts index b1b0683ed1c00f..1c21e187d46c40 100644 --- a/packages/mui-system/src/cssVars/useCurrentColorScheme.ts +++ b/packages/mui-system/src/cssVars/useCurrentColorScheme.ts @@ -150,6 +150,13 @@ export default function useCurrentColorScheme; }); + // This could be improved with `React.useSyncExternalStore` in the future. + const [, setHasMounted] = React.useState(false); + const hasMounted = React.useRef(false); + React.useEffect(() => { + setHasMounted(true); // to rerender the component after hydration + hasMounted.current = true; + }, []); const colorScheme = getColorScheme(state); @@ -332,7 +339,9 @@ export default function useCurrentColorScheme Date: Tue, 30 Jul 2024 10:06:51 +0700 Subject: [PATCH 06/82] move some props to ThemeProviderCssVariablesProps --- .../styles/ThemeProvider/ThemeProvider.tsx | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx b/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx index 7507de2d4c3455..c50dd14f902e9f 100644 --- a/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx +++ b/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx @@ -2,43 +2,43 @@ import * as React from 'react'; import { DefaultTheme } from '@mui/system'; import ThemeProviderNoVars from './ThemeProviderNoVars'; import { CssVarsProvider } from './ThemeProviderWithVars'; +import { CssThemeVariables } from '../createTheme/createThemeNoVars'; -export interface ThemeProviderProps { +type ThemeProviderCssVariablesProps = CssThemeVariables extends { disabled: true } + ? {} + : { + /** + * The node for attaching the `theme.colorSchemeSelector`. + * @default document + */ + colorSchemeNode?: Element | null; + /** + * If `true`, the provider creates its own context and generate stylesheet as if it is a root `ThemeProvider`. + */ + disableNestedContext?: boolean; + /** + * If `true`, the style sheet for CSS theme variables won't be generated. + * + * This is useful for controlling nested ThemeProvider behavior. + * @default false + */ + disableStyleSheetGeneration?: boolean; + }; + +export interface ThemeProviderProps extends ThemeProviderCssVariablesProps { children?: React.ReactNode; theme: Partial | ((outerTheme: Theme) => Theme); /** - * [Configurable if `theme.colorSchemes` is provided] * The document used to perform `disableTransitionOnChange` feature * @default document */ documentNode?: Document | null; /** - * [Configurable if `theme.colorSchemes` is provided] - * The node used to attach the color-scheme attribute - * @default document - */ - colorSchemeNode?: Element | null; - /** - * [Configurable if `theme.colorSchemes` is provided] * The window that attaches the 'storage' event listener * @default window */ storageWindow?: Window | null; /** - * [Configurable if `cssVariables` is not `false`] - * If `true`, the provider creates its own context and generate stylesheet as if it is a root `CssVarsProvider`. - */ - disableNestedContext?: boolean; - /** - * [Configurable if `cssVariables` is not `false`] - * If `true`, the style sheet won't be generated. - * - * This is useful for controlling nested CssVarsProvider behavior. - * @default false - */ - disableStyleSheetGeneration?: boolean; - /** - * [Configurable if `theme.colorSchemes` is provided] * Disable CSS transitions when switching between modes or color schemes * @default false */ From e7bf7dc8bc53210fa17d09405a1cd97af996abd8 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 30 Jul 2024 10:59:55 +0700 Subject: [PATCH 07/82] remove old createTheme and extendTheme --- .../src/styles/CssVarsProvider.tsx | 7 +- .../mui-material/src/styles/createTheme.d.ts | 62 --- .../mui-material/src/styles/createTheme.js | 144 ----- .../src/styles/createTheme.test.js | 51 ++ .../styles/createTheme/createTheme.test.ts | 62 --- .../src/styles/createTheme/createTheme.ts | 6 + .../styles/createTheme/createThemeNoVars.d.ts | 10 +- .../styles/createTheme/createThemeNoVars.js | 19 + .../createTheme/createThemeWithVars.d.ts | 2 +- .../src/styles/createTheme/index.ts | 1 + .../mui-material/src/styles/extendTheme.d.ts | 476 ---------------- .../mui-material/src/styles/extendTheme.js | 514 ------------------ packages/mui-material/src/styles/index.d.ts | 4 +- packages/mui-material/src/styles/index.js | 2 +- .../src/themeCssVarsAugmentation/index.d.ts | 29 +- 15 files changed, 98 insertions(+), 1291 deletions(-) delete mode 100644 packages/mui-material/src/styles/createTheme.d.ts delete mode 100644 packages/mui-material/src/styles/createTheme.js delete mode 100644 packages/mui-material/src/styles/createTheme/createTheme.test.ts delete mode 100644 packages/mui-material/src/styles/extendTheme.d.ts delete mode 100644 packages/mui-material/src/styles/extendTheme.js diff --git a/packages/mui-material/src/styles/CssVarsProvider.tsx b/packages/mui-material/src/styles/CssVarsProvider.tsx index 443c2bcf7099df..07b20ed8129b79 100644 --- a/packages/mui-material/src/styles/CssVarsProvider.tsx +++ b/packages/mui-material/src/styles/CssVarsProvider.tsx @@ -2,7 +2,10 @@ import * as React from 'react'; import { unstable_createCssVarsProvider as createCssVarsProvider, SxProps } from '@mui/system'; import styleFunctionSx from '@mui/system/styleFunctionSx'; -import extendTheme, { SupportedColorScheme, CssVarsTheme } from './extendTheme'; +import createThemeWithVars, { + SupportedColorScheme, + CssVarsTheme, +} from './createTheme/createThemeWithVars'; import createTypography from './createTypography'; import THEME_ID from './identifier'; import { defaultConfig } from '../InitColorSchemeScript/InitColorSchemeScript'; @@ -13,7 +16,7 @@ const { getInitColorSchemeScript: deprecatedGetInitColorSchemeScript, } = createCssVarsProvider({ themeId: THEME_ID, - theme: extendTheme, + theme: createThemeWithVars, colorSchemeStorageKey: defaultConfig.colorSchemeStorageKey, modeStorageKey: defaultConfig.modeStorageKey, defaultColorScheme: { diff --git a/packages/mui-material/src/styles/createTheme.d.ts b/packages/mui-material/src/styles/createTheme.d.ts deleted file mode 100644 index ef8cb895b1fb14..00000000000000 --- a/packages/mui-material/src/styles/createTheme.d.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { - ThemeOptions as SystemThemeOptions, - Theme as SystemTheme, - SxProps, - CSSObject, - SxConfig, -} from '@mui/system'; -import { Mixins, MixinsOptions } from './createMixins'; -import { Palette, PaletteOptions } from './createPalette'; -import { Typography, TypographyOptions } from './createTypography'; -import { Shadows } from './shadows'; -import { Transitions, TransitionsOptions } from './createTransitions'; -import { ZIndex, ZIndexOptions } from './zIndex'; -import { Components } from './components'; - -export interface ThemeOptions extends Omit { - mixins?: MixinsOptions; - components?: Components>; - palette?: PaletteOptions; - shadows?: Shadows; - transitions?: TransitionsOptions; - typography?: TypographyOptions | ((palette: Palette) => TypographyOptions); - zIndex?: ZIndexOptions; - unstable_strictMode?: boolean; - unstable_sxConfig?: SxConfig; -} - -interface BaseTheme extends SystemTheme { - mixins: Mixins; - palette: Palette; - shadows: Shadows; - transitions: Transitions; - typography: Typography; - zIndex: ZIndex; - unstable_strictMode?: boolean; -} - -// shut off automatic exporting for the `BaseTheme` above -export {}; - -/** - * Our [TypeScript guide on theme customization](https://mui.com/material-ui/guides/typescript/#customization-of-theme) explains in detail how you would add custom properties. - */ -export interface Theme extends BaseTheme { - components?: Components; - unstable_sx: (props: SxProps) => CSSObject; - unstable_sxConfig: SxConfig; -} - -/** - * @deprecated - * Use `import { createTheme } from '@mui/material/styles'` instead. - */ -export function createMuiTheme(options?: ThemeOptions, ...args: object[]): Theme; - -/** - * Generate a theme base on the options received. - * @param options Takes an incomplete theme object and adds the missing parts. - * @param args Deep merge the arguments with the about to be returned theme. - * @returns A complete, ready-to-use theme object. - */ -export default function createTheme(options?: ThemeOptions, ...args: object[]): Theme; diff --git a/packages/mui-material/src/styles/createTheme.js b/packages/mui-material/src/styles/createTheme.js deleted file mode 100644 index c2b78248e2c2fa..00000000000000 --- a/packages/mui-material/src/styles/createTheme.js +++ /dev/null @@ -1,144 +0,0 @@ -import deepmerge from '@mui/utils/deepmerge'; -import styleFunctionSx, { - unstable_defaultSxConfig as defaultSxConfig, -} from '@mui/system/styleFunctionSx'; -import systemCreateTheme from '@mui/system/createTheme'; -import MuiError from '@mui/internal-babel-macros/MuiError.macro'; -import generateUtilityClass from '@mui/utils/generateUtilityClass'; -import createMixins from './createMixins'; -import createPalette from './createPalette'; -import createTypography from './createTypography'; -import shadows from './shadows'; -import createTransitions from './createTransitions'; -import zIndex from './zIndex'; - -function createTheme(options = {}, ...args) { - const { - breakpoints: breakpointsInput, - mixins: mixinsInput = {}, - spacing: spacingInput, - palette: paletteInput = {}, - transitions: transitionsInput = {}, - typography: typographyInput = {}, - shape: shapeInput, - ...other - } = options; - - if (options.vars) { - throw new MuiError( - 'MUI: `vars` is a private field used for CSS variables support.\n' + - 'Please use another name.', - ); - } - - const palette = createPalette(paletteInput); - const systemTheme = systemCreateTheme(options); - - let muiTheme = deepmerge(systemTheme, { - mixins: createMixins(systemTheme.breakpoints, mixinsInput), - palette, - // Don't use [...shadows] until you've verified its transpiled code is not invoking the iterator protocol. - shadows: shadows.slice(), - typography: createTypography(palette, typographyInput), - transitions: createTransitions(transitionsInput), - zIndex: { ...zIndex }, - }); - - muiTheme = deepmerge(muiTheme, other); - muiTheme = args.reduce((acc, argument) => deepmerge(acc, argument), muiTheme); - - if (process.env.NODE_ENV !== 'production') { - // TODO v6: Refactor to use globalStateClassesMapping from @mui/utils once `readOnly` state class is used in Rating component. - const stateClasses = [ - 'active', - 'checked', - 'completed', - 'disabled', - 'error', - 'expanded', - 'focused', - 'focusVisible', - 'required', - 'selected', - ]; - - const traverse = (node, component) => { - let key; - - // eslint-disable-next-line guard-for-in - for (key in node) { - const child = node[key]; - if (stateClasses.indexOf(key) !== -1 && Object.keys(child).length > 0) { - if (process.env.NODE_ENV !== 'production') { - const stateClass = generateUtilityClass('', key); - console.error( - [ - `MUI: The \`${component}\` component increases ` + - `the CSS specificity of the \`${key}\` internal state.`, - 'You can not override it like this: ', - JSON.stringify(node, null, 2), - '', - `Instead, you need to use the '&.${stateClass}' syntax:`, - JSON.stringify( - { - root: { - [`&.${stateClass}`]: child, - }, - }, - null, - 2, - ), - '', - 'https://mui.com/r/state-classes-guide', - ].join('\n'), - ); - } - // Remove the style to prevent global conflicts. - node[key] = {}; - } - } - }; - - Object.keys(muiTheme.components).forEach((component) => { - const styleOverrides = muiTheme.components[component].styleOverrides; - - if (styleOverrides && component.indexOf('Mui') === 0) { - traverse(styleOverrides, component); - } - }); - } - - muiTheme.unstable_sxConfig = { - ...defaultSxConfig, - ...other?.unstable_sxConfig, - }; - muiTheme.unstable_sx = function sx(props) { - return styleFunctionSx({ - sx: props, - theme: this, - }); - }; - - return muiTheme; -} - -let warnedOnce = false; - -export function createMuiTheme(...args) { - if (process.env.NODE_ENV !== 'production') { - if (!warnedOnce) { - warnedOnce = true; - console.error( - [ - 'MUI: the createMuiTheme function was renamed to createTheme.', - '', - "You should use `import { createTheme } from '@mui/material/styles'`", - ].join('\n'), - ); - } - } - - return createTheme(...args); -} - -export default createTheme; diff --git a/packages/mui-material/src/styles/createTheme.test.js b/packages/mui-material/src/styles/createTheme.test.js index 03c0472c15b4a6..eba357d10d194f 100644 --- a/packages/mui-material/src/styles/createTheme.test.js +++ b/packages/mui-material/src/styles/createTheme.test.js @@ -5,6 +5,10 @@ import Button from '@mui/material/Button'; import Box from '@mui/material/Box'; import { ThemeProvider, createTheme, styled } from '@mui/material/styles'; import { deepOrange, green } from '@mui/material/colors'; +import createPalette from './createPalette'; + +const lightPalette = createPalette({ mode: 'light' }); +const darkPalette = createPalette({ mode: 'dark' }); describe('createTheme', () => { const { render } = createRenderer(); @@ -19,8 +23,55 @@ describe('createTheme', () => { const theme = createTheme({ palette: { primary: { main: deepOrange[500] }, secondary: { main: green.A400 } }, }); + expect(theme.defaultColorScheme).to.equal('light'); expect(theme.palette.primary.main).to.equal(deepOrange[500]); expect(theme.palette.secondary.main).to.equal(green.A400); + expect(theme.vars.palette.primary.main).to.equal( + `var(--mui-palette-primary-main, ${deepOrange[500]})`, + ); + expect(theme.vars.palette.secondary.main).to.equal( + `var(--mui-palette-secondary-main, ${green.A400})`, + ); + }); + + it('should have a dark as a default colorScheme if only `palette` is provided', () => { + const theme = createTheme({ + palette: { + mode: 'dark', + primary: { main: deepOrange[500] }, + }, + }); + expect(theme.defaultColorScheme).to.equal('dark'); + expect(theme.palette.primary.main).to.equal(deepOrange[500]); + expect(theme.vars.palette.primary.main).to.equal( + `var(--mui-palette-primary-main, ${deepOrange[500]})`, + ); + }); + + describe('Without custom properties', () => { + it('should not have custom properties', () => { + const theme = createTheme({ cssVariables: false }); + expect(theme.cssVariables).to.equal(false); + expect('vars' in theme).to.equal(false); + }); + + it('color schemes dark: true', () => { + const theme = createTheme({ cssVariables: false, colorSchemes: { dark: true } }); + const { light, dark } = theme.colorSchemes || {}; + expect(light?.palette.primary.main).to.deep.equal(lightPalette.primary.main); + expect(dark?.palette.primary.main).to.deep.equal(darkPalette.primary.main); + }); + + it('color schemes light: true', () => { + const theme = createTheme({ + cssVariables: false, + colorSchemes: { light: true }, + palette: { mode: 'dark' }, + }); + const { light, dark } = theme.colorSchemes || {}; + expect(light?.palette.primary.main).to.deep.equal(lightPalette.primary.main); + expect(dark?.palette.primary.main).to.deep.equal(darkPalette.primary.main); + }); }); describe('transitions', () => { diff --git a/packages/mui-material/src/styles/createTheme/createTheme.test.ts b/packages/mui-material/src/styles/createTheme/createTheme.test.ts deleted file mode 100644 index 551bbb1dfee491..00000000000000 --- a/packages/mui-material/src/styles/createTheme/createTheme.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { expect } from 'chai'; -import { deepOrange } from '@mui/material/colors'; -import createTheme from './createTheme'; -import createPalette from '../createPalette'; - -const lightPalette = createPalette({ mode: 'light' }); -const darkPalette = createPalette({ mode: 'dark' }); - -describe('createTheme', () => { - describe('Without custom properties', () => { - it('should not have custom properties', () => { - const theme = createTheme({ cssVariables: false }); - expect(theme.cssVariables).to.equal(false); - expect('vars' in theme).to.equal(false); - }); - - it('color schemes dark: true', () => { - const theme = createTheme({ cssVariables: false, colorSchemes: { dark: true } }); - const { light, dark } = theme.colorSchemes || {}; - expect(light?.palette.primary.main).to.deep.equal(lightPalette.primary.main); - expect(dark?.palette.primary.main).to.deep.equal(darkPalette.primary.main); - }); - - it('color schemes light: true', () => { - const theme = createTheme({ - cssVariables: false, - colorSchemes: { light: true }, - palette: { mode: 'dark' }, - }); - const { light, dark } = theme.colorSchemes || {}; - expect(light?.palette.primary.main).to.deep.equal(lightPalette.primary.main); - expect(dark?.palette.primary.main).to.deep.equal(darkPalette.primary.main); - }); - }); - - it('should have a light as a default colorScheme if only `palette` is provided', () => { - const theme = createTheme({ - palette: { - primary: { main: deepOrange[500] }, - }, - }); - expect(theme.defaultColorScheme).to.equal('light'); - expect(theme.palette.primary.main).to.equal(deepOrange[500]); - expect(theme.vars.palette.primary.main).to.equal( - `var(--mui-palette-primary-main, ${deepOrange[500]})`, - ); - }); - - it('should have a dark as a default colorScheme if only `palette` is provided', () => { - const theme = createTheme({ - palette: { - mode: 'dark', - primary: { main: deepOrange[500] }, - }, - }); - expect(theme.defaultColorScheme).to.equal('dark'); - expect(theme.palette.primary.main).to.equal(deepOrange[500]); - expect(theme.vars.palette.primary.main).to.equal( - `var(--mui-palette-primary-main, ${deepOrange[500]})`, - ); - }); -}); diff --git a/packages/mui-material/src/styles/createTheme/createTheme.ts b/packages/mui-material/src/styles/createTheme/createTheme.ts index 0aeb3f33d47918..78de7d6595cc15 100644 --- a/packages/mui-material/src/styles/createTheme/createTheme.ts +++ b/packages/mui-material/src/styles/createTheme/createTheme.ts @@ -22,6 +22,12 @@ function attachColorScheme( } } +/** + * Generate a theme base on the options received. + * @param options Takes an incomplete theme object and adds the missing parts. + * @param args Deep merge the arguments with the about to be returned theme. + * @returns A complete, ready-to-use theme object. + */ export default function createTheme( options: Omit & Pick & { diff --git a/packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts b/packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts index 9b37f6f48e68f1..df169b02330412 100644 --- a/packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts +++ b/packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts @@ -4,6 +4,7 @@ import { SxProps, CSSObject, SxConfig, + ApplyStyles, } from '@mui/system'; import { Mixins, MixinsOptions } from '../createMixins'; import { Palette, PaletteOptions } from '../createPalette'; @@ -69,7 +70,7 @@ export {}; /** * Our [TypeScript guide on theme customization](https://mui.com/material-ui/guides/typescript/#customization-of-theme) explains in detail how you would add custom properties. */ -export interface Theme extends BaseTheme { +export interface Theme extends BaseTheme { colorSchemes?: Partial< Record< SupportedColorScheme, @@ -81,8 +82,15 @@ export interface Theme extends BaseTheme { components?: Components; unstable_sx: (props: SxProps) => CSSObject; unstable_sxConfig: SxConfig; + applyStyles: ApplyStyles; } +/** + * @deprecated + * Use `import { createTheme } from '@mui/material/styles'` instead. + */ +export function createMuiTheme(options?: ThemeOptions, ...args: object[]): Theme; + /** * Generate a theme base on the options received. * @param options Takes an incomplete theme object and adds the missing parts. diff --git a/packages/mui-material/src/styles/createTheme/createThemeNoVars.js b/packages/mui-material/src/styles/createTheme/createThemeNoVars.js index 8637b6ab669d81..13b84b1877951a 100644 --- a/packages/mui-material/src/styles/createTheme/createThemeNoVars.js +++ b/packages/mui-material/src/styles/createTheme/createThemeNoVars.js @@ -122,4 +122,23 @@ function createThemeNoVars(options = {}, ...args) { return muiTheme; } +let warnedOnce = false; + +export function createMuiTheme(...args) { + if (process.env.NODE_ENV !== 'production') { + if (!warnedOnce) { + warnedOnce = true; + console.error( + [ + 'MUI: the createMuiTheme function was renamed to createTheme.', + '', + "You should use `import { createTheme } from '@mui/material/styles'`", + ].join('\n'), + ); + } + } + + return createThemeNoVars(...args); +} + export default createThemeNoVars; diff --git a/packages/mui-material/src/styles/createTheme/createThemeWithVars.d.ts b/packages/mui-material/src/styles/createTheme/createThemeWithVars.d.ts index c9cc55b25dd7c6..ce6885ad9a38c3 100644 --- a/packages/mui-material/src/styles/createTheme/createThemeWithVars.d.ts +++ b/packages/mui-material/src/styles/createTheme/createThemeWithVars.d.ts @@ -430,7 +430,7 @@ export type ThemeCssVar = OverridableStringUnion< * Theme properties generated by extendTheme and CssVarsProvider */ export interface CssVarsTheme extends ColorSystem { - colorSchemes: Record; + colorSchemes: Partial>; colorSchemeSelector: 'media' | 'class' | 'data' | string; cssVarPrefix: string; defaultColorScheme: SupportedColorScheme; diff --git a/packages/mui-material/src/styles/createTheme/index.ts b/packages/mui-material/src/styles/createTheme/index.ts index 7a2d890e7d490a..1271ad03e2c19f 100644 --- a/packages/mui-material/src/styles/createTheme/index.ts +++ b/packages/mui-material/src/styles/createTheme/index.ts @@ -1,2 +1,3 @@ export { default } from './createTheme'; +export { createMuiTheme } from './createThemeNoVars'; export type { CssThemeVariables, ThemeOptions, Theme } from './createThemeNoVars'; diff --git a/packages/mui-material/src/styles/extendTheme.d.ts b/packages/mui-material/src/styles/extendTheme.d.ts deleted file mode 100644 index ceec776d05b024..00000000000000 --- a/packages/mui-material/src/styles/extendTheme.d.ts +++ /dev/null @@ -1,476 +0,0 @@ -import { OverridableStringUnion } from '@mui/types'; -import { SxConfig, SxProps, CSSObject, ApplyStyles } from '@mui/system'; -import { ExtractTypographyTokens } from '@mui/system/cssVars'; -import { ThemeOptions, Theme } from './createTheme'; -import { Palette, PaletteOptions } from './createPalette'; -import { Shadows } from './shadows'; -import { ZIndex } from './zIndex'; -import { Components } from './components'; - -/** - * default MD color-schemes - */ -export type DefaultColorScheme = 'light' | 'dark'; - -/** - * The application can add more color-scheme by extending this interface via module augmentation - * - * Ex. - * declare module @mui/material/styles { - * interface ColorSchemeOverrides { - * foo: true; - * } - * } - * - * // SupportedColorScheme = 'light' | 'dark' | 'foo'; - */ -export interface ColorSchemeOverrides {} -export type ExtendedColorScheme = OverridableStringUnion; - -/** - * All color-schemes that the application has - */ -export type SupportedColorScheme = DefaultColorScheme | ExtendedColorScheme; - -export interface Opacity { - inputPlaceholder: number; - inputUnderline: number; - switchTrackDisabled: number; - switchTrack: number; -} - -export type Overlays = [ - string | undefined, - string | undefined, - string | undefined, - string | undefined, - string | undefined, - string | undefined, - string | undefined, - string | undefined, - string | undefined, - string | undefined, - string | undefined, - string | undefined, - string | undefined, - string | undefined, - string | undefined, - string | undefined, - string | undefined, - string | undefined, - string | undefined, - string | undefined, - string | undefined, - string | undefined, - string | undefined, - string | undefined, - string | undefined, -]; - -export interface PaletteBackgroundChannel { - defaultChannel: string; - paperChannel: string; -} - -export interface PaletteCommonChannel { - background: string; - backgroundChannel: string; - onBackground: string; - onBackgroundChannel: string; -} - -export interface PaletteColorChannel { - mainChannel: string; - lightChannel: string; - darkChannel: string; - contrastTextChannel: string; -} - -export interface PaletteActionChannel { - activeChannel: string; - selectedChannel: string; -} - -export interface PaletteTextChannel { - primaryChannel: string; - secondaryChannel: string; -} - -export interface PaletteAlert { - errorColor: string; - infoColor: string; - successColor: string; - warningColor: string; - errorFilledBg: string; - infoFilledBg: string; - successFilledBg: string; - warningFilledBg: string; - errorFilledColor: string; - infoFilledColor: string; - successFilledColor: string; - warningFilledColor: string; - errorStandardBg: string; - infoStandardBg: string; - successStandardBg: string; - warningStandardBg: string; - errorIconColor: string; - infoIconColor: string; - successIconColor: string; - warningIconColor: string; -} - -export interface PaletteAppBar { - defaultBg: string; - darkBg: string; - darkColor: string; -} - -export interface PaletteAvatar { - defaultBg: string; -} - -export interface PaletteButton { - inheritContainedBg: string; - inheritContainedHoverBg: string; -} - -export interface PaletteChip { - defaultBorder: string; - defaultAvatarColor: string; - defaultIconColor: string; -} - -export interface PaletteFilledInput { - bg: string; - hoverBg: string; - disabledBg: string; -} - -export interface PaletteLinearProgress { - primaryBg: string; - secondaryBg: string; - errorBg: string; - infoBg: string; - successBg: string; - warningBg: string; -} - -export interface PaletteSkeleton { - bg: string; -} - -export interface PaletteSlider { - primaryTrack: string; - secondaryTrack: string; - errorTrack: string; - infoTrack: string; - successTrack: string; - warningTrack: string; -} - -export interface PaletteSnackbarContent { - bg: string; - color: string; -} - -export interface PaletteSpeedDialAction { - fabHoverBg: string; -} - -export interface PaletteStepConnector { - border: string; -} - -export interface PaletteStepContent { - border: string; -} - -export interface PaletteSwitch { - defaultColor: string; - defaultDisabledColor: string; - primaryDisabledColor: string; - secondaryDisabledColor: string; - errorDisabledColor: string; - infoDisabledColor: string; - successDisabledColor: string; - warningDisabledColor: string; -} - -export interface PaletteTableCell { - border: string; -} - -export interface PaletteTooltip { - bg: string; -} - -// The Palette should be sync with `../themeCssVarsAugmentation/index.d.ts` -export interface ColorSystemOptions { - palette?: PaletteOptions & { - background?: Partial; - common?: Partial; - primary?: Partial; - secondary?: Partial; - error?: Partial; - info?: Partial; - success?: Partial; - text?: Partial; - dividerChannel?: Partial; - action?: Partial; - Alert?: Partial; - AppBar?: Partial; - Avatar?: Partial; - Button?: Partial; - Chip?: Partial; - FilledInput?: Partial; - LinearProgress?: Partial; - Skeleton?: Partial; - Slider?: Partial; - SnackbarContent?: Partial; - SpeedDialAction?: Partial; - StepConnector?: Partial; - StepContent?: Partial; - Switch?: Partial; - TableCell?: Partial; - Tooltip?: Partial; - }; - opacity?: Partial; - overlays?: Overlays; -} - -export interface CssVarsPalette { - colorScheme: SupportedColorScheme; // TODO: remove - common: PaletteCommonChannel; - primary: PaletteColorChannel; - secondary: PaletteColorChannel; - error: PaletteColorChannel; - info: PaletteColorChannel; - success: PaletteColorChannel; - warning: PaletteColorChannel; - text: PaletteTextChannel; - background: PaletteBackgroundChannel; - dividerChannel: string; - action: PaletteActionChannel; - Alert: PaletteAlert; - AppBar: PaletteAppBar; - Avatar: PaletteAvatar; - Button: PaletteButton; - Chip: PaletteChip; - FilledInput: PaletteFilledInput; - LinearProgress: PaletteLinearProgress; - Skeleton: PaletteSkeleton; - Slider: PaletteSlider; - SnackbarContent: PaletteSnackbarContent; - SpeedDialAction: PaletteSpeedDialAction; - StepConnector: PaletteStepConnector; - StepContent: PaletteStepContent; - Switch: PaletteSwitch; - TableCell: PaletteTableCell; - Tooltip: PaletteTooltip; -} - -export interface ColorSystem { - palette: Palette & CssVarsPalette; - opacity: Opacity; - overlays: Overlays; -} - -export interface CssVarsThemeOptions extends Omit { - /** - * @default 'light' - */ - defaultColorScheme?: SupportedColorScheme; - /** - * Prefix of the generated CSS variables - * @default 'mui' - */ - cssVarPrefix?: string; - /** - * Theme components - */ - components?: Components & CssVarsTheme>; - /** - * Color schemes configuration - */ - colorSchemes?: Partial> & - (ExtendedColorScheme extends string ? Record : {}); - /** - * The strategy to generate CSS variables - * - * @example 'media' - * Generate CSS variables using [prefers-color-scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) - * - * @example '.mode-%s' - * Generate CSS variables within a class .mode-light, .mode-dark - * - * @example '[data-mode-%s]' - * Generate CSS variables within a data attribute [data-mode-light], [data-mode-dark] - */ - colorSchemeSelector?: 'media' | 'class' | 'data' | string; - /** - * If `true`, the CSS color-scheme will not be set. - * https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme - * @default false - */ - disableCssColorScheme?: boolean; - /** - * A function to determine if the key, value should be attached as CSS Variable - * `keys` is an array that represents the object path keys. - * Ex, if the theme is { foo: { bar: 'var(--test)' } } - * then, keys = ['foo', 'bar'] - * value = 'var(--test)' - */ - shouldSkipGeneratingVar?: (keys: string[], value: string | number) => boolean; -} - -// should not include keys defined in `shouldSkipGeneratingVar` and have value typeof function -export interface ThemeVars { - font: ExtractTypographyTokens; - palette: Omit< - ColorSystem['palette'], - | 'colorScheme' - | 'mode' - | 'contrastThreshold' - | 'tonalOffset' - | 'getContrastText' - | 'augmentColor' - >; - opacity: Opacity; - overlays: Overlays; - shadows: Shadows; - shape: Theme['shape']; - spacing: string; - zIndex: ZIndex; -} - -type Split = K extends string | number - ? { [k in K]: Exclude } - : never; - -type ConcatDeep = - T extends Record - ? keyof T extends string | number - ? V extends string | number - ? keyof T - : keyof V extends string | number - ? `${keyof T}-${ConcatDeep>}` - : never - : never - : never; - -/** - * Does not work for these cases: - * - { borderRadius: string | number } // the value can't be a union - * - { shadows: [string, string, ..., string] } // the value can't be an array - */ -type NormalizeVars = ConcatDeep>; - -// shut off automatic exporting for the Generics above -export {}; - -export interface ThemeCssVarOverrides {} - -export type ThemeCssVar = OverridableStringUnion< - | NormalizeVars> - | 'shape-borderRadius' - | 'shadows-0' - | 'shadows-1' - | 'shadows-2' - | 'shadows-3' - | 'shadows-4' - | 'shadows-5' - | 'shadows-6' - | 'shadows-7' - | 'shadows-8' - | 'shadows-9' - | 'shadows-10' - | 'shadows-11' - | 'shadows-12' - | 'shadows-13' - | 'shadows-14' - | 'shadows-15' - | 'shadows-16' - | 'shadows-17' - | 'shadows-18' - | 'shadows-19' - | 'shadows-20' - | 'shadows-21' - | 'shadows-22' - | 'shadows-23' - | 'shadows-24' - | 'overlays-0' - | 'overlays-1' - | 'overlays-2' - | 'overlays-3' - | 'overlays-4' - | 'overlays-5' - | 'overlays-6' - | 'overlays-7' - | 'overlays-8' - | 'overlays-9' - | 'overlays-10' - | 'overlays-11' - | 'overlays-12' - | 'overlays-13' - | 'overlays-14' - | 'overlays-15' - | 'overlays-16' - | 'overlays-17' - | 'overlays-18' - | 'overlays-19' - | 'overlays-20' - | 'overlays-21' - | 'overlays-22' - | 'overlays-23' - | 'overlays-24', - ThemeCssVarOverrides ->; - -/** - * Theme properties generated by extendTheme and CssVarsProvider - */ -export interface CssVarsTheme extends ColorSystem { - colorSchemes: Record; - colorSchemeSelector: 'media' | 'class' | 'data' | string; - cssVarPrefix: string; - defaultColorScheme: SupportedColorScheme; - vars: ThemeVars; - getCssVar: (field: ThemeCssVar, ...vars: ThemeCssVar[]) => string; - getColorSchemeSelector: (colorScheme: SupportedColorScheme) => string; - generateThemeVars: () => ThemeVars; - generateStyleSheets: () => Array>; - generateSpacing: () => Theme['spacing']; - - // Default theme tokens - spacing: Theme['spacing']; - breakpoints: Theme['breakpoints']; - shape: Theme['shape']; - typography: Theme['typography']; - transitions: Theme['transitions']; - shadows: Theme['shadows']; - mixins: Theme['mixins']; - zIndex: Theme['zIndex']; - direction: Theme['direction']; - /** - * A function to determine if the key, value should be attached as CSS Variable - * `keys` is an array that represents the object path keys. - * Ex, if the theme is { foo: { bar: 'var(--test)' } } - * then, keys = ['foo', 'bar'] - * value = 'var(--test)' - */ - shouldSkipGeneratingVar: (keys: string[], value: string | number) => boolean; - unstable_sxConfig: SxConfig; - unstable_sx: (props: SxProps) => CSSObject; - applyStyles: ApplyStyles; -} - -/** - * Generate a theme base on the options received. - * @param options Takes an incomplete theme object and adds the missing parts. - * @param args Deep merge the arguments with the about to be returned theme. - * @returns A complete, ready-to-use theme object. - */ -export default function extendTheme( - options?: CssVarsThemeOptions, - ...args: object[] -): Omit & CssVarsTheme; diff --git a/packages/mui-material/src/styles/extendTheme.js b/packages/mui-material/src/styles/extendTheme.js deleted file mode 100644 index 7901d3d223cbfa..00000000000000 --- a/packages/mui-material/src/styles/extendTheme.js +++ /dev/null @@ -1,514 +0,0 @@ -import MuiError from '@mui/internal-babel-macros/MuiError.macro'; -import deepmerge from '@mui/utils/deepmerge'; -import { unstable_createGetCssVar as systemCreateGetCssVar, createSpacing } from '@mui/system'; -import { createUnarySpacing } from '@mui/system/spacing'; -import { - prepareCssVars, - prepareTypographyVars, - createGetColorSchemeSelector, -} from '@mui/system/cssVars'; -import styleFunctionSx, { - unstable_defaultSxConfig as defaultSxConfig, -} from '@mui/system/styleFunctionSx'; - -import { - private_safeColorChannel as safeColorChannel, - private_safeAlpha as safeAlpha, - private_safeDarken as safeDarken, - private_safeLighten as safeLighten, - private_safeEmphasize as safeEmphasize, - hslToRgb, -} from '@mui/system/colorManipulator'; - -import defaultShouldSkipGeneratingVar from './shouldSkipGeneratingVar'; -import createThemeWithoutVars from './createTheme'; -import getOverlayAlpha from './getOverlayAlpha'; -import defaultGetSelector from './createGetSelector'; -import { stringifyTheme } from './stringifyTheme'; - -const defaultDarkOverlays = [...Array(25)].map((_, index) => { - if (index === 0) { - return undefined; - } - const overlay = getOverlayAlpha(index); - return `linear-gradient(rgba(255 255 255 / ${overlay}), rgba(255 255 255 / ${overlay}))`; -}); - -function assignNode(obj, keys) { - keys.forEach((k) => { - if (!obj[k]) { - obj[k] = {}; - } - }); -} - -function setColor(obj, key, defaultValue) { - if (!obj[key] && defaultValue) { - obj[key] = defaultValue; - } -} - -function toRgb(color) { - if (!color || !color.startsWith('hsl')) { - return color; - } - return hslToRgb(color); -} - -function setColorChannel(obj, key) { - if (!(`${key}Channel` in obj)) { - // custom channel token is not provided, generate one. - // if channel token can't be generated, show a warning. - obj[`${key}Channel`] = safeColorChannel( - toRgb(obj[key]), - `MUI: Can't create \`palette.${key}Channel\` because \`palette.${key}\` is not one of these formats: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla(), color().` + - '\n' + - `To suppress this warning, you need to explicitly provide the \`palette.${key}Channel\` as a string (in rgb format, for example "12 12 12") or undefined if you want to remove the channel token.`, - ); - } -} - -function getSpacingVal(spacingInput) { - if (typeof spacingInput === 'number') { - return `${spacingInput}px`; - } - if (typeof spacingInput === 'string') { - return spacingInput; - } - if (typeof spacingInput === 'function') { - return getSpacingVal(spacingInput(1)); - } - if (Array.isArray(spacingInput)) { - return spacingInput; - } - return '8px'; -} - -const silent = (fn) => { - try { - return fn(); - } catch (error) { - // ignore error - } - return undefined; -}; - -export const createGetCssVar = (cssVarPrefix = 'mui') => systemCreateGetCssVar(cssVarPrefix); - -function getOpacity(mode) { - return { - inputPlaceholder: mode === 'dark' ? 0.5 : 0.42, - inputUnderline: mode === 'dark' ? 0.7 : 0.42, - switchTrackDisabled: mode === 'dark' ? 0.2 : 0.12, - switchTrack: mode === 'dark' ? 0.3 : 0.38, - }; -} -function getOverlays(mode) { - return mode === 'dark' ? defaultDarkOverlays : []; -} - -function attachColorScheme(colorSchemes, scheme, restTheme, colorScheme) { - if (!scheme) { - return undefined; - } - scheme = scheme === true ? {} : scheme; - const mode = colorScheme === 'dark' ? 'dark' : 'light'; - const { palette, ...muiTheme } = createThemeWithoutVars({ - ...restTheme, - palette: { - mode, - ...scheme?.palette, - }, - }); - colorSchemes[colorScheme] = { - ...scheme, - palette, - opacity: { - ...getOpacity(mode), - ...scheme?.opacity, - }, - overlays: scheme?.overlays || getOverlays(mode), - }; - return muiTheme; -} - -/** - * A default `extendTheme` comes with a single color scheme, either `light` or `dark` based on the `defaultColorScheme`. - * This is better suited for apps that only need a single color scheme. - * - * To enable built-in `light` and `dark` color schemes, either: - * 1. provide a `colorSchemeSelector` to define how the color schemes will change. - * 2. provide `colorSchemes.dark` will set `colorSchemeSelector: 'media'` by default. - */ -export default function extendTheme(options = {}, ...args) { - const { - colorSchemes: colorSchemesInput = { light: true }, - defaultColorScheme: defaultColorSchemeInput, - disableCssColorScheme = false, - cssVarPrefix = 'mui', - shouldSkipGeneratingVar = defaultShouldSkipGeneratingVar, - colorSchemeSelector: selector = colorSchemesInput.light && colorSchemesInput.dark - ? 'media' - : undefined, - ...input - } = options; - const firstColorScheme = Object.keys(colorSchemesInput)[0]; - const defaultColorScheme = - defaultColorSchemeInput || - (colorSchemesInput.light && firstColorScheme !== 'light' ? 'light' : firstColorScheme); - const getCssVar = createGetCssVar(cssVarPrefix); - const { - [defaultColorScheme]: defaultSchemeInput, - light: builtInLight, - dark: builtInDark, - ...customColorSchemes - } = colorSchemesInput; - const colorSchemes = { ...customColorSchemes }; - let defaultScheme = defaultSchemeInput; - - // For built-in light and dark color schemes, ensure that the value is valid if they are the default color scheme. - if ( - (defaultColorScheme === 'dark' && !('dark' in colorSchemesInput)) || - (defaultColorScheme === 'light' && !('light' in colorSchemesInput)) - ) { - defaultScheme = true; - } - - if (!defaultScheme) { - throw new MuiError( - 'MUI: The provided `colorSchemes.%s` to the `extendTheme` function is either missing or invalid.', - defaultColorScheme, - ); - } - - // Create the palette for the default color scheme, either `light`, `dark`, or custom color scheme. - const muiTheme = attachColorScheme(colorSchemes, defaultScheme, input, defaultColorScheme); - - if (builtInLight && !colorSchemes.light) { - attachColorScheme(colorSchemes, builtInLight, undefined, 'light'); - } - - if (builtInDark && !colorSchemes.dark) { - attachColorScheme(colorSchemes, builtInDark, undefined, 'dark'); - } - - let theme = { - defaultColorScheme, - ...muiTheme, - cssVarPrefix, - colorSchemeSelector: selector, - getCssVar, - colorSchemes, - font: { ...prepareTypographyVars(muiTheme.typography), ...muiTheme.font }, - spacing: getSpacingVal(input.spacing), - }; - - Object.keys(theme.colorSchemes).forEach((key) => { - const palette = theme.colorSchemes[key].palette; - - const setCssVarColor = (cssVar) => { - const tokens = cssVar.split('-'); - const color = tokens[1]; - const colorToken = tokens[2]; - return getCssVar(cssVar, palette[color][colorToken]); - }; - - // attach black & white channels to common node - if (palette.mode === 'light') { - setColor(palette.common, 'background', '#fff'); - setColor(palette.common, 'onBackground', '#000'); - } - if (palette.mode === 'dark') { - setColor(palette.common, 'background', '#000'); - setColor(palette.common, 'onBackground', '#fff'); - } - - // assign component variables - assignNode(palette, [ - 'Alert', - 'AppBar', - 'Avatar', - 'Button', - 'Chip', - 'FilledInput', - 'LinearProgress', - 'Skeleton', - 'Slider', - 'SnackbarContent', - 'SpeedDialAction', - 'StepConnector', - 'StepContent', - 'Switch', - 'TableCell', - 'Tooltip', - ]); - if (palette.mode === 'light') { - setColor(palette.Alert, 'errorColor', safeDarken(palette.error.light, 0.6)); - setColor(palette.Alert, 'infoColor', safeDarken(palette.info.light, 0.6)); - setColor(palette.Alert, 'successColor', safeDarken(palette.success.light, 0.6)); - setColor(palette.Alert, 'warningColor', safeDarken(palette.warning.light, 0.6)); - setColor(palette.Alert, 'errorFilledBg', setCssVarColor('palette-error-main')); - setColor(palette.Alert, 'infoFilledBg', setCssVarColor('palette-info-main')); - setColor(palette.Alert, 'successFilledBg', setCssVarColor('palette-success-main')); - setColor(palette.Alert, 'warningFilledBg', setCssVarColor('palette-warning-main')); - setColor( - palette.Alert, - 'errorFilledColor', - silent(() => palette.getContrastText(palette.error.main)), - ); - setColor( - palette.Alert, - 'infoFilledColor', - silent(() => palette.getContrastText(palette.info.main)), - ); - setColor( - palette.Alert, - 'successFilledColor', - silent(() => palette.getContrastText(palette.success.main)), - ); - setColor( - palette.Alert, - 'warningFilledColor', - silent(() => palette.getContrastText(palette.warning.main)), - ); - setColor(palette.Alert, 'errorStandardBg', safeLighten(palette.error.light, 0.9)); - setColor(palette.Alert, 'infoStandardBg', safeLighten(palette.info.light, 0.9)); - setColor(palette.Alert, 'successStandardBg', safeLighten(palette.success.light, 0.9)); - setColor(palette.Alert, 'warningStandardBg', safeLighten(palette.warning.light, 0.9)); - setColor(palette.Alert, 'errorIconColor', setCssVarColor('palette-error-main')); - setColor(palette.Alert, 'infoIconColor', setCssVarColor('palette-info-main')); - setColor(palette.Alert, 'successIconColor', setCssVarColor('palette-success-main')); - setColor(palette.Alert, 'warningIconColor', setCssVarColor('palette-warning-main')); - setColor(palette.AppBar, 'defaultBg', setCssVarColor('palette-grey-100')); - setColor(palette.Avatar, 'defaultBg', setCssVarColor('palette-grey-400')); - setColor(palette.Button, 'inheritContainedBg', setCssVarColor('palette-grey-300')); - setColor(palette.Button, 'inheritContainedHoverBg', setCssVarColor('palette-grey-A100')); - setColor(palette.Chip, 'defaultBorder', setCssVarColor('palette-grey-400')); - setColor(palette.Chip, 'defaultAvatarColor', setCssVarColor('palette-grey-700')); - setColor(palette.Chip, 'defaultIconColor', setCssVarColor('palette-grey-700')); - setColor(palette.FilledInput, 'bg', 'rgba(0, 0, 0, 0.06)'); - setColor(palette.FilledInput, 'hoverBg', 'rgba(0, 0, 0, 0.09)'); - setColor(palette.FilledInput, 'disabledBg', 'rgba(0, 0, 0, 0.12)'); - setColor(palette.LinearProgress, 'primaryBg', safeLighten(palette.primary.main, 0.62)); - setColor(palette.LinearProgress, 'secondaryBg', safeLighten(palette.secondary.main, 0.62)); - setColor(palette.LinearProgress, 'errorBg', safeLighten(palette.error.main, 0.62)); - setColor(palette.LinearProgress, 'infoBg', safeLighten(palette.info.main, 0.62)); - setColor(palette.LinearProgress, 'successBg', safeLighten(palette.success.main, 0.62)); - setColor(palette.LinearProgress, 'warningBg', safeLighten(palette.warning.main, 0.62)); - setColor( - palette.Skeleton, - 'bg', - `rgba(${setCssVarColor('palette-text-primaryChannel')} / 0.11)`, - ); - setColor(palette.Slider, 'primaryTrack', safeLighten(palette.primary.main, 0.62)); - setColor(palette.Slider, 'secondaryTrack', safeLighten(palette.secondary.main, 0.62)); - setColor(palette.Slider, 'errorTrack', safeLighten(palette.error.main, 0.62)); - setColor(palette.Slider, 'infoTrack', safeLighten(palette.info.main, 0.62)); - setColor(palette.Slider, 'successTrack', safeLighten(palette.success.main, 0.62)); - setColor(palette.Slider, 'warningTrack', safeLighten(palette.warning.main, 0.62)); - const snackbarContentBackground = safeEmphasize(palette.background.default, 0.8); - setColor(palette.SnackbarContent, 'bg', snackbarContentBackground); - setColor( - palette.SnackbarContent, - 'color', - silent(() => palette.getContrastText(snackbarContentBackground)), - ); - setColor( - palette.SpeedDialAction, - 'fabHoverBg', - safeEmphasize(palette.background.paper, 0.15), - ); - setColor(palette.StepConnector, 'border', setCssVarColor('palette-grey-400')); - setColor(palette.StepContent, 'border', setCssVarColor('palette-grey-400')); - setColor(palette.Switch, 'defaultColor', setCssVarColor('palette-common-white')); - setColor(palette.Switch, 'defaultDisabledColor', setCssVarColor('palette-grey-100')); - setColor(palette.Switch, 'primaryDisabledColor', safeLighten(palette.primary.main, 0.62)); - setColor(palette.Switch, 'secondaryDisabledColor', safeLighten(palette.secondary.main, 0.62)); - setColor(palette.Switch, 'errorDisabledColor', safeLighten(palette.error.main, 0.62)); - setColor(palette.Switch, 'infoDisabledColor', safeLighten(palette.info.main, 0.62)); - setColor(palette.Switch, 'successDisabledColor', safeLighten(palette.success.main, 0.62)); - setColor(palette.Switch, 'warningDisabledColor', safeLighten(palette.warning.main, 0.62)); - setColor(palette.TableCell, 'border', safeLighten(safeAlpha(palette.divider, 1), 0.88)); - setColor(palette.Tooltip, 'bg', safeAlpha(palette.grey[700], 0.92)); - } - if (palette.mode === 'dark') { - setColor(palette.Alert, 'errorColor', safeLighten(palette.error.light, 0.6)); - setColor(palette.Alert, 'infoColor', safeLighten(palette.info.light, 0.6)); - setColor(palette.Alert, 'successColor', safeLighten(palette.success.light, 0.6)); - setColor(palette.Alert, 'warningColor', safeLighten(palette.warning.light, 0.6)); - setColor(palette.Alert, 'errorFilledBg', setCssVarColor('palette-error-dark')); - setColor(palette.Alert, 'infoFilledBg', setCssVarColor('palette-info-dark')); - setColor(palette.Alert, 'successFilledBg', setCssVarColor('palette-success-dark')); - setColor(palette.Alert, 'warningFilledBg', setCssVarColor('palette-warning-dark')); - setColor( - palette.Alert, - 'errorFilledColor', - silent(() => palette.getContrastText(palette.error.dark)), - ); - setColor( - palette.Alert, - 'infoFilledColor', - silent(() => palette.getContrastText(palette.info.dark)), - ); - setColor( - palette.Alert, - 'successFilledColor', - silent(() => palette.getContrastText(palette.success.dark)), - ); - setColor( - palette.Alert, - 'warningFilledColor', - silent(() => palette.getContrastText(palette.warning.dark)), - ); - setColor(palette.Alert, 'errorStandardBg', safeDarken(palette.error.light, 0.9)); - setColor(palette.Alert, 'infoStandardBg', safeDarken(palette.info.light, 0.9)); - setColor(palette.Alert, 'successStandardBg', safeDarken(palette.success.light, 0.9)); - setColor(palette.Alert, 'warningStandardBg', safeDarken(palette.warning.light, 0.9)); - setColor(palette.Alert, 'errorIconColor', setCssVarColor('palette-error-main')); - setColor(palette.Alert, 'infoIconColor', setCssVarColor('palette-info-main')); - setColor(palette.Alert, 'successIconColor', setCssVarColor('palette-success-main')); - setColor(palette.Alert, 'warningIconColor', setCssVarColor('palette-warning-main')); - setColor(palette.AppBar, 'defaultBg', setCssVarColor('palette-grey-900')); - setColor(palette.AppBar, 'darkBg', setCssVarColor('palette-background-paper')); // specific for dark mode - setColor(palette.AppBar, 'darkColor', setCssVarColor('palette-text-primary')); // specific for dark mode - setColor(palette.Avatar, 'defaultBg', setCssVarColor('palette-grey-600')); - setColor(palette.Button, 'inheritContainedBg', setCssVarColor('palette-grey-800')); - setColor(palette.Button, 'inheritContainedHoverBg', setCssVarColor('palette-grey-700')); - setColor(palette.Chip, 'defaultBorder', setCssVarColor('palette-grey-700')); - setColor(palette.Chip, 'defaultAvatarColor', setCssVarColor('palette-grey-300')); - setColor(palette.Chip, 'defaultIconColor', setCssVarColor('palette-grey-300')); - setColor(palette.FilledInput, 'bg', 'rgba(255, 255, 255, 0.09)'); - setColor(palette.FilledInput, 'hoverBg', 'rgba(255, 255, 255, 0.13)'); - setColor(palette.FilledInput, 'disabledBg', 'rgba(255, 255, 255, 0.12)'); - setColor(palette.LinearProgress, 'primaryBg', safeDarken(palette.primary.main, 0.5)); - setColor(palette.LinearProgress, 'secondaryBg', safeDarken(palette.secondary.main, 0.5)); - setColor(palette.LinearProgress, 'errorBg', safeDarken(palette.error.main, 0.5)); - setColor(palette.LinearProgress, 'infoBg', safeDarken(palette.info.main, 0.5)); - setColor(palette.LinearProgress, 'successBg', safeDarken(palette.success.main, 0.5)); - setColor(palette.LinearProgress, 'warningBg', safeDarken(palette.warning.main, 0.5)); - setColor( - palette.Skeleton, - 'bg', - `rgba(${setCssVarColor('palette-text-primaryChannel')} / 0.13)`, - ); - setColor(palette.Slider, 'primaryTrack', safeDarken(palette.primary.main, 0.5)); - setColor(palette.Slider, 'secondaryTrack', safeDarken(palette.secondary.main, 0.5)); - setColor(palette.Slider, 'errorTrack', safeDarken(palette.error.main, 0.5)); - setColor(palette.Slider, 'infoTrack', safeDarken(palette.info.main, 0.5)); - setColor(palette.Slider, 'successTrack', safeDarken(palette.success.main, 0.5)); - setColor(palette.Slider, 'warningTrack', safeDarken(palette.warning.main, 0.5)); - const snackbarContentBackground = safeEmphasize(palette.background.default, 0.98); - setColor(palette.SnackbarContent, 'bg', snackbarContentBackground); - setColor( - palette.SnackbarContent, - 'color', - silent(() => palette.getContrastText(snackbarContentBackground)), - ); - setColor( - palette.SpeedDialAction, - 'fabHoverBg', - safeEmphasize(palette.background.paper, 0.15), - ); - setColor(palette.StepConnector, 'border', setCssVarColor('palette-grey-600')); - setColor(palette.StepContent, 'border', setCssVarColor('palette-grey-600')); - setColor(palette.Switch, 'defaultColor', setCssVarColor('palette-grey-300')); - setColor(palette.Switch, 'defaultDisabledColor', setCssVarColor('palette-grey-600')); - setColor(palette.Switch, 'primaryDisabledColor', safeDarken(palette.primary.main, 0.55)); - setColor(palette.Switch, 'secondaryDisabledColor', safeDarken(palette.secondary.main, 0.55)); - setColor(palette.Switch, 'errorDisabledColor', safeDarken(palette.error.main, 0.55)); - setColor(palette.Switch, 'infoDisabledColor', safeDarken(palette.info.main, 0.55)); - setColor(palette.Switch, 'successDisabledColor', safeDarken(palette.success.main, 0.55)); - setColor(palette.Switch, 'warningDisabledColor', safeDarken(palette.warning.main, 0.55)); - setColor(palette.TableCell, 'border', safeDarken(safeAlpha(palette.divider, 1), 0.68)); - setColor(palette.Tooltip, 'bg', safeAlpha(palette.grey[700], 0.92)); - } - - // MUI X - DataGrid needs this token. - setColorChannel(palette.background, 'default'); - - // added for consistency with the `background.default` token - setColorChannel(palette.background, 'paper'); - - setColorChannel(palette.common, 'background'); - setColorChannel(palette.common, 'onBackground'); - - setColorChannel(palette, 'divider'); - - Object.keys(palette).forEach((color) => { - const colors = palette[color]; - - // The default palettes (primary, secondary, error, info, success, and warning) errors are handled by the above `createTheme(...)`. - - if (colors && typeof colors === 'object') { - // Silent the error for custom palettes. - if (colors.main) { - setColor(palette[color], 'mainChannel', safeColorChannel(toRgb(colors.main))); - } - if (colors.light) { - setColor(palette[color], 'lightChannel', safeColorChannel(toRgb(colors.light))); - } - if (colors.dark) { - setColor(palette[color], 'darkChannel', safeColorChannel(toRgb(colors.dark))); - } - if (colors.contrastText) { - setColor( - palette[color], - 'contrastTextChannel', - safeColorChannel(toRgb(colors.contrastText)), - ); - } - - if (color === 'text') { - // Text colors: text.primary, text.secondary - setColorChannel(palette[color], 'primary'); - setColorChannel(palette[color], 'secondary'); - } - - if (color === 'action') { - // Action colors: action.active, action.selected - if (colors.active) { - setColorChannel(palette[color], 'active'); - } - if (colors.selected) { - setColorChannel(palette[color], 'selected'); - } - } - } - }); - }); - - theme = args.reduce((acc, argument) => deepmerge(acc, argument), theme); - - const parserConfig = { - prefix: cssVarPrefix, - disableCssColorScheme, - shouldSkipGeneratingVar, - getSelector: defaultGetSelector(theme), - }; - const { vars, generateThemeVars, generateStyleSheets } = prepareCssVars(theme, parserConfig); - theme.vars = vars; - Object.entries(theme.colorSchemes[theme.defaultColorScheme]).forEach(([key, value]) => { - theme[key] = value; - }); - theme.generateThemeVars = generateThemeVars; - theme.generateStyleSheets = generateStyleSheets; - theme.generateSpacing = function generateSpacing() { - return createSpacing(input.spacing, createUnarySpacing(this)); - }; - theme.getColorSchemeSelector = createGetColorSchemeSelector(selector); - theme.spacing = theme.generateSpacing(); - theme.shouldSkipGeneratingVar = shouldSkipGeneratingVar; - theme.unstable_sxConfig = { - ...defaultSxConfig, - ...input?.unstable_sxConfig, - }; - theme.unstable_sx = function sx(props) { - return styleFunctionSx({ - sx: props, - theme: this, - }); - }; - theme.toRuntimeSource = stringifyTheme; // for Pigment CSS integration - - return theme; -} diff --git a/packages/mui-material/src/styles/index.d.ts b/packages/mui-material/src/styles/index.d.ts index f866cd09a96116..0076c0acd5ed04 100644 --- a/packages/mui-material/src/styles/index.d.ts +++ b/packages/mui-material/src/styles/index.d.ts @@ -100,7 +100,7 @@ export { default as withTheme } from './withTheme'; export * from './CssVarsProvider'; -export { default as extendTheme } from './extendTheme'; +export { default as extendTheme } from './createTheme/createThemeWithVars'; export type { ColorSchemeOverrides, @@ -134,7 +134,7 @@ export type { ThemeCssVar, ThemeCssVarOverrides, ColorSystemOptions, -} from './extendTheme'; +} from './createTheme/createThemeWithVars'; export { default as getOverlayAlpha } from './getOverlayAlpha'; export { default as shouldSkipGeneratingVar } from './shouldSkipGeneratingVar'; diff --git a/packages/mui-material/src/styles/index.js b/packages/mui-material/src/styles/index.js index ce4948840d5acd..c5ae7897133b15 100644 --- a/packages/mui-material/src/styles/index.js +++ b/packages/mui-material/src/styles/index.js @@ -46,7 +46,7 @@ export { default as withStyles } from './withStyles'; export { default as withTheme } from './withTheme'; export * from './CssVarsProvider'; -export { default as extendTheme } from './extendTheme'; +export { default as extendTheme } from './createTheme/createThemeWithVars'; export { default as experimental_extendTheme } from './experimental_extendTheme'; // TODO: Remove in v7 export { default as getOverlayAlpha } from './getOverlayAlpha'; export { default as shouldSkipGeneratingVar } from './shouldSkipGeneratingVar'; diff --git a/packages/mui-material/src/themeCssVarsAugmentation/index.d.ts b/packages/mui-material/src/themeCssVarsAugmentation/index.d.ts index 06f66f75d2088a..d4c99da54c8601 100644 --- a/packages/mui-material/src/themeCssVarsAugmentation/index.d.ts +++ b/packages/mui-material/src/themeCssVarsAugmentation/index.d.ts @@ -1,28 +1,5 @@ -import type { - CssVarsTheme, - CssVarsPalette, - PaletteBackgroundChannel, - PaletteCommonChannel, - PaletteColorChannel, - PaletteTextChannel, - PaletteActionChannel, -} from '../styles/extendTheme'; - /** - * Enhance the theme types to include new properties from the CssVarsProvider. - * The theme is typed with CSS variables in `styled`, `sx`, `useTheme`, etc. + * @deprecated + * CSS theme variables are included in the types by default. There is no need to use this module. */ -declare module '@mui/material/styles' { - // The palette must be extended in each node. - interface Theme extends Omit {} - - // Extend the type that will be used in palette - interface CommonColors extends PaletteCommonChannel {} - interface PaletteColor extends PaletteColorChannel {} - interface TypeBackground extends PaletteBackgroundChannel {} - interface TypeText extends PaletteTextChannel {} - interface TypeAction extends PaletteActionChannel {} - - // The extended Palette should be in sync with `extendTheme` - interface Palette extends CssVarsPalette {} -} +export {}; From 36ec12ebadf6dc78b71f5c9832c55e3f31e1f619 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 30 Jul 2024 11:33:30 +0700 Subject: [PATCH 08/82] fix import paths --- .../src/styles/createTheme.test.js | 12 +++++ .../styles/createTheme/createThemeNoVars.d.ts | 50 +++++++++---------- .../mui-material/src/styles/defaultTheme.js | 2 +- .../src/styles/experimental_extendTheme.js | 2 +- packages/mui-material/src/styles/index.d.ts | 1 + .../src/styles/stringifyTheme.test.ts | 6 +-- 6 files changed, 43 insertions(+), 30 deletions(-) diff --git a/packages/mui-material/src/styles/createTheme.test.js b/packages/mui-material/src/styles/createTheme.test.js index eba357d10d194f..765ff6565c0e99 100644 --- a/packages/mui-material/src/styles/createTheme.test.js +++ b/packages/mui-material/src/styles/createTheme.test.js @@ -72,6 +72,18 @@ describe('createTheme', () => { expect(light?.palette.primary.main).to.deep.equal(lightPalette.primary.main); expect(dark?.palette.primary.main).to.deep.equal(darkPalette.primary.main); }); + + it('should provide spacing in px', () => { + const theme = createTheme({ cssVariables: false }); + expect(theme.spacing(1)).to.equal('8px'); + }); + }); + + describe('spacing', () => { + it('should provide the default spacing', () => { + const theme = createTheme(); + expect(theme.spacing(1)).to.equal(`calc(1 * var(--mui-spacing, 8px))`); + }); }); describe('transitions', () => { diff --git a/packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts b/packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts index df169b02330412..56158975b9a699 100644 --- a/packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts +++ b/packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts @@ -4,7 +4,6 @@ import { SxProps, CSSObject, SxConfig, - ApplyStyles, } from '@mui/system'; import { Mixins, MixinsOptions } from '../createMixins'; import { Palette, PaletteOptions } from '../createPalette'; @@ -13,13 +12,7 @@ import { Shadows } from '../shadows'; import { Transitions, TransitionsOptions } from '../createTransitions'; import { ZIndex, ZIndexOptions } from '../zIndex'; import { Components } from '../components'; -import { - CssVarsPalette, - ColorSystemOptions, - ColorSystem, - ThemeVars, - SupportedColorScheme, -} from './createThemeWithVars'; +import { CssVarsTheme, CssVarsPalette, ColorSystemOptions } from './createThemeWithVars'; /** * To disable custom properties, use module augmentation @@ -33,17 +26,15 @@ import { */ export interface CssThemeVariables {} -type CssVarsOptions = CssVariables extends { +type CssVarsOptions = CssThemeVariables extends { disabled: true; } ? {} : ColorSystemOptions; -export interface ThemeOptions - extends Omit, - CssVarsOptions { +export interface ThemeOptions extends Omit, CssVarsOptions { mixins?: MixinsOptions; - components?: Components, 'components'>>; + components?: Components>; palette?: PaletteOptions; shadows?: Shadows; transitions?: TransitionsOptions; @@ -53,36 +44,45 @@ export interface ThemeOptions unstable_sxConfig?: SxConfig; } -interface BaseTheme extends SystemTheme { +interface BaseTheme extends SystemTheme { mixins: Mixins; - palette: Palette & (CssVariables extends { disabled: true } ? {} : CssVarsPalette); + palette: Palette & (CssThemeVariables extends { disabled: true } ? {} : CssVarsPalette); shadows: Shadows; transitions: Transitions; typography: Typography; zIndex: ZIndex; unstable_strictMode?: boolean; - vars: CssThemeVariables extends { disabled: true } ? undefined : ThemeVars; } // shut off automatic exporting for the `BaseTheme` above export {}; +type CssVarsProperties = CssThemeVariables extends { disabled: true } + ? {} + : Pick< + CssVarsTheme, + | 'applyStyles' + | 'colorSchemes' + | 'colorSchemeSelector' + | 'cssVarPrefix' + | 'defaultColorScheme' + | 'getCssVar' + | 'getColorSchemeSelector' + | 'generateThemeVars' + | 'generateStyleSheets' + | 'generateSpacing' + | 'shouldSkipGeneratingVar' + | 'vars' + >; + /** * Our [TypeScript guide on theme customization](https://mui.com/material-ui/guides/typescript/#customization-of-theme) explains in detail how you would add custom properties. */ -export interface Theme extends BaseTheme { - colorSchemes?: Partial< - Record< - SupportedColorScheme, - CssVariables extends { disabled: true } ? { palette: Palette } : ColorSystem - > - >; - defaultColorScheme: SupportedColorScheme; +export interface Theme extends BaseTheme, CssVarsProperties { cssVariables?: false; components?: Components; unstable_sx: (props: SxProps) => CSSObject; unstable_sxConfig: SxConfig; - applyStyles: ApplyStyles; } /** diff --git a/packages/mui-material/src/styles/defaultTheme.js b/packages/mui-material/src/styles/defaultTheme.js index 094155f2e31e4a..d55f1451b7ab39 100644 --- a/packages/mui-material/src/styles/defaultTheme.js +++ b/packages/mui-material/src/styles/defaultTheme.js @@ -1,6 +1,6 @@ 'use client'; import createTheme from './createTheme'; -const defaultTheme = createTheme(); +const defaultTheme = createTheme({ cssVariables: false }); export default defaultTheme; diff --git a/packages/mui-material/src/styles/experimental_extendTheme.js b/packages/mui-material/src/styles/experimental_extendTheme.js index 3ead445e2bd92a..51efb520f348f4 100644 --- a/packages/mui-material/src/styles/experimental_extendTheme.js +++ b/packages/mui-material/src/styles/experimental_extendTheme.js @@ -1,4 +1,4 @@ -import extendTheme from './extendTheme'; +import extendTheme from './createTheme/createThemeWithVars'; let warnedOnce = false; diff --git a/packages/mui-material/src/styles/index.d.ts b/packages/mui-material/src/styles/index.d.ts index 0076c0acd5ed04..91bc9feb99ea5d 100644 --- a/packages/mui-material/src/styles/index.d.ts +++ b/packages/mui-material/src/styles/index.d.ts @@ -5,6 +5,7 @@ export { createMuiTheme, ThemeOptions, Theme, + CssThemeVariables, } from './createTheme'; export { default as adaptV4Theme, DeprecatedThemeOptions } from './adaptV4Theme'; export { Shadows } from './shadows'; diff --git a/packages/mui-material/src/styles/stringifyTheme.test.ts b/packages/mui-material/src/styles/stringifyTheme.test.ts index 8831a59eedf9c0..fb2ded3c8ca0c3 100644 --- a/packages/mui-material/src/styles/stringifyTheme.test.ts +++ b/packages/mui-material/src/styles/stringifyTheme.test.ts @@ -1,10 +1,10 @@ import { expect } from 'chai'; +import { createTheme } from '@mui/material/styles'; import { stringifyTheme } from './stringifyTheme'; -import extendTheme from './extendTheme'; describe('StringifyTheme', () => { it('should serialize the theme', () => { - const theme = extendTheme(); + const theme = createTheme(); const result = stringifyTheme({ breakpoints: theme.breakpoints, transitions: theme.transitions, @@ -59,7 +59,7 @@ export default theme;`); }); it('should serialize the custom theme', () => { - const theme = extendTheme({ + const theme = createTheme({ breakpoints: { values: { mobile: 0, From 2603b25669d4815a8ef127a612ab8f28633c7236 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 30 Jul 2024 13:13:03 +0700 Subject: [PATCH 09/82] fix all tests --- packages/mui-lab/src/Masonry/Masonry.test.js | 2 +- .../mui-material/src/Drawer/Drawer.test.js | 16 +++++++------- packages/mui-material/src/Grid/Grid.test.js | 21 ++++++++++++------- .../src/Link/getTextDecoration.test.js | 2 +- .../mui-material/src/styles/styled.test.js | 3 +++ .../mui-styles/test/theme-scoping.test.tsx | 1 + .../src/cssVars/createCssVarsProvider.test.js | 8 +++++-- 7 files changed, 32 insertions(+), 21 deletions(-) diff --git a/packages/mui-lab/src/Masonry/Masonry.test.js b/packages/mui-lab/src/Masonry/Masonry.test.js index c5e56f2a0ac5b0..5194f2b95e5efa 100644 --- a/packages/mui-lab/src/Masonry/Masonry.test.js +++ b/packages/mui-lab/src/Masonry/Masonry.test.js @@ -25,7 +25,7 @@ describe('', () => { }), ); - const theme = createTheme({ spacing: 8 }); + const theme = createTheme({ cssVariables: false, spacing: 8 }); const maxColumnHeight = 100; describe('render', () => { diff --git a/packages/mui-material/src/Drawer/Drawer.test.js b/packages/mui-material/src/Drawer/Drawer.test.js index 2eee979d62a4d2..3755c159300c8c 100644 --- a/packages/mui-material/src/Drawer/Drawer.test.js +++ b/packages/mui-material/src/Drawer/Drawer.test.js @@ -3,6 +3,7 @@ import { expect } from 'chai'; import { spy } from 'sinon'; import { createRenderer, screen } from '@mui/internal-test-utils'; import { ThemeProvider, createTheme } from '@mui/material/styles'; +import defaultTheme from '@mui/material/styles/defaultTheme'; import Drawer, { drawerClasses as classes } from '@mui/material/Drawer'; import { getAnchor, isHorizontal } from './Drawer'; import describeConformance from '../../test/describeConformance'; @@ -37,8 +38,8 @@ describe('', () => { if (/jsdom/.test(window.navigator.userAgent)) { this.skip(); } - const theme = createTheme(); - const enteringScreenDurationInSeconds = theme.transitions.duration.enteringScreen / 1000; + const enteringScreenDurationInSeconds = + defaultTheme.transitions.duration.enteringScreen / 1000; render(
@@ -321,16 +322,13 @@ describe('', () => { describe('zIndex', () => { it('should set correct zIndex on the root element', () => { - const theme = createTheme(); render( - - -
- - , + +
+ , ); expect(document.querySelector(`.${classes.root}`)).toHaveComputedStyle({ - zIndex: String(theme.zIndex.drawer), + zIndex: String(defaultTheme.zIndex.drawer), }); }); }); diff --git a/packages/mui-material/src/Grid/Grid.test.js b/packages/mui-material/src/Grid/Grid.test.js index 68ce2ec894958f..3912ff620302b4 100644 --- a/packages/mui-material/src/Grid/Grid.test.js +++ b/packages/mui-material/src/Grid/Grid.test.js @@ -155,14 +155,13 @@ describe('Material UI ', () => { }); it('should generate correct responsive styles regardless of breakpoints order', () => { - const theme = createTheme(); expect( generateDirection({ ownerState: { container: true, direction: { sm: 'column', xs: 'row' }, }, - theme, + theme: defaultTheme, }), ).to.deep.equal({ '@media (min-width:0px)': { @@ -210,6 +209,7 @@ describe('Material UI ', () => { it('should generate correct responsive styles regardless of custom breakpoints order', () => { const theme = createTheme({ + cssVariables: false, breakpoints: { keys: ['mobile', 'desktop'], values: { @@ -713,14 +713,13 @@ describe('Material UI ', () => { describe('prop: rowSpacing, columnSpacing', () => { it('should generate correct responsive styles', () => { - const theme = createTheme(); expect( generateRowGap({ ownerState: { container: true, rowSpacing: { xs: 1, sm: 2 }, }, - theme, + theme: defaultTheme, }), ).to.deep.equal({ '@media (min-width:0px)': { @@ -743,7 +742,7 @@ describe('Material UI ', () => { container: true, columnSpacing: { xs: 1, sm: 2 }, }, - theme, + theme: defaultTheme, }), ).to.deep.equal({ '@media (min-width:0px)': { @@ -765,6 +764,7 @@ describe('Material UI ', () => { it('should support custom breakpoints and generate correct responsive styles', () => { const theme = createTheme({ + cssVariables: false, breakpoints: { keys: ['mobile', 'desktop'], values: { @@ -824,6 +824,7 @@ describe('Material UI ', () => { it("shouldn't support custom breakpoints with values of zeros and shouldn't generate responsive styles", () => { const theme = createTheme({ + cssVariables: false, breakpoints: { keys: ['mobile', 'desktop'], values: { @@ -872,6 +873,7 @@ describe('Material UI ', () => { it("shouldn't support custom breakpoints without its spacing values and shouldn't generate responsive styles", () => { const theme = createTheme({ + cssVariables: false, breakpoints: { keys: ['mobile', 'desktop'], values: { @@ -918,6 +920,7 @@ describe('Material UI ', () => { it("should ignore custom breakpoints that doesn't exist in the theme and shouldn't generate responsive styles", () => { const theme = createTheme({ + cssVariables: false, breakpoints: { keys: ['mobile', 'desktop'], values: { @@ -963,14 +966,13 @@ describe('Material UI ', () => { }); it('should generate correct responsive styles regardless of breakpoints order ', () => { - const theme = createTheme(); expect( generateRowGap({ ownerState: { container: true, rowSpacing: { sm: 2, xs: 1 }, }, - theme, + theme: defaultTheme, }), ).to.deep.equal({ '@media (min-width:0px)': { @@ -993,7 +995,7 @@ describe('Material UI ', () => { container: true, columnSpacing: { sm: 2, xs: 1 }, }, - theme, + theme: defaultTheme, }), ).to.deep.equal({ '@media (min-width:0px)': { @@ -1015,6 +1017,7 @@ describe('Material UI ', () => { it('should generate correct responsive styles regardless of custom breakpoints order ', () => { const theme = createTheme({ + cssVariables: false, breakpoints: { keys: ['mobile', 'desktop'], values: { @@ -1074,6 +1077,7 @@ describe('Material UI ', () => { it('should generate correct responsive styles for overriding with zero value styles for higher breakpoints', () => { const theme = createTheme({ + cssVariables: false, breakpoints: { values: { mobile: 0, @@ -1208,6 +1212,7 @@ describe('Material UI ', () => { it('should not generate responsive styles for lower breakpoints below a given non-zero breakpoint', () => { const theme = createTheme({ + cssVariables: false, breakpoints: { values: { mobile: 0, diff --git a/packages/mui-material/src/Link/getTextDecoration.test.js b/packages/mui-material/src/Link/getTextDecoration.test.js index cf15c993b1d48c..11f89a5d3a554b 100644 --- a/packages/mui-material/src/Link/getTextDecoration.test.js +++ b/packages/mui-material/src/Link/getTextDecoration.test.js @@ -4,7 +4,7 @@ import getTextDecoration from './getTextDecoration'; describe('getTextDecoration', () => { describe('without theme.vars', () => { - const theme = createTheme(); + const theme = createTheme({ cssVariables: false }); it('deprecated color', () => { expect(getTextDecoration({ theme, ownerState: { color: 'textPrimary' } })).to.equal( diff --git a/packages/mui-material/src/styles/styled.test.js b/packages/mui-material/src/styles/styled.test.js index b547370b18f569..719596f0c8a315 100644 --- a/packages/mui-material/src/styles/styled.test.js +++ b/packages/mui-material/src/styles/styled.test.js @@ -62,6 +62,7 @@ describe('styled', () => { `; const theme = createTheme({ + cssVariables: false, spacing: 10, }); @@ -82,6 +83,7 @@ describe('styled', () => { })); const theme = createTheme({ + cssVariables: false, spacing: 10, }); @@ -140,6 +142,7 @@ describe('styled', () => { before(() => { theme = createTheme({ + cssVariables: false, palette: { primary: { main: 'rgb(0, 0, 255)', diff --git a/packages/mui-styles/test/theme-scoping.test.tsx b/packages/mui-styles/test/theme-scoping.test.tsx index 2820deb0f12229..7c847d0208b8ef 100644 --- a/packages/mui-styles/test/theme-scoping.test.tsx +++ b/packages/mui-styles/test/theme-scoping.test.tsx @@ -66,6 +66,7 @@ describe('Theme scoping', () => { { describe('[option]: `disableTransitionOnChange`', () => { clock.withFakeTimers(); + beforeEach(() => { + document.head.replaceChildren([]); + }); + it('disable all css transitions when switching between modes, given `disableTransitionOnChange` is true', () => { const { CssVarsProvider, useColorScheme } = createCssVarsProvider({ theme: createCssVarsTheme({ @@ -268,7 +272,7 @@ describe('createCssVarsProvider', () => { , ); - + clock.runToLast(); expect(document.head.children[document.head.children.length - 1]?.textContent).not.to.equal( DISABLE_CSS_TRANSITION, ); @@ -309,7 +313,7 @@ describe('createCssVarsProvider', () => { , ); - + clock.runToLast(); expect(document.head.children[document.head.children.length - 1]?.textContent).not.to.equal( DISABLE_CSS_TRANSITION, ); From 4e0f40063b046da113864fdd3abbc69897ed6a8c Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 30 Jul 2024 15:35:56 +0700 Subject: [PATCH 10/82] switch to new ThemeProvider --- .../modules/components/AppLayoutDocsFooter.js | 6 +- .../src/modules/components/DiamondSponsors.js | 2 +- packages/mui-material/src/Chip/Chip.test.js | 6 +- .../src/styles/ThemeProvider.d.ts | 17 --- .../mui-material/src/styles/ThemeProvider.js | 27 ----- .../src/styles/ThemeProvider.test.tsx | 18 --- .../styles/ThemeProvider/ThemeProvider.tsx | 7 +- .../ThemeProvider/ThemeProviderNoVars.tsx | 2 +- .../src/styles/ThemeProvider2.tsx | 0 .../src/styles/createTheme.test.js | 104 +++++++++--------- .../src/styles/createTheme/createTheme.ts | 5 +- .../mui-material/src/styles/defaultTheme.js | 2 +- packages/mui-material/src/styles/index.d.ts | 2 +- packages/mui-material/src/styles/index.js | 2 +- .../src/styles/stringifyTheme.test.ts | 8 +- .../src/cssVars/useCurrentColorScheme.ts | 27 +++-- 16 files changed, 98 insertions(+), 137 deletions(-) delete mode 100644 packages/mui-material/src/styles/ThemeProvider.d.ts delete mode 100644 packages/mui-material/src/styles/ThemeProvider.js delete mode 100644 packages/mui-material/src/styles/ThemeProvider.test.tsx delete mode 100644 packages/mui-material/src/styles/ThemeProvider2.tsx diff --git a/docs/src/modules/components/AppLayoutDocsFooter.js b/docs/src/modules/components/AppLayoutDocsFooter.js index bba181c105ad87..36945feb5f55b4 100644 --- a/docs/src/modules/components/AppLayoutDocsFooter.js +++ b/docs/src/modules/components/AppLayoutDocsFooter.js @@ -39,9 +39,9 @@ const FooterLink = styled(Link)(({ theme }) => { display: 'flex', alignItems: 'center', gap: 2, - fontFamily: (theme.vars || theme).typography.fontFamily, - fontSize: (theme.vars || theme).typography.pxToRem(13), - fontWeight: (theme.vars || theme).typography.fontWeightMedium, + fontFamily: theme.typography.fontFamily, + fontSize: theme.typography.pxToRem(13), + fontWeight: theme.typography.fontWeightMedium, color: (theme.vars || theme).palette.primary[600], '& > svg': { fontSize: '13px', transition: '0.2s' }, '&:hover > svg': { transform: 'translateX(2px)' }, diff --git a/docs/src/modules/components/DiamondSponsors.js b/docs/src/modules/components/DiamondSponsors.js index 607abd325b3cff..7061bf89cce463 100644 --- a/docs/src/modules/components/DiamondSponsors.js +++ b/docs/src/modules/components/DiamondSponsors.js @@ -27,7 +27,7 @@ const NativeLink = styled('a')(({ theme }) => ({ backgroundColor: (theme.vars || theme).palette.grey[50], }, '&:focus-visible': { - outline: `3px solid ${alpha((theme.vars || theme).palette.primary[500], 0.5)}`, + outline: `3px solid ${alpha(theme.palette.primary[500], 0.5)}`, outlineOffset: '-3px', }, '& img': { diff --git a/packages/mui-material/src/Chip/Chip.test.js b/packages/mui-material/src/Chip/Chip.test.js index e5d790ea24f0ca..aa695a6de9aabb 100644 --- a/packages/mui-material/src/Chip/Chip.test.js +++ b/packages/mui-material/src/Chip/Chip.test.js @@ -11,7 +11,7 @@ import { } from '@mui/internal-test-utils'; import Avatar from '@mui/material/Avatar'; import Chip, { chipClasses as classes } from '@mui/material/Chip'; -import { ThemeProvider, createTheme, hexToRgb, extendTheme } from '@mui/material/styles'; +import { ThemeProvider, createTheme, hexToRgb } from '@mui/material/styles'; import CheckBox from '../internal/svg-icons/CheckBox'; import defaultTheme from '../styles/defaultTheme'; import describeConformance from '../../test/describeConformance'; @@ -710,7 +710,7 @@ describe('', () => { describe('CSS vars', () => { it('should not throw when there is theme value is CSS variable', () => { - const theme = extendTheme(); + const theme = createTheme({ cssVariables: true }); theme.palette = theme.colorSchemes.light.palette; theme.palette.text = { ...theme.palette.text, @@ -718,7 +718,7 @@ describe('', () => { }; expect(() => render( - + , ), diff --git a/packages/mui-material/src/styles/ThemeProvider.d.ts b/packages/mui-material/src/styles/ThemeProvider.d.ts deleted file mode 100644 index d2e37403ed3abd..00000000000000 --- a/packages/mui-material/src/styles/ThemeProvider.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { DefaultTheme } from '@mui/system'; - -export interface ThemeProviderProps { - children?: React.ReactNode; - theme: Partial | ((outerTheme: Theme) => Theme); -} - -/** - * This component makes the `theme` available down the React tree. - * It should preferably be used at **the root of your component tree**. - * API: - * - * - [ThemeProvider API](https://mui.com/material-ui/customization/theming/#themeprovider) - */ -export default function ThemeProvider( - props: ThemeProviderProps, -): React.ReactElement>; diff --git a/packages/mui-material/src/styles/ThemeProvider.js b/packages/mui-material/src/styles/ThemeProvider.js deleted file mode 100644 index c9eb81b4987886..00000000000000 --- a/packages/mui-material/src/styles/ThemeProvider.js +++ /dev/null @@ -1,27 +0,0 @@ -'use client'; -import * as React from 'react'; -import PropTypes from 'prop-types'; -import { ThemeProvider as SystemThemeProvider } from '@mui/system'; -import THEME_ID from './identifier'; - -export default function ThemeProvider({ theme: themeInput, ...props }) { - const scopedTheme = themeInput[THEME_ID]; - return ( - - ); -} - -ThemeProvider.propTypes = { - /** - * Your component tree. - */ - children: PropTypes.node, - /** - * A theme object. You can provide a function to extend the outer theme. - */ - theme: PropTypes.oneOfType([PropTypes.object, PropTypes.func]).isRequired, -}; diff --git a/packages/mui-material/src/styles/ThemeProvider.test.tsx b/packages/mui-material/src/styles/ThemeProvider.test.tsx deleted file mode 100644 index 0e7d7b83d0e3f5..00000000000000 --- a/packages/mui-material/src/styles/ThemeProvider.test.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import * as React from 'react'; -import { expect } from 'chai'; -import { createRenderer } from '@mui/internal-test-utils'; -import { ThemeProvider } from '@mui/material/styles'; - -describe('ThemeProvider', () => { - const { render } = createRenderer(); - - it('When theme is a function, it should not show warning', () => { - expect(() => - render( - - ({})} /> - , - ), - ).not.toWarnDev(); - }); -}); diff --git a/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx b/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx index c50dd14f902e9f..d2b19fb9dc49f0 100644 --- a/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx +++ b/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx @@ -3,6 +3,7 @@ import { DefaultTheme } from '@mui/system'; import ThemeProviderNoVars from './ThemeProviderNoVars'; import { CssVarsProvider } from './ThemeProviderWithVars'; import { CssThemeVariables } from '../createTheme/createThemeNoVars'; +import THEME_ID from '../identifier'; type ThemeProviderCssVariablesProps = CssThemeVariables extends { disabled: true } ? {} @@ -49,7 +50,11 @@ export default function ThemeProvider({ theme, ...props }: ThemeProviderProps) { - if (!('colorSchemes' in theme)) { + if (typeof theme === 'function') { + return ; + } + const muiTheme = (THEME_ID in theme ? theme[THEME_ID] : theme) as ThemeProviderProps['theme']; + if (!('colorSchemes' in muiTheme)) { return ; } // @ts-expect-error `theme` is created by `createTheme`, typing is handled there. diff --git a/packages/mui-material/src/styles/ThemeProvider/ThemeProviderNoVars.tsx b/packages/mui-material/src/styles/ThemeProvider/ThemeProviderNoVars.tsx index f622137da91ed1..c29773fcb49bfd 100644 --- a/packages/mui-material/src/styles/ThemeProvider/ThemeProviderNoVars.tsx +++ b/packages/mui-material/src/styles/ThemeProvider/ThemeProviderNoVars.tsx @@ -12,7 +12,7 @@ export default function ThemeProviderNoVars({ theme: themeInput, ...props }: ThemeProviderNoVarsProps): React.ReactElement> { - const scopedTheme = THEME_ID in themeInput ? themeInput[THEME_ID] : themeInput; + const scopedTheme = THEME_ID in themeInput ? themeInput[THEME_ID] : undefined; return ( { const { render } = createRenderer(); + it('should not have custom properties', () => { + const theme = createTheme({ cssVariables: false }); + expect(theme.cssVariables).to.equal(false); + expect('vars' in theme).to.equal(false); + }); + + it('color schemes dark: true', () => { + const theme = createTheme({ cssVariables: false, colorSchemes: { dark: true } }); + const { light, dark } = theme.colorSchemes || {}; + expect(light?.palette.primary.main).to.deep.equal(lightPalette.primary.main); + expect(dark?.palette.primary.main).to.deep.equal(darkPalette.primary.main); + }); + + it('color schemes light: true', () => { + const theme = createTheme({ + cssVariables: false, + colorSchemes: { light: true }, + palette: { mode: 'dark' }, + }); + const { light, dark } = theme.colorSchemes || {}; + expect(light?.palette.primary.main).to.deep.equal(lightPalette.primary.main); + expect(dark?.palette.primary.main).to.deep.equal(darkPalette.primary.main); + }); + + it('should provide spacing in px', () => { + const theme = createTheme({ cssVariables: false }); + expect(theme.spacing(1)).to.equal('8px'); + }); + it('should have a palette', () => { const theme = createTheme(); expect(typeof createTheme).to.equal('function'); @@ -26,63 +55,40 @@ describe('createTheme', () => { expect(theme.defaultColorScheme).to.equal('light'); expect(theme.palette.primary.main).to.equal(deepOrange[500]); expect(theme.palette.secondary.main).to.equal(green.A400); - expect(theme.vars.palette.primary.main).to.equal( - `var(--mui-palette-primary-main, ${deepOrange[500]})`, - ); - expect(theme.vars.palette.secondary.main).to.equal( - `var(--mui-palette-secondary-main, ${green.A400})`, - ); }); - it('should have a dark as a default colorScheme if only `palette` is provided', () => { - const theme = createTheme({ - palette: { - mode: 'dark', - primary: { main: deepOrange[500] }, - }, - }); - expect(theme.defaultColorScheme).to.equal('dark'); - expect(theme.palette.primary.main).to.equal(deepOrange[500]); - expect(theme.vars.palette.primary.main).to.equal( - `var(--mui-palette-primary-main, ${deepOrange[500]})`, - ); - }); - - describe('Without custom properties', () => { - it('should not have custom properties', () => { - const theme = createTheme({ cssVariables: false }); - expect(theme.cssVariables).to.equal(false); - expect('vars' in theme).to.equal(false); - }); - - it('color schemes dark: true', () => { - const theme = createTheme({ cssVariables: false, colorSchemes: { dark: true } }); - const { light, dark } = theme.colorSchemes || {}; - expect(light?.palette.primary.main).to.deep.equal(lightPalette.primary.main); - expect(dark?.palette.primary.main).to.deep.equal(darkPalette.primary.main); - }); - - it('color schemes light: true', () => { + describe('CSS variables', () => { + it('should have a light as a default colorScheme if only `palette` is provided', () => { const theme = createTheme({ - cssVariables: false, - colorSchemes: { light: true }, - palette: { mode: 'dark' }, + cssVariables: true, + palette: { primary: { main: deepOrange[500] } }, }); - const { light, dark } = theme.colorSchemes || {}; - expect(light?.palette.primary.main).to.deep.equal(lightPalette.primary.main); - expect(dark?.palette.primary.main).to.deep.equal(darkPalette.primary.main); + expect(theme.defaultColorScheme).to.equal('light'); + expect(theme.vars.palette.primary.main).to.equal( + `var(--mui-palette-primary-main, ${deepOrange[500]})`, + ); }); - it('should provide spacing in px', () => { - const theme = createTheme({ cssVariables: false }); - expect(theme.spacing(1)).to.equal('8px'); + it('should have a dark as a default colorScheme if only `palette` is provided', () => { + const theme = createTheme({ + cssVariables: true, + palette: { + mode: 'dark', + primary: { main: deepOrange[500] }, + }, + }); + expect(theme.defaultColorScheme).to.equal('dark'); + expect(theme.palette.primary.main).to.equal(deepOrange[500]); + expect(theme.vars.palette.primary.main).to.equal( + `var(--mui-palette-primary-main, ${deepOrange[500]})`, + ); }); - }); - describe('spacing', () => { - it('should provide the default spacing', () => { - const theme = createTheme(); - expect(theme.spacing(1)).to.equal(`calc(1 * var(--mui-spacing, 8px))`); + describe('spacing', () => { + it('should provide the default spacing', () => { + const theme = createTheme({ cssVariables: true }); + expect(theme.spacing(1)).to.equal(`calc(1 * var(--mui-spacing, 8px))`); + }); }); }); diff --git a/packages/mui-material/src/styles/createTheme/createTheme.ts b/packages/mui-material/src/styles/createTheme/createTheme.ts index 78de7d6595cc15..4d4808bdcdf79d 100644 --- a/packages/mui-material/src/styles/createTheme/createTheme.ts +++ b/packages/mui-material/src/styles/createTheme/createTheme.ts @@ -45,9 +45,9 @@ export default function createTheme( ): Theme { const { palette, + cssVariables = false, colorSchemes: initialColorSchemes = !palette ? { light: true } : undefined, defaultColorScheme: initialDefaultColorScheme = palette?.mode, - cssVariables, ...rest } = options; const defaultColorSchemeInput = initialDefaultColorScheme || 'light'; @@ -68,6 +68,8 @@ export default function createTheme( if (cssVariables === false) { // @ts-expect-error ignore mismatch types here const theme = createThemeNoVars(options, ...args) as unknown as Theme; + theme.defaultColorScheme = defaultColorSchemeInput; + if (!('colorSchemes' in options)) { return theme; } @@ -83,7 +85,6 @@ export default function createTheme( attachColorScheme(theme, 'light', colorSchemesInput.light); } - theme.defaultColorScheme = defaultColorSchemeInput; return theme; } diff --git a/packages/mui-material/src/styles/defaultTheme.js b/packages/mui-material/src/styles/defaultTheme.js index d55f1451b7ab39..094155f2e31e4a 100644 --- a/packages/mui-material/src/styles/defaultTheme.js +++ b/packages/mui-material/src/styles/defaultTheme.js @@ -1,6 +1,6 @@ 'use client'; import createTheme from './createTheme'; -const defaultTheme = createTheme({ cssVariables: false }); +const defaultTheme = createTheme(); export default defaultTheme; diff --git a/packages/mui-material/src/styles/index.d.ts b/packages/mui-material/src/styles/index.d.ts index 91bc9feb99ea5d..fd3faae6edf11f 100644 --- a/packages/mui-material/src/styles/index.d.ts +++ b/packages/mui-material/src/styles/index.d.ts @@ -79,7 +79,7 @@ export { default as styled } from './styled'; * @deprecated will be removed in v5.beta, please use styled from @mui/material/styles instead */ export { default as experimentalStyled } from './styled'; -export { default as ThemeProvider } from './ThemeProvider'; +export { default as ThemeProvider } from './ThemeProvider/ThemeProvider'; export { ComponentsProps, ComponentsPropsList } from './props'; export { ComponentsVariants } from './variants'; export { ComponentsOverrides, ComponentNameToClassKey } from './overrides'; diff --git a/packages/mui-material/src/styles/index.js b/packages/mui-material/src/styles/index.js index c5ae7897133b15..3d6a29e531833b 100644 --- a/packages/mui-material/src/styles/index.js +++ b/packages/mui-material/src/styles/index.js @@ -37,7 +37,7 @@ export { default as useTheme } from './useTheme'; export { default as useThemeProps } from './useThemeProps'; export { default as styled } from './styled'; export { default as experimentalStyled } from './styled'; -export { default as ThemeProvider } from './ThemeProvider'; +export { default as ThemeProvider } from './ThemeProvider/ThemeProvider'; export { StyledEngineProvider } from '@mui/system'; // The legacy utilities from @mui/styles // These are just empty functions that throws when invoked diff --git a/packages/mui-material/src/styles/stringifyTheme.test.ts b/packages/mui-material/src/styles/stringifyTheme.test.ts index fb2ded3c8ca0c3..28715c26f95794 100644 --- a/packages/mui-material/src/styles/stringifyTheme.test.ts +++ b/packages/mui-material/src/styles/stringifyTheme.test.ts @@ -4,7 +4,7 @@ import { stringifyTheme } from './stringifyTheme'; describe('StringifyTheme', () => { it('should serialize the theme', () => { - const theme = createTheme(); + const theme = createTheme({ cssVariables: true }); const result = stringifyTheme({ breakpoints: theme.breakpoints, transitions: theme.transitions, @@ -60,6 +60,7 @@ export default theme;`); it('should serialize the custom theme', () => { const theme = createTheme({ + cssVariables: true, breakpoints: { values: { mobile: 0, @@ -126,7 +127,10 @@ export default theme;`); }); it('works with framework toRuntimeSource', () => { - const theme = { palette: { primary: { main: '#ff5252' } }, toRuntimeSource: stringifyTheme }; + const theme = { + palette: { primary: { main: '#ff5252' } }, + toRuntimeSource: stringifyTheme, + }; expect(theme.toRuntimeSource.call(theme, theme)).to .equal(`import { unstable_createBreakpoints as createBreakpoints, createTransitions } from '@mui/material/styles'; diff --git a/packages/mui-system/src/cssVars/useCurrentColorScheme.ts b/packages/mui-system/src/cssVars/useCurrentColorScheme.ts index 1c21e187d46c40..feb6f7582a0547 100644 --- a/packages/mui-system/src/cssVars/useCurrentColorScheme.ts +++ b/packages/mui-system/src/cssVars/useCurrentColorScheme.ts @@ -54,7 +54,11 @@ export type Result = State { - const handler = (...args: any) => mediaListener.current(...args); + if (typeof window.matchMedia === 'function') { + const handler = (...args: any) => mediaListener.current(...args); - // Always listen to System preference - const media = window.matchMedia('(prefers-color-scheme: dark)'); + // Always listen to System preference + const media = window.matchMedia('(prefers-color-scheme: dark)'); - // Intentionally use deprecated listener methods to support iOS & old browsers - media.addListener(handler); - handler(media); - return () => { - media.removeListener(handler); - }; + // Intentionally use deprecated listener methods to support iOS & old browsers + media.addListener(handler); + handler(media); + return () => { + media.removeListener(handler); + }; + } + return undefined; }, []); // Handle when localStorage has changed From 82aa32e051094f147ccf0149e82f51589c74291c Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 30 Jul 2024 15:38:10 +0700 Subject: [PATCH 11/82] fix export path --- packages/mui-material/src/styles/index.d.ts | 2 +- packages/mui-material/src/styles/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/mui-material/src/styles/index.d.ts b/packages/mui-material/src/styles/index.d.ts index fd3faae6edf11f..91bc9feb99ea5d 100644 --- a/packages/mui-material/src/styles/index.d.ts +++ b/packages/mui-material/src/styles/index.d.ts @@ -79,7 +79,7 @@ export { default as styled } from './styled'; * @deprecated will be removed in v5.beta, please use styled from @mui/material/styles instead */ export { default as experimentalStyled } from './styled'; -export { default as ThemeProvider } from './ThemeProvider/ThemeProvider'; +export { default as ThemeProvider } from './ThemeProvider'; export { ComponentsProps, ComponentsPropsList } from './props'; export { ComponentsVariants } from './variants'; export { ComponentsOverrides, ComponentNameToClassKey } from './overrides'; diff --git a/packages/mui-material/src/styles/index.js b/packages/mui-material/src/styles/index.js index 3d6a29e531833b..c5ae7897133b15 100644 --- a/packages/mui-material/src/styles/index.js +++ b/packages/mui-material/src/styles/index.js @@ -37,7 +37,7 @@ export { default as useTheme } from './useTheme'; export { default as useThemeProps } from './useThemeProps'; export { default as styled } from './styled'; export { default as experimentalStyled } from './styled'; -export { default as ThemeProvider } from './ThemeProvider/ThemeProvider'; +export { default as ThemeProvider } from './ThemeProvider'; export { StyledEngineProvider } from '@mui/system'; // The legacy utilities from @mui/styles // These are just empty functions that throws when invoked From 584056e80d74749429cc9e8591ecf517833b5bd7 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 30 Jul 2024 15:49:59 +0700 Subject: [PATCH 12/82] switch to enable method --- .../src/styles/ThemeProvider/ThemeProvider.tsx | 8 ++++---- .../styles/createTheme/createThemeNoVars.d.ts | 18 +++++++++--------- .../src/themeCssVarsAugmentation/index.d.ts | 10 +++++++--- .../src/cssVars/createCssVarsProvider.js | 9 +++++++-- 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx b/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx index d2b19fb9dc49f0..b83f8954f8eb3a 100644 --- a/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx +++ b/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx @@ -5,9 +5,8 @@ import { CssVarsProvider } from './ThemeProviderWithVars'; import { CssThemeVariables } from '../createTheme/createThemeNoVars'; import THEME_ID from '../identifier'; -type ThemeProviderCssVariablesProps = CssThemeVariables extends { disabled: true } - ? {} - : { +type ThemeProviderCssVariablesProps = CssThemeVariables extends { enabled: true } + ? { /** * The node for attaching the `theme.colorSchemeSelector`. * @default document @@ -24,7 +23,8 @@ type ThemeProviderCssVariablesProps = CssThemeVariables extends { disabled: true * @default false */ disableStyleSheetGeneration?: boolean; - }; + } + : {}; export interface ThemeProviderProps extends ThemeProviderCssVariablesProps { children?: React.ReactNode; diff --git a/packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts b/packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts index 56158975b9a699..88024dfbdea647 100644 --- a/packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts +++ b/packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts @@ -20,17 +20,17 @@ import { CssVarsTheme, CssVarsPalette, ColorSystemOptions } from './createThemeW * @example * declare module '@mui/material/styles' { * interface CssThemeVariables { - * disabled: true; + * enabled: true; * } * } */ export interface CssThemeVariables {} type CssVarsOptions = CssThemeVariables extends { - disabled: true; + enabled: true; } - ? {} - : ColorSystemOptions; + ? ColorSystemOptions + : {}; export interface ThemeOptions extends Omit, CssVarsOptions { mixins?: MixinsOptions; @@ -46,7 +46,7 @@ export interface ThemeOptions extends Omit, CssVar interface BaseTheme extends SystemTheme { mixins: Mixins; - palette: Palette & (CssThemeVariables extends { disabled: true } ? {} : CssVarsPalette); + palette: Palette & (CssThemeVariables extends { enabled: true } ? CssVarsPalette : {}); shadows: Shadows; transitions: Transitions; typography: Typography; @@ -57,9 +57,8 @@ interface BaseTheme extends SystemTheme { // shut off automatic exporting for the `BaseTheme` above export {}; -type CssVarsProperties = CssThemeVariables extends { disabled: true } - ? {} - : Pick< +type CssVarsProperties = CssThemeVariables extends { enabled: true } + ? Pick< CssVarsTheme, | 'applyStyles' | 'colorSchemes' @@ -73,7 +72,8 @@ type CssVarsProperties = CssThemeVariables extends { disabled: true } | 'generateSpacing' | 'shouldSkipGeneratingVar' | 'vars' - >; + > + : {}; /** * Our [TypeScript guide on theme customization](https://mui.com/material-ui/guides/typescript/#customization-of-theme) explains in detail how you would add custom properties. diff --git a/packages/mui-material/src/themeCssVarsAugmentation/index.d.ts b/packages/mui-material/src/themeCssVarsAugmentation/index.d.ts index d4c99da54c8601..1f5c2581bd14bd 100644 --- a/packages/mui-material/src/themeCssVarsAugmentation/index.d.ts +++ b/packages/mui-material/src/themeCssVarsAugmentation/index.d.ts @@ -1,5 +1,9 @@ /** - * @deprecated - * CSS theme variables are included in the types by default. There is no need to use this module. + * Enhance the theme types to include new properties from the CssVarsProvider. + * The theme is typed with CSS variables in `styled`, `sx`, `useTheme`, etc. */ -export {}; +declare module '@mui/material/styles' { + interface CssThemeVariables { + enabled: true; + } +} diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.js b/packages/mui-system/src/cssVars/createCssVarsProvider.js index 89772c060a34d5..89c592c527af58 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.js +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.js @@ -64,11 +64,16 @@ export default function createCssVarsProvider(options) { const scopedTheme = React.useMemo(() => { if (themeProp) { - return themeProp[themeId] || themeProp; + return themeProp[themeId]; } return typeof defaultTheme === 'function' ? defaultTheme() : defaultTheme; }, [themeProp]); - const { colorSchemes = {}, components = {}, cssVarPrefix, ...restThemeProp } = scopedTheme; + const { + colorSchemes = {}, + components = {}, + cssVarPrefix, + ...restThemeProp + } = scopedTheme || themeProp; const joinedColorSchemes = Object.keys(colorSchemes) .filter((k) => !!colorSchemes[k]) .join(','); From de9fb70f63e24f22fe6f5123a9d85f35a0cb2211 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 30 Jul 2024 16:32:22 +0700 Subject: [PATCH 13/82] fix types --- .../mui-material/src/styles/createTheme/createTheme.ts | 7 +++++-- .../mui-material/src/themeCssVarsAugmentation/index.d.ts | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/mui-material/src/styles/createTheme/createTheme.ts b/packages/mui-material/src/styles/createTheme/createTheme.ts index 4d4808bdcdf79d..1c0a128427eac9 100644 --- a/packages/mui-material/src/styles/createTheme/createTheme.ts +++ b/packages/mui-material/src/styles/createTheme/createTheme.ts @@ -67,13 +67,16 @@ export default function createTheme( if (cssVariables === false) { // @ts-expect-error ignore mismatch types here - const theme = createThemeNoVars(options, ...args) as unknown as Theme; - theme.defaultColorScheme = defaultColorSchemeInput; + const theme = createThemeNoVars(options, ...args) as unknown as Theme & { + defaultColorScheme?: 'light' | 'dark'; + colorSchemes?: Partial>; + }; if (!('colorSchemes' in options)) { return theme; } + theme.defaultColorScheme = defaultColorSchemeInput; theme.colorSchemes = {}; if (theme.palette.mode === 'light') { diff --git a/packages/mui-material/src/themeCssVarsAugmentation/index.d.ts b/packages/mui-material/src/themeCssVarsAugmentation/index.d.ts index 1f5c2581bd14bd..5db7c7a9419006 100644 --- a/packages/mui-material/src/themeCssVarsAugmentation/index.d.ts +++ b/packages/mui-material/src/themeCssVarsAugmentation/index.d.ts @@ -1,3 +1,4 @@ +export {}; /** * Enhance the theme types to include new properties from the CssVarsProvider. * The theme is typed with CSS variables in `styled`, `sx`, `useTheme`, etc. From d1b7783b0ce1dcc1863f67758e0b624d26a6bd72 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 30 Jul 2024 16:41:49 +0700 Subject: [PATCH 14/82] fix rsc --- packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx b/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx index b83f8954f8eb3a..5ddd02c98e86fa 100644 --- a/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx +++ b/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx @@ -1,3 +1,4 @@ +'use client'; import * as React from 'react'; import { DefaultTheme } from '@mui/system'; import ThemeProviderNoVars from './ThemeProviderNoVars'; From bfac926b50531ba4f3ebc7f2299a27b6dbbf1247 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 30 Jul 2024 16:41:52 +0700 Subject: [PATCH 15/82] fix test --- packages/mui-material/src/styles/createTheme.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/mui-material/src/styles/createTheme.test.js b/packages/mui-material/src/styles/createTheme.test.js index cdc00d2a9e95c7..3f1d9925a45a8f 100644 --- a/packages/mui-material/src/styles/createTheme.test.js +++ b/packages/mui-material/src/styles/createTheme.test.js @@ -52,7 +52,6 @@ describe('createTheme', () => { const theme = createTheme({ palette: { primary: { main: deepOrange[500] }, secondary: { main: green.A400 } }, }); - expect(theme.defaultColorScheme).to.equal('light'); expect(theme.palette.primary.main).to.equal(deepOrange[500]); expect(theme.palette.secondary.main).to.equal(green.A400); }); From 20d1da58c63a4b75b049b6b3e14fbe551b6d6b3d Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 30 Jul 2024 16:46:47 +0700 Subject: [PATCH 16/82] widen the type --- packages/mui-system/src/cssVars/createCssVarsProvider.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts b/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts index 8b79fbebd43f6c..542c6f9b016e01 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts @@ -50,7 +50,7 @@ export interface CreateCssVarsProviderResult< { cssVariables?: false; cssVarPrefix?: string; - colorSchemes: Record>; + colorSchemes: Partial>; colorSchemeSelector?: 'media' | 'class' | 'data' | string; } >; From e076c5cd1502fdd10a2de37f31eb65492260ee13 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 30 Jul 2024 17:04:05 +0700 Subject: [PATCH 17/82] Revert "fix all tests" This reverts commit 2603b25669d4815a8ef127a612ab8f28633c7236. --- packages/mui-lab/src/Masonry/Masonry.test.js | 2 +- .../mui-material/src/Drawer/Drawer.test.js | 16 +++++++------- packages/mui-material/src/Grid/Grid.test.js | 21 +++++++------------ .../src/Link/getTextDecoration.test.js | 2 +- .../mui-material/src/styles/styled.test.js | 3 --- .../mui-styles/test/theme-scoping.test.tsx | 1 - .../src/cssVars/createCssVarsProvider.test.js | 8 ++----- 7 files changed, 21 insertions(+), 32 deletions(-) diff --git a/packages/mui-lab/src/Masonry/Masonry.test.js b/packages/mui-lab/src/Masonry/Masonry.test.js index 5194f2b95e5efa..c5e56f2a0ac5b0 100644 --- a/packages/mui-lab/src/Masonry/Masonry.test.js +++ b/packages/mui-lab/src/Masonry/Masonry.test.js @@ -25,7 +25,7 @@ describe('', () => { }), ); - const theme = createTheme({ cssVariables: false, spacing: 8 }); + const theme = createTheme({ spacing: 8 }); const maxColumnHeight = 100; describe('render', () => { diff --git a/packages/mui-material/src/Drawer/Drawer.test.js b/packages/mui-material/src/Drawer/Drawer.test.js index 3755c159300c8c..2eee979d62a4d2 100644 --- a/packages/mui-material/src/Drawer/Drawer.test.js +++ b/packages/mui-material/src/Drawer/Drawer.test.js @@ -3,7 +3,6 @@ import { expect } from 'chai'; import { spy } from 'sinon'; import { createRenderer, screen } from '@mui/internal-test-utils'; import { ThemeProvider, createTheme } from '@mui/material/styles'; -import defaultTheme from '@mui/material/styles/defaultTheme'; import Drawer, { drawerClasses as classes } from '@mui/material/Drawer'; import { getAnchor, isHorizontal } from './Drawer'; import describeConformance from '../../test/describeConformance'; @@ -38,8 +37,8 @@ describe('', () => { if (/jsdom/.test(window.navigator.userAgent)) { this.skip(); } - const enteringScreenDurationInSeconds = - defaultTheme.transitions.duration.enteringScreen / 1000; + const theme = createTheme(); + const enteringScreenDurationInSeconds = theme.transitions.duration.enteringScreen / 1000; render(
@@ -322,13 +321,16 @@ describe('', () => { describe('zIndex', () => { it('should set correct zIndex on the root element', () => { + const theme = createTheme(); render( - -
- , + + +
+ + , ); expect(document.querySelector(`.${classes.root}`)).toHaveComputedStyle({ - zIndex: String(defaultTheme.zIndex.drawer), + zIndex: String(theme.zIndex.drawer), }); }); }); diff --git a/packages/mui-material/src/Grid/Grid.test.js b/packages/mui-material/src/Grid/Grid.test.js index 3912ff620302b4..68ce2ec894958f 100644 --- a/packages/mui-material/src/Grid/Grid.test.js +++ b/packages/mui-material/src/Grid/Grid.test.js @@ -155,13 +155,14 @@ describe('Material UI ', () => { }); it('should generate correct responsive styles regardless of breakpoints order', () => { + const theme = createTheme(); expect( generateDirection({ ownerState: { container: true, direction: { sm: 'column', xs: 'row' }, }, - theme: defaultTheme, + theme, }), ).to.deep.equal({ '@media (min-width:0px)': { @@ -209,7 +210,6 @@ describe('Material UI ', () => { it('should generate correct responsive styles regardless of custom breakpoints order', () => { const theme = createTheme({ - cssVariables: false, breakpoints: { keys: ['mobile', 'desktop'], values: { @@ -713,13 +713,14 @@ describe('Material UI ', () => { describe('prop: rowSpacing, columnSpacing', () => { it('should generate correct responsive styles', () => { + const theme = createTheme(); expect( generateRowGap({ ownerState: { container: true, rowSpacing: { xs: 1, sm: 2 }, }, - theme: defaultTheme, + theme, }), ).to.deep.equal({ '@media (min-width:0px)': { @@ -742,7 +743,7 @@ describe('Material UI ', () => { container: true, columnSpacing: { xs: 1, sm: 2 }, }, - theme: defaultTheme, + theme, }), ).to.deep.equal({ '@media (min-width:0px)': { @@ -764,7 +765,6 @@ describe('Material UI ', () => { it('should support custom breakpoints and generate correct responsive styles', () => { const theme = createTheme({ - cssVariables: false, breakpoints: { keys: ['mobile', 'desktop'], values: { @@ -824,7 +824,6 @@ describe('Material UI ', () => { it("shouldn't support custom breakpoints with values of zeros and shouldn't generate responsive styles", () => { const theme = createTheme({ - cssVariables: false, breakpoints: { keys: ['mobile', 'desktop'], values: { @@ -873,7 +872,6 @@ describe('Material UI ', () => { it("shouldn't support custom breakpoints without its spacing values and shouldn't generate responsive styles", () => { const theme = createTheme({ - cssVariables: false, breakpoints: { keys: ['mobile', 'desktop'], values: { @@ -920,7 +918,6 @@ describe('Material UI ', () => { it("should ignore custom breakpoints that doesn't exist in the theme and shouldn't generate responsive styles", () => { const theme = createTheme({ - cssVariables: false, breakpoints: { keys: ['mobile', 'desktop'], values: { @@ -966,13 +963,14 @@ describe('Material UI ', () => { }); it('should generate correct responsive styles regardless of breakpoints order ', () => { + const theme = createTheme(); expect( generateRowGap({ ownerState: { container: true, rowSpacing: { sm: 2, xs: 1 }, }, - theme: defaultTheme, + theme, }), ).to.deep.equal({ '@media (min-width:0px)': { @@ -995,7 +993,7 @@ describe('Material UI ', () => { container: true, columnSpacing: { sm: 2, xs: 1 }, }, - theme: defaultTheme, + theme, }), ).to.deep.equal({ '@media (min-width:0px)': { @@ -1017,7 +1015,6 @@ describe('Material UI ', () => { it('should generate correct responsive styles regardless of custom breakpoints order ', () => { const theme = createTheme({ - cssVariables: false, breakpoints: { keys: ['mobile', 'desktop'], values: { @@ -1077,7 +1074,6 @@ describe('Material UI ', () => { it('should generate correct responsive styles for overriding with zero value styles for higher breakpoints', () => { const theme = createTheme({ - cssVariables: false, breakpoints: { values: { mobile: 0, @@ -1212,7 +1208,6 @@ describe('Material UI ', () => { it('should not generate responsive styles for lower breakpoints below a given non-zero breakpoint', () => { const theme = createTheme({ - cssVariables: false, breakpoints: { values: { mobile: 0, diff --git a/packages/mui-material/src/Link/getTextDecoration.test.js b/packages/mui-material/src/Link/getTextDecoration.test.js index 11f89a5d3a554b..cf15c993b1d48c 100644 --- a/packages/mui-material/src/Link/getTextDecoration.test.js +++ b/packages/mui-material/src/Link/getTextDecoration.test.js @@ -4,7 +4,7 @@ import getTextDecoration from './getTextDecoration'; describe('getTextDecoration', () => { describe('without theme.vars', () => { - const theme = createTheme({ cssVariables: false }); + const theme = createTheme(); it('deprecated color', () => { expect(getTextDecoration({ theme, ownerState: { color: 'textPrimary' } })).to.equal( diff --git a/packages/mui-material/src/styles/styled.test.js b/packages/mui-material/src/styles/styled.test.js index 719596f0c8a315..b547370b18f569 100644 --- a/packages/mui-material/src/styles/styled.test.js +++ b/packages/mui-material/src/styles/styled.test.js @@ -62,7 +62,6 @@ describe('styled', () => { `; const theme = createTheme({ - cssVariables: false, spacing: 10, }); @@ -83,7 +82,6 @@ describe('styled', () => { })); const theme = createTheme({ - cssVariables: false, spacing: 10, }); @@ -142,7 +140,6 @@ describe('styled', () => { before(() => { theme = createTheme({ - cssVariables: false, palette: { primary: { main: 'rgb(0, 0, 255)', diff --git a/packages/mui-styles/test/theme-scoping.test.tsx b/packages/mui-styles/test/theme-scoping.test.tsx index 7c847d0208b8ef..2820deb0f12229 100644 --- a/packages/mui-styles/test/theme-scoping.test.tsx +++ b/packages/mui-styles/test/theme-scoping.test.tsx @@ -66,7 +66,6 @@ describe('Theme scoping', () => { { describe('[option]: `disableTransitionOnChange`', () => { clock.withFakeTimers(); - beforeEach(() => { - document.head.replaceChildren([]); - }); - it('disable all css transitions when switching between modes, given `disableTransitionOnChange` is true', () => { const { CssVarsProvider, useColorScheme } = createCssVarsProvider({ theme: createCssVarsTheme({ @@ -272,7 +268,7 @@ describe('createCssVarsProvider', () => { , ); - clock.runToLast(); + expect(document.head.children[document.head.children.length - 1]?.textContent).not.to.equal( DISABLE_CSS_TRANSITION, ); @@ -313,7 +309,7 @@ describe('createCssVarsProvider', () => { , ); - clock.runToLast(); + expect(document.head.children[document.head.children.length - 1]?.textContent).not.to.equal( DISABLE_CSS_TRANSITION, ); From 28873d05ecc5842631ffce7f67fb99c64af7056d Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 30 Jul 2024 17:06:03 +0700 Subject: [PATCH 18/82] fix disableTransitionOnChange test --- .../mui-system/src/cssVars/createCssVarsProvider.test.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.test.js b/packages/mui-system/src/cssVars/createCssVarsProvider.test.js index 6168066a83dac4..ec45a5d6c1e106 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.test.js +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.test.js @@ -243,6 +243,10 @@ describe('createCssVarsProvider', () => { describe('[option]: `disableTransitionOnChange`', () => { clock.withFakeTimers(); + beforeEach(() => { + document.head.replaceChildren([]); + }); + it('disable all css transitions when switching between modes, given `disableTransitionOnChange` is true', () => { const { CssVarsProvider, useColorScheme } = createCssVarsProvider({ theme: createCssVarsTheme({ @@ -268,7 +272,7 @@ describe('createCssVarsProvider', () => { , ); - + clock.runToLast(); expect(document.head.children[document.head.children.length - 1]?.textContent).not.to.equal( DISABLE_CSS_TRANSITION, ); @@ -309,7 +313,7 @@ describe('createCssVarsProvider', () => { , ); - + clock.runToLast(); expect(document.head.children[document.head.children.length - 1]?.textContent).not.to.equal( DISABLE_CSS_TRANSITION, ); From fd557f59e26ce8a679a7fb241825d86f863bfbf4 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 30 Jul 2024 17:40:55 +0700 Subject: [PATCH 19/82] fix getInitialTheme --- packages/mui-system/src/cssVars/createCssVarsProvider.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.js b/packages/mui-system/src/cssVars/createCssVarsProvider.js index 89c592c527af58..3b4665d3b35dd5 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.js +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.js @@ -62,18 +62,19 @@ export default function createCssVarsProvider(options) { const ctx = React.useContext(ColorSchemeContext); const nested = !!ctx && !disableNestedContext; - const scopedTheme = React.useMemo(() => { + const initialTheme = React.useMemo(() => { if (themeProp) { - return themeProp[themeId]; + return themeProp; } return typeof defaultTheme === 'function' ? defaultTheme() : defaultTheme; }, [themeProp]); + const scopedTheme = initialTheme[themeId]; const { colorSchemes = {}, components = {}, cssVarPrefix, ...restThemeProp - } = scopedTheme || themeProp; + } = scopedTheme || initialTheme; const joinedColorSchemes = Object.keys(colorSchemes) .filter((k) => !!colorSchemes[k]) .join(','); From 7337a7d658f2459c10441e9c9c28645324fd67d4 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 30 Jul 2024 17:54:14 +0700 Subject: [PATCH 20/82] add test --- .../src/cssVars/createCssVarsProvider.test.js | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.test.js b/packages/mui-system/src/cssVars/createCssVarsProvider.test.js index ec45a5d6c1e106..2431242d75fe5f 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.test.js +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.test.js @@ -2,6 +2,7 @@ import * as React from 'react'; import { expect } from 'chai'; import { spy } from 'sinon'; import { createRenderer, screen, fireEvent } from '@mui/internal-test-utils'; +import { ThemeProvider } from '@mui/system'; import createCssVarsTheme from './createCssVarsTheme'; import createCssVarsProvider, { DISABLE_CSS_TRANSITION } from './createCssVarsProvider'; import { @@ -896,5 +897,34 @@ describe('createCssVarsProvider', () => { expect(getByTestId('inner')).to.have.text('dark'); }); + + it('themeId should not exist in the theme if not provided as a prop', () => { + const { CssVarsProvider } = createCssVarsProvider({ + themeId: '$$foo', + theme: createCssVarsTheme({ + colorSchemes: { + light: { + color: 'light', + }, + dark: { + color: 'dark', + }, + }, + }), + defaultColorScheme: 'light', + }); + function Text() { + const theme = useTheme(); + return theme.$$foo ? 'failed' : 'passed'; + } + const { container } = render( + 'foo-bar' }}> + + + + , + ); + expect(container.textContent).to.equal('passed'); + }); }); }); From 7d8f6900644797bb643acfc783cf9825c522b208 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 30 Jul 2024 18:15:25 +0700 Subject: [PATCH 21/82] fix types --- packages/mui-material/src/styles/createTheme/createTheme.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/mui-material/src/styles/createTheme/createTheme.ts b/packages/mui-material/src/styles/createTheme/createTheme.ts index 1c0a128427eac9..380284b1b5d923 100644 --- a/packages/mui-material/src/styles/createTheme/createTheme.ts +++ b/packages/mui-material/src/styles/createTheme/createTheme.ts @@ -17,7 +17,7 @@ function attachColorScheme( palette: createPalette({ ...(colorScheme === true ? {} : colorScheme), mode: scheme, - }), + } as any), // cast type to skip module augmentation test }; } } @@ -40,7 +40,7 @@ export default function createTheme( | 'cssVarPrefix' | 'shouldSkipGeneratingVar' >; - } = {}, + } = {} as any, // cast type to skip module augmentation test ...args: object[] ): Theme { const { From 0bc2274db2b3d95fe1080246445702e4290c92b9 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 30 Jul 2024 18:21:44 +0700 Subject: [PATCH 22/82] flatten nested folder --- .../src/styles/CssVarsProvider.tsx | 5 +---- .../{ThemeProvider => }/ThemeProvider.tsx | 4 ++-- .../src/styles/ThemeProvider/index.ts | 2 -- .../ThemeProviderNoVars.tsx | 2 +- .../ThemeProviderWithVars.tsx | 11 ++++------- .../styles/{createTheme => }/createTheme.ts | 18 +++++++++++------- .../src/styles/createTheme/index.ts | 3 --- .../{createTheme => }/createThemeNoVars.d.ts | 14 +++++++------- .../{createTheme => }/createThemeNoVars.js | 12 ++++++------ .../{createTheme => }/createThemeWithVars.d.ts | 8 ++++---- .../{createTheme => }/createThemeWithVars.js | 8 ++++---- .../src/styles/experimental_extendTheme.js | 2 +- packages/mui-material/src/styles/index.d.ts | 4 ++-- packages/mui-material/src/styles/index.js | 2 +- 14 files changed, 44 insertions(+), 51 deletions(-) rename packages/mui-material/src/styles/{ThemeProvider => }/ThemeProvider.tsx (94%) delete mode 100644 packages/mui-material/src/styles/ThemeProvider/index.ts rename packages/mui-material/src/styles/{ThemeProvider => }/ThemeProviderNoVars.tsx (94%) rename packages/mui-material/src/styles/{ThemeProvider => }/ThemeProviderWithVars.tsx (88%) rename packages/mui-material/src/styles/{createTheme => }/createTheme.ts (85%) delete mode 100644 packages/mui-material/src/styles/createTheme/index.ts rename packages/mui-material/src/styles/{createTheme => }/createThemeNoVars.d.ts (87%) rename packages/mui-material/src/styles/{createTheme => }/createThemeNoVars.js (93%) rename packages/mui-material/src/styles/{createTheme => }/createThemeWithVars.d.ts (98%) rename packages/mui-material/src/styles/{createTheme => }/createThemeWithVars.js (98%) diff --git a/packages/mui-material/src/styles/CssVarsProvider.tsx b/packages/mui-material/src/styles/CssVarsProvider.tsx index 07b20ed8129b79..b7d747a75f36c5 100644 --- a/packages/mui-material/src/styles/CssVarsProvider.tsx +++ b/packages/mui-material/src/styles/CssVarsProvider.tsx @@ -2,10 +2,7 @@ import * as React from 'react'; import { unstable_createCssVarsProvider as createCssVarsProvider, SxProps } from '@mui/system'; import styleFunctionSx from '@mui/system/styleFunctionSx'; -import createThemeWithVars, { - SupportedColorScheme, - CssVarsTheme, -} from './createTheme/createThemeWithVars'; +import createThemeWithVars, { SupportedColorScheme, CssVarsTheme } from './createThemeWithVars'; import createTypography from './createTypography'; import THEME_ID from './identifier'; import { defaultConfig } from '../InitColorSchemeScript/InitColorSchemeScript'; diff --git a/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx b/packages/mui-material/src/styles/ThemeProvider.tsx similarity index 94% rename from packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx rename to packages/mui-material/src/styles/ThemeProvider.tsx index 5ddd02c98e86fa..2535372d254d04 100644 --- a/packages/mui-material/src/styles/ThemeProvider/ThemeProvider.tsx +++ b/packages/mui-material/src/styles/ThemeProvider.tsx @@ -3,8 +3,8 @@ import * as React from 'react'; import { DefaultTheme } from '@mui/system'; import ThemeProviderNoVars from './ThemeProviderNoVars'; import { CssVarsProvider } from './ThemeProviderWithVars'; -import { CssThemeVariables } from '../createTheme/createThemeNoVars'; -import THEME_ID from '../identifier'; +import { CssThemeVariables } from './createThemeNoVars'; +import THEME_ID from './identifier'; type ThemeProviderCssVariablesProps = CssThemeVariables extends { enabled: true } ? { diff --git a/packages/mui-material/src/styles/ThemeProvider/index.ts b/packages/mui-material/src/styles/ThemeProvider/index.ts deleted file mode 100644 index 8774f170cc1f73..00000000000000 --- a/packages/mui-material/src/styles/ThemeProvider/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default } from './ThemeProvider'; -export type { ThemeProviderProps } from './ThemeProvider'; diff --git a/packages/mui-material/src/styles/ThemeProvider/ThemeProviderNoVars.tsx b/packages/mui-material/src/styles/ThemeProviderNoVars.tsx similarity index 94% rename from packages/mui-material/src/styles/ThemeProvider/ThemeProviderNoVars.tsx rename to packages/mui-material/src/styles/ThemeProviderNoVars.tsx index c29773fcb49bfd..a7e78f37536c56 100644 --- a/packages/mui-material/src/styles/ThemeProvider/ThemeProviderNoVars.tsx +++ b/packages/mui-material/src/styles/ThemeProviderNoVars.tsx @@ -1,7 +1,7 @@ 'use client'; import * as React from 'react'; import { ThemeProvider as SystemThemeProvider, DefaultTheme } from '@mui/system'; -import THEME_ID from '../identifier'; +import THEME_ID from './identifier'; export interface ThemeProviderNoVarsProps { children?: React.ReactNode; diff --git a/packages/mui-material/src/styles/ThemeProvider/ThemeProviderWithVars.tsx b/packages/mui-material/src/styles/ThemeProviderWithVars.tsx similarity index 88% rename from packages/mui-material/src/styles/ThemeProvider/ThemeProviderWithVars.tsx rename to packages/mui-material/src/styles/ThemeProviderWithVars.tsx index f9526dc8a9fe72..b7d747a75f36c5 100644 --- a/packages/mui-material/src/styles/ThemeProvider/ThemeProviderWithVars.tsx +++ b/packages/mui-material/src/styles/ThemeProviderWithVars.tsx @@ -2,13 +2,10 @@ import * as React from 'react'; import { unstable_createCssVarsProvider as createCssVarsProvider, SxProps } from '@mui/system'; import styleFunctionSx from '@mui/system/styleFunctionSx'; -import createThemeWithVars, { - SupportedColorScheme, - CssVarsTheme, -} from '../createTheme/createThemeWithVars'; -import createTypography from '../createTypography'; -import THEME_ID from '../identifier'; -import { defaultConfig } from '../../InitColorSchemeScript/InitColorSchemeScript'; +import createThemeWithVars, { SupportedColorScheme, CssVarsTheme } from './createThemeWithVars'; +import createTypography from './createTypography'; +import THEME_ID from './identifier'; +import { defaultConfig } from '../InitColorSchemeScript/InitColorSchemeScript'; const { CssVarsProvider, diff --git a/packages/mui-material/src/styles/createTheme/createTheme.ts b/packages/mui-material/src/styles/createTheme.ts similarity index 85% rename from packages/mui-material/src/styles/createTheme/createTheme.ts rename to packages/mui-material/src/styles/createTheme.ts index 380284b1b5d923..559add7f926ca0 100644 --- a/packages/mui-material/src/styles/createTheme/createTheme.ts +++ b/packages/mui-material/src/styles/createTheme.ts @@ -1,7 +1,13 @@ -import createPalette from '../createPalette'; -import createThemeWithVars, { CssVarsThemeOptions, ColorSystem } from './createThemeWithVars'; +import createPalette from './createPalette'; +import createThemeWithVars, { + CssVarsThemeOptions, + ColorSystem, + DefaultColorScheme, +} from './createThemeWithVars'; import createThemeNoVars, { Theme, ThemeOptions } from './createThemeNoVars'; +export { createMuiTheme, ThemeOptions, Theme, CssThemeVariables } from './createThemeNoVars'; + // eslint-disable-next-line consistent-return function attachColorScheme( theme: { colorSchemes?: Partial> }, @@ -50,15 +56,14 @@ export default function createTheme( defaultColorScheme: initialDefaultColorScheme = palette?.mode, ...rest } = options; - const defaultColorSchemeInput = initialDefaultColorScheme || 'light'; + const defaultColorSchemeInput = (initialDefaultColorScheme as DefaultColorScheme) || 'light'; + const defaultScheme = initialColorSchemes?.[defaultColorSchemeInput]; const colorSchemesInput = { ...initialColorSchemes, ...(palette ? { [defaultColorSchemeInput]: { - ...(initialColorSchemes as undefined | Record<'light' | 'dark', any>)?.[ - defaultColorSchemeInput - ], + ...(typeof defaultScheme !== 'boolean' && defaultScheme), palette, }, } @@ -66,7 +71,6 @@ export default function createTheme( }; if (cssVariables === false) { - // @ts-expect-error ignore mismatch types here const theme = createThemeNoVars(options, ...args) as unknown as Theme & { defaultColorScheme?: 'light' | 'dark'; colorSchemes?: Partial>; diff --git a/packages/mui-material/src/styles/createTheme/index.ts b/packages/mui-material/src/styles/createTheme/index.ts deleted file mode 100644 index 1271ad03e2c19f..00000000000000 --- a/packages/mui-material/src/styles/createTheme/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { default } from './createTheme'; -export { createMuiTheme } from './createThemeNoVars'; -export type { CssThemeVariables, ThemeOptions, Theme } from './createThemeNoVars'; diff --git a/packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts b/packages/mui-material/src/styles/createThemeNoVars.d.ts similarity index 87% rename from packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts rename to packages/mui-material/src/styles/createThemeNoVars.d.ts index 88024dfbdea647..1b17234a324b27 100644 --- a/packages/mui-material/src/styles/createTheme/createThemeNoVars.d.ts +++ b/packages/mui-material/src/styles/createThemeNoVars.d.ts @@ -5,13 +5,13 @@ import { CSSObject, SxConfig, } from '@mui/system'; -import { Mixins, MixinsOptions } from '../createMixins'; -import { Palette, PaletteOptions } from '../createPalette'; -import { Typography, TypographyOptions } from '../createTypography'; -import { Shadows } from '../shadows'; -import { Transitions, TransitionsOptions } from '../createTransitions'; -import { ZIndex, ZIndexOptions } from '../zIndex'; -import { Components } from '../components'; +import { Mixins, MixinsOptions } from './createMixins'; +import { Palette, PaletteOptions } from './createPalette'; +import { Typography, TypographyOptions } from './createTypography'; +import { Shadows } from './shadows'; +import { Transitions, TransitionsOptions } from './createTransitions'; +import { ZIndex, ZIndexOptions } from './zIndex'; +import { Components } from './components'; import { CssVarsTheme, CssVarsPalette, ColorSystemOptions } from './createThemeWithVars'; /** diff --git a/packages/mui-material/src/styles/createTheme/createThemeNoVars.js b/packages/mui-material/src/styles/createThemeNoVars.js similarity index 93% rename from packages/mui-material/src/styles/createTheme/createThemeNoVars.js rename to packages/mui-material/src/styles/createThemeNoVars.js index 13b84b1877951a..527c29474994ec 100644 --- a/packages/mui-material/src/styles/createTheme/createThemeNoVars.js +++ b/packages/mui-material/src/styles/createThemeNoVars.js @@ -5,12 +5,12 @@ import styleFunctionSx, { import systemCreateTheme from '@mui/system/createTheme'; import MuiError from '@mui/internal-babel-macros/MuiError.macro'; import generateUtilityClass from '@mui/utils/generateUtilityClass'; -import createMixins from '../createMixins'; -import createPalette from '../createPalette'; -import createTypography from '../createTypography'; -import shadows from '../shadows'; -import createTransitions from '../createTransitions'; -import zIndex from '../zIndex'; +import createMixins from './createMixins'; +import createPalette from './createPalette'; +import createTypography from './createTypography'; +import shadows from './shadows'; +import createTransitions from './createTransitions'; +import zIndex from './zIndex'; function createThemeNoVars(options = {}, ...args) { const { diff --git a/packages/mui-material/src/styles/createTheme/createThemeWithVars.d.ts b/packages/mui-material/src/styles/createThemeWithVars.d.ts similarity index 98% rename from packages/mui-material/src/styles/createTheme/createThemeWithVars.d.ts rename to packages/mui-material/src/styles/createThemeWithVars.d.ts index ce6885ad9a38c3..5d5ff73ccde54d 100644 --- a/packages/mui-material/src/styles/createTheme/createThemeWithVars.d.ts +++ b/packages/mui-material/src/styles/createThemeWithVars.d.ts @@ -2,10 +2,10 @@ import { OverridableStringUnion } from '@mui/types'; import { SxConfig, SxProps, CSSObject, ApplyStyles } from '@mui/system'; import { ExtractTypographyTokens } from '@mui/system/cssVars'; import { ThemeOptions, Theme } from './createThemeNoVars'; -import { Palette, PaletteOptions } from '../createPalette'; -import { Shadows } from '../shadows'; -import { ZIndex } from '../zIndex'; -import { Components } from '../components'; +import { Palette, PaletteOptions } from './createPalette'; +import { Shadows } from './shadows'; +import { ZIndex } from './zIndex'; +import { Components } from './components'; /** * default MD color-schemes diff --git a/packages/mui-material/src/styles/createTheme/createThemeWithVars.js b/packages/mui-material/src/styles/createThemeWithVars.js similarity index 98% rename from packages/mui-material/src/styles/createTheme/createThemeWithVars.js rename to packages/mui-material/src/styles/createThemeWithVars.js index 015130c522df75..0680955506dfac 100644 --- a/packages/mui-material/src/styles/createTheme/createThemeWithVars.js +++ b/packages/mui-material/src/styles/createThemeWithVars.js @@ -21,10 +21,10 @@ import { } from '@mui/system/colorManipulator'; import createThemeNoVars from './createThemeNoVars'; -import defaultShouldSkipGeneratingVar from '../shouldSkipGeneratingVar'; -import getOverlayAlpha from '../getOverlayAlpha'; -import defaultGetSelector from '../createGetSelector'; -import { stringifyTheme } from '../stringifyTheme'; +import defaultShouldSkipGeneratingVar from './shouldSkipGeneratingVar'; +import getOverlayAlpha from './getOverlayAlpha'; +import defaultGetSelector from './createGetSelector'; +import { stringifyTheme } from './stringifyTheme'; const defaultDarkOverlays = [...Array(25)].map((_, index) => { if (index === 0) { diff --git a/packages/mui-material/src/styles/experimental_extendTheme.js b/packages/mui-material/src/styles/experimental_extendTheme.js index 51efb520f348f4..be0e6f349b9317 100644 --- a/packages/mui-material/src/styles/experimental_extendTheme.js +++ b/packages/mui-material/src/styles/experimental_extendTheme.js @@ -1,4 +1,4 @@ -import extendTheme from './createTheme/createThemeWithVars'; +import extendTheme from './createThemeWithVars'; let warnedOnce = false; diff --git a/packages/mui-material/src/styles/index.d.ts b/packages/mui-material/src/styles/index.d.ts index 91bc9feb99ea5d..bd872868d75e9e 100644 --- a/packages/mui-material/src/styles/index.d.ts +++ b/packages/mui-material/src/styles/index.d.ts @@ -101,7 +101,7 @@ export { default as withTheme } from './withTheme'; export * from './CssVarsProvider'; -export { default as extendTheme } from './createTheme/createThemeWithVars'; +export { default as extendTheme } from './createThemeWithVars'; export type { ColorSchemeOverrides, @@ -135,7 +135,7 @@ export type { ThemeCssVar, ThemeCssVarOverrides, ColorSystemOptions, -} from './createTheme/createThemeWithVars'; +} from './createThemeWithVars'; export { default as getOverlayAlpha } from './getOverlayAlpha'; export { default as shouldSkipGeneratingVar } from './shouldSkipGeneratingVar'; diff --git a/packages/mui-material/src/styles/index.js b/packages/mui-material/src/styles/index.js index c5ae7897133b15..ba89e85ad97def 100644 --- a/packages/mui-material/src/styles/index.js +++ b/packages/mui-material/src/styles/index.js @@ -46,7 +46,7 @@ export { default as withStyles } from './withStyles'; export { default as withTheme } from './withTheme'; export * from './CssVarsProvider'; -export { default as extendTheme } from './createTheme/createThemeWithVars'; +export { default as extendTheme } from './createThemeWithVars'; export { default as experimental_extendTheme } from './experimental_extendTheme'; // TODO: Remove in v7 export { default as getOverlayAlpha } from './getOverlayAlpha'; export { default as shouldSkipGeneratingVar } from './shouldSkipGeneratingVar'; From d239b2f590fa6fd64cccead97b1edd56e5b15093 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 30 Jul 2024 19:48:08 +0700 Subject: [PATCH 23/82] fix types --- packages/mui-material/src/styles/ThemeProvider.tsx | 4 ++-- packages/mui-material/src/styles/createTheme.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/mui-material/src/styles/ThemeProvider.tsx b/packages/mui-material/src/styles/ThemeProvider.tsx index 2535372d254d04..68d449b1624be7 100644 --- a/packages/mui-material/src/styles/ThemeProvider.tsx +++ b/packages/mui-material/src/styles/ThemeProvider.tsx @@ -4,6 +4,7 @@ import { DefaultTheme } from '@mui/system'; import ThemeProviderNoVars from './ThemeProviderNoVars'; import { CssVarsProvider } from './ThemeProviderWithVars'; import { CssThemeVariables } from './createThemeNoVars'; +import { CssVarsTheme } from './createThemeWithVars'; import THEME_ID from './identifier'; type ThemeProviderCssVariablesProps = CssThemeVariables extends { enabled: true } @@ -58,6 +59,5 @@ export default function ThemeProvider({ if (!('colorSchemes' in muiTheme)) { return ; } - // @ts-expect-error `theme` is created by `createTheme`, typing is handled there. - return ; + return ; } diff --git a/packages/mui-material/src/styles/createTheme.ts b/packages/mui-material/src/styles/createTheme.ts index 559add7f926ca0..32362a8d111ddf 100644 --- a/packages/mui-material/src/styles/createTheme.ts +++ b/packages/mui-material/src/styles/createTheme.ts @@ -71,7 +71,7 @@ export default function createTheme( }; if (cssVariables === false) { - const theme = createThemeNoVars(options, ...args) as unknown as Theme & { + const theme = createThemeNoVars(options as ThemeOptions, ...args) as unknown as Theme & { defaultColorScheme?: 'light' | 'dark'; colorSchemes?: Partial>; }; From cc970410f990858e9d68e0628577e21d07a7bf5b Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 31 Jul 2024 11:21:01 +0700 Subject: [PATCH 24/82] fix lint --- packages/mui-material/src/styles/createTheme.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/mui-material/src/styles/createTheme.ts b/packages/mui-material/src/styles/createTheme.ts index 32362a8d111ddf..813f20734455d4 100644 --- a/packages/mui-material/src/styles/createTheme.ts +++ b/packages/mui-material/src/styles/createTheme.ts @@ -6,7 +6,8 @@ import createThemeWithVars, { } from './createThemeWithVars'; import createThemeNoVars, { Theme, ThemeOptions } from './createThemeNoVars'; -export { createMuiTheme, ThemeOptions, Theme, CssThemeVariables } from './createThemeNoVars'; +export { createMuiTheme } from './createThemeNoVars'; +export type { ThemeOptions, Theme, CssThemeVariables } from './createThemeNoVars'; // eslint-disable-next-line consistent-return function attachColorScheme( From 24f9a887bb5d4b4d871ea57a16dc84af10d51eaf Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 31 Jul 2024 11:46:48 +0700 Subject: [PATCH 25/82] fix alpha usage --- docs/src/modules/components/Demo.js | 10 +++++----- docs/src/modules/components/DemoEditor.tsx | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/src/modules/components/Demo.js b/docs/src/modules/components/Demo.js index 2e40c05819796f..9db296fe554381 100644 --- a/docs/src/modules/components/Demo.js +++ b/docs/src/modules/components/Demo.js @@ -298,10 +298,10 @@ const DemoRootMaterial = styled('div', { }, style: { padding: theme.spacing(3), - backgroundColor: alpha((theme.vars || theme).palette.grey[50], 0.5), + backgroundColor: alpha(theme.palette.grey[50], 0.5), border: `1px solid ${(theme.vars || theme).palette.divider}`, ...theme.applyDarkStyles({ - backgroundColor: alpha((theme.vars || theme).palette.primaryDark[700], 0.4), + backgroundColor: alpha(theme.palette.primaryDark[700], 0.4), }), }, }, @@ -317,10 +317,10 @@ const DemoRootMaterial = styled('div', { borderRightWidth: 0, backgroundClip: 'padding-box', backgroundColor: alpha(theme.palette.primary[50], 0.2), - backgroundImage: `radial-gradient(120% 140% at 50% 10%, transparent 40%, ${alpha((theme.vars || theme).palette.primary[100], 0.2)} 70%)`, + backgroundImage: `radial-gradient(120% 140% at 50% 10%, transparent 40%, ${alpha(theme.palette.primary[100], 0.2)} 70%)`, ...theme.applyDarkStyles({ backgroundColor: (theme.vars || theme).palette.primaryDark[900], - backgroundImage: `radial-gradient(120% 140% at 50% 10%, transparent 30%, ${alpha((theme.vars || theme).palette.primary[900], 0.3)} 80%)`, + backgroundImage: `radial-gradient(120% 140% at 50% 10%, transparent 30%, ${alpha(theme.palette.primary[900], 0.3)} 80%)`, }), }, }, @@ -428,7 +428,7 @@ const selectionOverride = (theme) => ({ borderColor: (theme.vars || theme).palette.primary[200], ...theme.applyDarkStyles({ color: (theme.vars || theme).palette.primary[200], - backgroundColor: alpha((theme.vars || theme).palette.primary[900], 0.4), + backgroundColor: alpha(theme.palette.primary[900], 0.4), borderColor: (theme.vars || theme).palette.primary[800], }), }, diff --git a/docs/src/modules/components/DemoEditor.tsx b/docs/src/modules/components/DemoEditor.tsx index 6add281ed1fc95..b60ed7ead349f5 100644 --- a/docs/src/modules/components/DemoEditor.tsx +++ b/docs/src/modules/components/DemoEditor.tsx @@ -19,10 +19,10 @@ const StyledMarkdownElement = styled(MarkdownElement)(({ theme }) => [ border: 0, colorScheme: 'dark', '&:hover': { - boxShadow: `0 0 0 3px ${alpha((theme.vars || theme).palette.primary[500], 0.5)}`, + boxShadow: `0 0 0 3px ${alpha(theme.palette.primary[500], 0.5)}`, }, '&:focus-within': { - boxShadow: `0 0 0 3px ${alpha((theme.vars || theme).palette.primary[500], 0.8)}`, + boxShadow: `0 0 0 3px ${alpha(theme.palette.primary[500], 0.8)}`, }, [theme.breakpoints.up('sm')]: { borderRadius: '0 0 12px 12px', From 4e36f1ebc25e491ebaeb70a4ba131ed9c6a3f0fd Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 31 Jul 2024 11:46:55 +0700 Subject: [PATCH 26/82] fix naming --- packages/mui-material/src/styles/createThemeWithVars.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/mui-material/src/styles/createThemeWithVars.js b/packages/mui-material/src/styles/createThemeWithVars.js index 0680955506dfac..0ad31b06d5dcf6 100644 --- a/packages/mui-material/src/styles/createThemeWithVars.js +++ b/packages/mui-material/src/styles/createThemeWithVars.js @@ -133,14 +133,14 @@ function attachColorScheme(colorSchemes, scheme, restTheme, colorScheme) { } /** - * A default `extendTheme` comes with a single color scheme, either `light` or `dark` based on the `defaultColorScheme`. + * A default `createThemeWithVars` comes with a single color scheme, either `light` or `dark` based on the `defaultColorScheme`. * This is better suited for apps that only need a single color scheme. * * To enable built-in `light` and `dark` color schemes, either: * 1. provide a `colorSchemeSelector` to define how the color schemes will change. * 2. provide `colorSchemes.dark` will set `colorSchemeSelector: 'media'` by default. */ -export default function extendTheme(options = {}, ...args) { +export default function createThemeWithVars(options = {}, ...args) { const { colorSchemes: colorSchemesInput = { light: true }, defaultColorScheme: defaultColorSchemeInput, @@ -176,7 +176,7 @@ export default function extendTheme(options = {}, ...args) { if (!defaultScheme) { throw new MuiError( - 'MUI: The provided `colorSchemes.%s` to the `extendTheme` function is either missing or invalid.', + 'MUI: The provided `colorSchemes.%s` to the `createThemeWithVars` function is either missing or invalid.', defaultColorScheme, ); } From 9066fd1159aaa8299dc26f5cd5d0689b1acc3103 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 31 Jul 2024 12:04:12 +0700 Subject: [PATCH 27/82] remove function name --- packages/mui-material/src/styles/createThemeWithVars.js | 2 +- packages/mui-material/src/styles/extendTheme.test.js | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/mui-material/src/styles/createThemeWithVars.js b/packages/mui-material/src/styles/createThemeWithVars.js index 0ad31b06d5dcf6..84a6b997ee0cb8 100644 --- a/packages/mui-material/src/styles/createThemeWithVars.js +++ b/packages/mui-material/src/styles/createThemeWithVars.js @@ -176,7 +176,7 @@ export default function createThemeWithVars(options = {}, ...args) { if (!defaultScheme) { throw new MuiError( - 'MUI: The provided `colorSchemes.%s` to the `createThemeWithVars` function is either missing or invalid.', + 'MUI: The provided `colorSchemes.%s` is either missing or invalid.', defaultColorScheme, ); } diff --git a/packages/mui-material/src/styles/extendTheme.test.js b/packages/mui-material/src/styles/extendTheme.test.js index a92099aaebd178..2aebefacfd42e4 100644 --- a/packages/mui-material/src/styles/extendTheme.test.js +++ b/packages/mui-material/src/styles/extendTheme.test.js @@ -74,14 +74,12 @@ describe('extendTheme', () => { it('should throw error if the default color scheme is invalid', () => { expect(() => extendTheme({ colorSchemes: { dark: false }, defaultColorScheme: 'dark' }), - ).to.throw( - 'MUI: The provided `colorSchemes.dark` to the `extendTheme` function is either missing or invalid.', - ); + ).to.throw('MUI: The provided `colorSchemes.dark` is either missing or invalid.'); }); it('should throw error if the default color scheme is missing', () => { expect(() => extendTheme({ defaultColorScheme: 'paper' })).to.throw( - 'MUI: The provided `colorSchemes.paper` to the `extendTheme` function is either missing or invalid.', + 'MUI: The provided `colorSchemes.paper` is either missing or invalid.', ); }); From 7987ead5cc2a633ff996e05f20f83d79f4bd645a Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 31 Jul 2024 12:05:31 +0700 Subject: [PATCH 28/82] extract error code --- docs/public/static/error-codes.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/public/static/error-codes.json b/docs/public/static/error-codes.json index 87ced849443515..bc0f3460206f7b 100644 --- a/docs/public/static/error-codes.json +++ b/docs/public/static/error-codes.json @@ -21,5 +21,6 @@ "20": "MUI: The `experimental_sx` has been moved to `theme.unstable_sx`.For more details, see https://github.com/mui/material-ui/pull/35150.", "21": "MUI: The provided shorthand %s is invalid. The format should be `@` or `@/`.\nFor example, `@sm` or `@600` or `@40rem/sidebar`.", "22": "MUI: Missing or invalid value of `colorSchemes.%s` from the `extendTheme` function.", - "23": "MUI: The provided `colorSchemes.%s` to the `extendTheme` function is either missing or invalid." -} + "23": "MUI: The provided `colorSchemes.%s` to the `extendTheme` function is either missing or invalid.", + "24": "MUI: The provided `colorSchemes.%s` is either missing or invalid." +} \ No newline at end of file From 351deb2488d3db4ca81fa0de805c971bb6e63dcf Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 31 Jul 2024 12:51:45 +0700 Subject: [PATCH 29/82] revert unnecessary change --- docs/src/modules/components/AppLayoutDocsFooter.js | 6 +++--- docs/src/modules/components/Demo.js | 10 +++++----- docs/src/modules/components/DemoEditor.tsx | 4 ++-- docs/src/modules/components/DiamondSponsors.js | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/src/modules/components/AppLayoutDocsFooter.js b/docs/src/modules/components/AppLayoutDocsFooter.js index 36945feb5f55b4..bba181c105ad87 100644 --- a/docs/src/modules/components/AppLayoutDocsFooter.js +++ b/docs/src/modules/components/AppLayoutDocsFooter.js @@ -39,9 +39,9 @@ const FooterLink = styled(Link)(({ theme }) => { display: 'flex', alignItems: 'center', gap: 2, - fontFamily: theme.typography.fontFamily, - fontSize: theme.typography.pxToRem(13), - fontWeight: theme.typography.fontWeightMedium, + fontFamily: (theme.vars || theme).typography.fontFamily, + fontSize: (theme.vars || theme).typography.pxToRem(13), + fontWeight: (theme.vars || theme).typography.fontWeightMedium, color: (theme.vars || theme).palette.primary[600], '& > svg': { fontSize: '13px', transition: '0.2s' }, '&:hover > svg': { transform: 'translateX(2px)' }, diff --git a/docs/src/modules/components/Demo.js b/docs/src/modules/components/Demo.js index 9db296fe554381..2e40c05819796f 100644 --- a/docs/src/modules/components/Demo.js +++ b/docs/src/modules/components/Demo.js @@ -298,10 +298,10 @@ const DemoRootMaterial = styled('div', { }, style: { padding: theme.spacing(3), - backgroundColor: alpha(theme.palette.grey[50], 0.5), + backgroundColor: alpha((theme.vars || theme).palette.grey[50], 0.5), border: `1px solid ${(theme.vars || theme).palette.divider}`, ...theme.applyDarkStyles({ - backgroundColor: alpha(theme.palette.primaryDark[700], 0.4), + backgroundColor: alpha((theme.vars || theme).palette.primaryDark[700], 0.4), }), }, }, @@ -317,10 +317,10 @@ const DemoRootMaterial = styled('div', { borderRightWidth: 0, backgroundClip: 'padding-box', backgroundColor: alpha(theme.palette.primary[50], 0.2), - backgroundImage: `radial-gradient(120% 140% at 50% 10%, transparent 40%, ${alpha(theme.palette.primary[100], 0.2)} 70%)`, + backgroundImage: `radial-gradient(120% 140% at 50% 10%, transparent 40%, ${alpha((theme.vars || theme).palette.primary[100], 0.2)} 70%)`, ...theme.applyDarkStyles({ backgroundColor: (theme.vars || theme).palette.primaryDark[900], - backgroundImage: `radial-gradient(120% 140% at 50% 10%, transparent 30%, ${alpha(theme.palette.primary[900], 0.3)} 80%)`, + backgroundImage: `radial-gradient(120% 140% at 50% 10%, transparent 30%, ${alpha((theme.vars || theme).palette.primary[900], 0.3)} 80%)`, }), }, }, @@ -428,7 +428,7 @@ const selectionOverride = (theme) => ({ borderColor: (theme.vars || theme).palette.primary[200], ...theme.applyDarkStyles({ color: (theme.vars || theme).palette.primary[200], - backgroundColor: alpha(theme.palette.primary[900], 0.4), + backgroundColor: alpha((theme.vars || theme).palette.primary[900], 0.4), borderColor: (theme.vars || theme).palette.primary[800], }), }, diff --git a/docs/src/modules/components/DemoEditor.tsx b/docs/src/modules/components/DemoEditor.tsx index b60ed7ead349f5..6add281ed1fc95 100644 --- a/docs/src/modules/components/DemoEditor.tsx +++ b/docs/src/modules/components/DemoEditor.tsx @@ -19,10 +19,10 @@ const StyledMarkdownElement = styled(MarkdownElement)(({ theme }) => [ border: 0, colorScheme: 'dark', '&:hover': { - boxShadow: `0 0 0 3px ${alpha(theme.palette.primary[500], 0.5)}`, + boxShadow: `0 0 0 3px ${alpha((theme.vars || theme).palette.primary[500], 0.5)}`, }, '&:focus-within': { - boxShadow: `0 0 0 3px ${alpha(theme.palette.primary[500], 0.8)}`, + boxShadow: `0 0 0 3px ${alpha((theme.vars || theme).palette.primary[500], 0.8)}`, }, [theme.breakpoints.up('sm')]: { borderRadius: '0 0 12px 12px', diff --git a/docs/src/modules/components/DiamondSponsors.js b/docs/src/modules/components/DiamondSponsors.js index 7061bf89cce463..607abd325b3cff 100644 --- a/docs/src/modules/components/DiamondSponsors.js +++ b/docs/src/modules/components/DiamondSponsors.js @@ -27,7 +27,7 @@ const NativeLink = styled('a')(({ theme }) => ({ backgroundColor: (theme.vars || theme).palette.grey[50], }, '&:focus-visible': { - outline: `3px solid ${alpha(theme.palette.primary[500], 0.5)}`, + outline: `3px solid ${alpha((theme.vars || theme).palette.primary[500], 0.5)}`, outlineOffset: '-3px', }, '& img': { From 5e0ae73e188424274523c33eb38e948ca420db74 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 31 Jul 2024 12:53:09 +0700 Subject: [PATCH 30/82] refine condition --- packages/mui-material/src/CssBaseline/CssBaseline.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/mui-material/src/CssBaseline/CssBaseline.js b/packages/mui-material/src/CssBaseline/CssBaseline.js index 4dd736f771de5d..f6d01420222714 100644 --- a/packages/mui-material/src/CssBaseline/CssBaseline.js +++ b/packages/mui-material/src/CssBaseline/CssBaseline.js @@ -31,7 +31,11 @@ export const body = (theme) => ({ export const styles = (theme, enableColorScheme = false) => { const colorSchemeStyles = {}; - if (enableColorScheme && theme.vars) { + if ( + enableColorScheme && + theme.colorSchemes && + typeof theme.getColorSchemeSelector === 'function' + ) { Object.entries(theme.colorSchemes).forEach(([key, scheme]) => { const selector = theme.getColorSchemeSelector(key); if (selector.startsWith('@')) { From 44f6618c7b3f6d46c76c08a88a279fddd87113be Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 31 Jul 2024 14:29:08 +0700 Subject: [PATCH 31/82] remove CssVarsProvider file --- .../src/styles/CssVarsProvider.tsx | 76 ------------------- .../src/styles/ThemeProvider.test.tsx | 69 +++++++++++++++++ .../mui-material/src/styles/ThemeProvider.tsx | 2 +- ...pec.tsx => ThemeProviderWithVars.spec.tsx} | 0 ....test.js => ThemeProviderWithVars.test.js} | 2 +- packages/mui-material/src/styles/index.d.ts | 2 +- packages/mui-material/src/styles/index.js | 2 +- .../src/cssVars/createCssVarsProvider.js | 2 +- 8 files changed, 74 insertions(+), 81 deletions(-) delete mode 100644 packages/mui-material/src/styles/CssVarsProvider.tsx create mode 100644 packages/mui-material/src/styles/ThemeProvider.test.tsx rename packages/mui-material/src/styles/{CssVarsProvider.spec.tsx => ThemeProviderWithVars.spec.tsx} (100%) rename packages/mui-material/src/styles/{CssVarsProvider.test.js => ThemeProviderWithVars.test.js} (99%) diff --git a/packages/mui-material/src/styles/CssVarsProvider.tsx b/packages/mui-material/src/styles/CssVarsProvider.tsx deleted file mode 100644 index b7d747a75f36c5..00000000000000 --- a/packages/mui-material/src/styles/CssVarsProvider.tsx +++ /dev/null @@ -1,76 +0,0 @@ -'use client'; -import * as React from 'react'; -import { unstable_createCssVarsProvider as createCssVarsProvider, SxProps } from '@mui/system'; -import styleFunctionSx from '@mui/system/styleFunctionSx'; -import createThemeWithVars, { SupportedColorScheme, CssVarsTheme } from './createThemeWithVars'; -import createTypography from './createTypography'; -import THEME_ID from './identifier'; -import { defaultConfig } from '../InitColorSchemeScript/InitColorSchemeScript'; - -const { - CssVarsProvider, - useColorScheme, - getInitColorSchemeScript: deprecatedGetInitColorSchemeScript, -} = createCssVarsProvider({ - themeId: THEME_ID, - theme: createThemeWithVars, - colorSchemeStorageKey: defaultConfig.colorSchemeStorageKey, - modeStorageKey: defaultConfig.modeStorageKey, - defaultColorScheme: { - light: defaultConfig.defaultLightColorScheme, - dark: defaultConfig.defaultDarkColorScheme, - }, - resolveTheme: (theme) => { - const newTheme = { - ...theme, - typography: createTypography(theme.palette, theme.typography), - }; - - newTheme.unstable_sx = function sx(props: SxProps) { - return styleFunctionSx({ sx: props, theme: this }); - }; - - return newTheme; - }, -}); - -let warnedOnce = false; - -// TODO: remove in v7 -// eslint-disable-next-line @typescript-eslint/naming-convention -function Experimental_CssVarsProvider(props: any) { - if (!warnedOnce) { - console.warn( - [ - 'MUI: The Experimental_CssVarsProvider component has been stabilized.', - '', - "You should use `import { CssVarsProvider } from '@mui/material/styles'`", - ].join('\n'), - ); - - warnedOnce = true; - } - - return ; -} - -let warnedInitScriptOnce = false; - -// TODO: remove in v7 -const getInitColorSchemeScript: typeof deprecatedGetInitColorSchemeScript = (params) => { - if (!warnedInitScriptOnce) { - console.warn( - [ - 'MUI: The getInitColorSchemeScript function has been deprecated.', - '', - "You should use `import InitColorSchemeScript from '@mui/material/InitColorSchemeScript'`", - 'and replace the function call with `` instead.', - ].join('\n'), - ); - - warnedInitScriptOnce = true; - } - return deprecatedGetInitColorSchemeScript(params); -}; - -export { useColorScheme, CssVarsProvider, getInitColorSchemeScript, Experimental_CssVarsProvider }; diff --git a/packages/mui-material/src/styles/ThemeProvider.test.tsx b/packages/mui-material/src/styles/ThemeProvider.test.tsx new file mode 100644 index 00000000000000..93f461421efef1 --- /dev/null +++ b/packages/mui-material/src/styles/ThemeProvider.test.tsx @@ -0,0 +1,69 @@ +import * as React from 'react'; +import { expect } from 'chai'; +import { createRenderer, fireEvent } from '@mui/internal-test-utils'; +import { ThemeProvider, createTheme, useColorScheme } from '@mui/material/styles'; + +describe('ThemeProvider', () => { + const { render } = createRenderer(); + + it('When theme is a function, it should not show warning', () => { + expect(() => + render( + + ({})} /> + , + ), + ).not.toWarnDev(); + }); + + describe('light & dark', () => { + const ModeSwitcher = () => { + const { mode, setMode } = useColorScheme(); + if (!mode) { + return null; + } + return ( + + ); + }; + it('should be able to use `useColorScheme`', () => { + const theme = createTheme({ + colorSchemes: { dark: true }, + }); + expect(() => + render( + + + , + ), + ).not.toErrorDev(); + }); + + it('should be able to switch between modes', () => { + const theme = createTheme({ + colorSchemes: { dark: true }, + }); + const { getByTestId } = render( + + + , + ); + + expect(getByTestId('mode-switcher')).to.have.property('value', 'system'); + + fireEvent.change(getByTestId('mode-switcher'), { target: { value: 'dark' } }); + + expect(getByTestId('mode-switcher')).to.have.property('value', 'dark'); + }); + }); +}); diff --git a/packages/mui-material/src/styles/ThemeProvider.tsx b/packages/mui-material/src/styles/ThemeProvider.tsx index 68d449b1624be7..7a566e6ea4b066 100644 --- a/packages/mui-material/src/styles/ThemeProvider.tsx +++ b/packages/mui-material/src/styles/ThemeProvider.tsx @@ -2,8 +2,8 @@ import * as React from 'react'; import { DefaultTheme } from '@mui/system'; import ThemeProviderNoVars from './ThemeProviderNoVars'; -import { CssVarsProvider } from './ThemeProviderWithVars'; import { CssThemeVariables } from './createThemeNoVars'; +import { CssVarsProvider } from './ThemeProviderWithVars'; import { CssVarsTheme } from './createThemeWithVars'; import THEME_ID from './identifier'; diff --git a/packages/mui-material/src/styles/CssVarsProvider.spec.tsx b/packages/mui-material/src/styles/ThemeProviderWithVars.spec.tsx similarity index 100% rename from packages/mui-material/src/styles/CssVarsProvider.spec.tsx rename to packages/mui-material/src/styles/ThemeProviderWithVars.spec.tsx diff --git a/packages/mui-material/src/styles/CssVarsProvider.test.js b/packages/mui-material/src/styles/ThemeProviderWithVars.test.js similarity index 99% rename from packages/mui-material/src/styles/CssVarsProvider.test.js rename to packages/mui-material/src/styles/ThemeProviderWithVars.test.js index 6dfd78746c7213..9629a94028f37b 100644 --- a/packages/mui-material/src/styles/CssVarsProvider.test.js +++ b/packages/mui-material/src/styles/ThemeProviderWithVars.test.js @@ -4,7 +4,7 @@ import { createRenderer, screen } from '@mui/internal-test-utils'; import Box from '@mui/material/Box'; import { CssVarsProvider, extendTheme, useTheme } from '@mui/material/styles'; -describe('[Material UI] CssVarsProvider', () => { +describe('[Material UI] ThemeProviderWithVars', () => { let originalMatchmedia; const { render } = createRenderer(); const storage = {}; diff --git a/packages/mui-material/src/styles/index.d.ts b/packages/mui-material/src/styles/index.d.ts index bd872868d75e9e..38dbdac7b6078b 100644 --- a/packages/mui-material/src/styles/index.d.ts +++ b/packages/mui-material/src/styles/index.d.ts @@ -99,7 +99,7 @@ export { default as makeStyles } from './makeStyles'; export { default as withStyles } from './withStyles'; export { default as withTheme } from './withTheme'; -export * from './CssVarsProvider'; +export * from './ThemeProviderWithVars'; export { default as extendTheme } from './createThemeWithVars'; diff --git a/packages/mui-material/src/styles/index.js b/packages/mui-material/src/styles/index.js index ba89e85ad97def..08a68e212b13c3 100644 --- a/packages/mui-material/src/styles/index.js +++ b/packages/mui-material/src/styles/index.js @@ -45,7 +45,7 @@ export { default as makeStyles } from './makeStyles'; export { default as withStyles } from './withStyles'; export { default as withTheme } from './withTheme'; -export * from './CssVarsProvider'; +export * from './ThemeProviderWithVars'; export { default as extendTheme } from './createThemeWithVars'; export { default as experimental_extendTheme } from './experimental_extendTheme'; // TODO: Remove in v7 export { default as getOverlayAlpha } from './getOverlayAlpha'; diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.js b/packages/mui-system/src/cssVars/createCssVarsProvider.js index 3b4665d3b35dd5..4385def1bd42c8 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.js +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.js @@ -281,7 +281,7 @@ export default function createCssVarsProvider(options) { ); - if (nested && restThemeProp.cssVariables !== false) { + if (nested) { return element; } From eea2f01a513b7d2f4540b9c8d2364fadf6e12648 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 31 Jul 2024 14:32:18 +0700 Subject: [PATCH 32/82] prettier --- docs/public/static/error-codes.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/public/static/error-codes.json b/docs/public/static/error-codes.json index bc0f3460206f7b..1e9aba3c5a3e2b 100644 --- a/docs/public/static/error-codes.json +++ b/docs/public/static/error-codes.json @@ -23,4 +23,4 @@ "22": "MUI: Missing or invalid value of `colorSchemes.%s` from the `extendTheme` function.", "23": "MUI: The provided `colorSchemes.%s` to the `extendTheme` function is either missing or invalid.", "24": "MUI: The provided `colorSchemes.%s` is either missing or invalid." -} \ No newline at end of file +} From 40a78a41d8f265d544df34691dbbdb5a3486c1b4 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 31 Jul 2024 15:25:01 +0700 Subject: [PATCH 33/82] fix test --- .../src/styles/ThemeProvider.test.tsx | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/packages/mui-material/src/styles/ThemeProvider.test.tsx b/packages/mui-material/src/styles/ThemeProvider.test.tsx index 93f461421efef1..82e086c0a21921 100644 --- a/packages/mui-material/src/styles/ThemeProvider.test.tsx +++ b/packages/mui-material/src/styles/ThemeProvider.test.tsx @@ -5,6 +5,32 @@ import { ThemeProvider, createTheme, useColorScheme } from '@mui/material/styles describe('ThemeProvider', () => { const { render } = createRenderer(); + let originalMatchmedia: typeof window.matchMedia; + let storage: Record = {}; + + beforeEach(() => { + originalMatchmedia = window.matchMedia; + // Create mocks of localStorage getItem and setItem functions + storage = {}; + Object.defineProperty(global, 'localStorage', { + value: { + getItem: (key: string) => storage[key], + setItem: (key: string, value: string) => { + storage[key] = value; + }, + }, + configurable: true, + }); + window.matchMedia = () => + ({ + addListener: () => {}, + removeListener: () => {}, + }) as unknown as MediaQueryList; + }); + + afterEach(() => { + window.matchMedia = originalMatchmedia; + }); it('When theme is a function, it should not show warning', () => { expect(() => @@ -17,7 +43,7 @@ describe('ThemeProvider', () => { }); describe('light & dark', () => { - const ModeSwitcher = () => { + function ModeSwitcher() { const { mode, setMode } = useColorScheme(); if (!mode) { return null; @@ -35,7 +61,8 @@ describe('ThemeProvider', () => { ); - }; + } + it('should be able to use `useColorScheme`', () => { const theme = createTheme({ colorSchemes: { dark: true }, From 6b5f671016135c6c00b1e9aadb3e7904e4a7c8fa Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 31 Jul 2024 15:42:24 +0700 Subject: [PATCH 34/82] add missing types --- packages/mui-material/src/styles/ThemeProvider.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/mui-material/src/styles/ThemeProvider.tsx b/packages/mui-material/src/styles/ThemeProvider.tsx index 7a566e6ea4b066..cf8775ad32b0e2 100644 --- a/packages/mui-material/src/styles/ThemeProvider.tsx +++ b/packages/mui-material/src/styles/ThemeProvider.tsx @@ -41,6 +41,16 @@ export interface ThemeProviderProps extends ThemeProviderC * @default window */ storageWindow?: Window | null; + /** + * localStorage key used to store application `mode` + * @default 'mui-mode' + */ + modeStorageKey?: string; + /** + * localStorage key used to store `colorScheme` + * @default 'mui-color-scheme' + */ + colorSchemeStorageKey?: string; /** * Disable CSS transitions when switching between modes or color schemes * @default false From 000588831e1f33f1d9d7dca0a2cd68796943542b Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 31 Jul 2024 15:42:41 +0700 Subject: [PATCH 35/82] support 'class' and 'data' for InitColorSchemeScript --- .../InitColorSchemeScript.test.js | 20 +++++++++++++++++++ .../InitColorSchemeScript.tsx | 11 ++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/packages/mui-system/src/InitColorSchemeScript/InitColorSchemeScript.test.js b/packages/mui-system/src/InitColorSchemeScript/InitColorSchemeScript.test.js index 50f9ae3330d383..f081fe25f2200e 100644 --- a/packages/mui-system/src/InitColorSchemeScript/InitColorSchemeScript.test.js +++ b/packages/mui-system/src/InitColorSchemeScript/InitColorSchemeScript.test.js @@ -46,6 +46,26 @@ describe('InitColorSchemeScript', () => { expect(document.documentElement.getAttribute(DEFAULT_ATTRIBUTE)).to.equal('foo'); }); + it('should set `light` color scheme with class', () => { + storage[DEFAULT_MODE_STORAGE_KEY] = 'light'; + storage[`${DEFAULT_COLOR_SCHEME_STORAGE_KEY}-light`] = 'foo'; + document.documentElement.classList.remove(...document.documentElement.classList); + + const { container } = render(); + eval(container.firstChild.textContent); + expect(document.documentElement.classList.value).to.equal('foo'); + document.documentElement.classList.remove('foo'); // cleanup + }); + + it('should set `light` color scheme with data', () => { + storage[DEFAULT_MODE_STORAGE_KEY] = 'light'; + storage[`${DEFAULT_COLOR_SCHEME_STORAGE_KEY}-light`] = 'foo'; + + const { container } = render(); + eval(container.firstChild.textContent); + expect(document.documentElement.getAttribute('data-foo')).to.equal(''); + }); + it('should set custom color scheme to body with custom attribute', () => { storage['mui-foo-mode'] = 'light'; storage[`mui-bar-color-scheme-light`] = 'flash'; diff --git a/packages/mui-system/src/InitColorSchemeScript/InitColorSchemeScript.tsx b/packages/mui-system/src/InitColorSchemeScript/InitColorSchemeScript.tsx index 3d537ed6087971..7320bb7c10af42 100644 --- a/packages/mui-system/src/InitColorSchemeScript/InitColorSchemeScript.tsx +++ b/packages/mui-system/src/InitColorSchemeScript/InitColorSchemeScript.tsx @@ -40,7 +40,7 @@ export interface InitColorSchemeScriptProps { * @example '.mode-%s' // for class based color scheme * @example '[data-mode-%s]' // for data-attribute without '=' */ - attribute?: string; + attribute?: 'class' | 'data' | string; /** * Nonce string to pass to the inline script for CSP headers */ @@ -53,11 +53,18 @@ export default function InitColorSchemeScript(options?: InitColorSchemeScriptPro defaultDarkColorScheme = 'dark', modeStorageKey = DEFAULT_MODE_STORAGE_KEY, colorSchemeStorageKey = DEFAULT_COLOR_SCHEME_STORAGE_KEY, - attribute = DEFAULT_ATTRIBUTE, + attribute: initialAttribute = DEFAULT_ATTRIBUTE, colorSchemeNode = 'document.documentElement', nonce, } = options || {}; let setter = ''; + let attribute = initialAttribute; + if (initialAttribute === 'class') { + attribute = '.%s'; + } + if (initialAttribute === 'data') { + attribute = '[data-%s]'; + } if (attribute.startsWith('.')) { const selector = attribute.substring(1); setter += `${colorSchemeNode}.classList.remove('${selector}'.replace('%s', light), '${selector}'.replace('%s', dark)); From 6689fa2c2e3ac26b5d8623043159dc0d66dceee8 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 31 Jul 2024 16:22:47 +0700 Subject: [PATCH 36/82] fix error code --- docs/public/static/error-codes.json | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/public/static/error-codes.json b/docs/public/static/error-codes.json index 1e9aba3c5a3e2b..68f720382acf75 100644 --- a/docs/public/static/error-codes.json +++ b/docs/public/static/error-codes.json @@ -21,6 +21,5 @@ "20": "MUI: The `experimental_sx` has been moved to `theme.unstable_sx`.For more details, see https://github.com/mui/material-ui/pull/35150.", "21": "MUI: The provided shorthand %s is invalid. The format should be `@` or `@/`.\nFor example, `@sm` or `@600` or `@40rem/sidebar`.", "22": "MUI: Missing or invalid value of `colorSchemes.%s` from the `extendTheme` function.", - "23": "MUI: The provided `colorSchemes.%s` to the `extendTheme` function is either missing or invalid.", "24": "MUI: The provided `colorSchemes.%s` is either missing or invalid." } From df4e18978164ed7dd212b2189d9ccedae014be64 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 31 Jul 2024 16:29:04 +0700 Subject: [PATCH 37/82] refactor for code review --- .../src/cssVars/useCurrentColorScheme.ts | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/mui-system/src/cssVars/useCurrentColorScheme.ts b/packages/mui-system/src/cssVars/useCurrentColorScheme.ts index feb6f7582a0547..dd35a3fec8d877 100644 --- a/packages/mui-system/src/cssVars/useCurrentColorScheme.ts +++ b/packages/mui-system/src/cssVars/useCurrentColorScheme.ts @@ -286,20 +286,20 @@ export default function useCurrentColorScheme { - if (typeof window.matchMedia === 'function') { - const handler = (...args: any) => mediaListener.current(...args); + if (typeof window.matchMedia !== 'function') { + return undefined; + } + const handler = (...args: any) => mediaListener.current(...args); - // Always listen to System preference - const media = window.matchMedia('(prefers-color-scheme: dark)'); + // Always listen to System preference + const media = window.matchMedia('(prefers-color-scheme: dark)'); - // Intentionally use deprecated listener methods to support iOS & old browsers - media.addListener(handler); - handler(media); - return () => { - media.removeListener(handler); - }; - } - return undefined; + // Intentionally use deprecated listener methods to support iOS & old browsers + media.addListener(handler); + handler(media); + return () => { + media.removeListener(handler); + }; }, []); // Handle when localStorage has changed From 54560307a2a600373a2e59e5af477174b3ab8e28 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 31 Jul 2024 23:02:27 +0700 Subject: [PATCH 38/82] update docs --- .../css-theme-variables/configuration.md | 86 ++++------ .../css-theme-variables/overview.md | 22 +-- .../css-theme-variables/usage.md | 149 ++++------------- .../dark-mode/ToggleColorMode.js | 59 +++---- .../dark-mode/ToggleColorMode.tsx | 64 +++---- .../dark-mode/ToggleColorMode.tsx.preview | 8 +- .../customization/dark-mode/dark-mode.md | 157 ++++++++++-------- .../material/customization/palette/palette.md | 67 ++++++++ .../material/customization/theming/theming.md | 30 +++- 9 files changed, 301 insertions(+), 341 deletions(-) diff --git a/docs/data/material/customization/css-theme-variables/configuration.md b/docs/data/material/customization/css-theme-variables/configuration.md index 71d616376cbde7..f3bc0689f95fd3 100644 --- a/docs/data/material/customization/css-theme-variables/configuration.md +++ b/docs/data/material/customization/css-theme-variables/configuration.md @@ -7,7 +7,7 @@ To change the default variable prefix (`--mui`), provide a string to `cssVarPrefix` property, as shown below: ```js -extendTheme({ cssVarPrefix: 'any' }); +createTheme({ cssVariables: { cssVarPrefix: 'any' } }); // generated stylesheet: // --any-palette-primary-main: ...; @@ -16,7 +16,7 @@ extendTheme({ cssVarPrefix: 'any' }); To remove the prefix, use an empty string as a value: ```js -extendTheme({ cssVarPrefix: '' }); +createTheme({ cssVariables: { cssVarPrefix: '' } }); // generated stylesheet: // --palette-primary-main: ...; @@ -29,9 +29,11 @@ To toggle between modes manually, set the `colorSchemeSelector` with one of the ```js class -extendTheme({ +createTheme({ colorSchemes: { light: true, dark: true }, - colorSchemeSelector: 'class' + cssVariables: { + colorSchemeSelector: 'class' + } }); // CSS Result @@ -40,9 +42,11 @@ extendTheme({ ``` ```js data -extendTheme({ +createTheme({ colorSchemes: { light: true, dark: true }, - colorSchemeSelector: 'data' + cssVariables: { + colorSchemeSelector: 'data' + } }); // CSS Result @@ -52,9 +56,11 @@ extendTheme({ ```js string // The value must start with dot (.) for class or square brackets ([]) for data -extendTheme({ +createTheme({ colorSchemes: { light: true, dark: true }, - colorSchemeSelector: '.theme-%s' + cssVariables: { + colorSchemeSelector: '.theme-%s' + } }); // CSS Result @@ -66,44 +72,13 @@ extendTheme({ Then, use `useColorScheme` hook to switch between modes: - - -```jsx client-side-app -import { useColorScheme } from '@mui/material/styles'; - -function ModeSwitcher() { - const { mode, setMode } = useColorScheme(); - - return ( - - ); -} -``` - -```jsx server-side-app +```jsx import { useColorScheme } from '@mui/material/styles'; function ModeSwitcher() { const { mode, setMode } = useColorScheme(); - const [mounted, setMounted] = React.useState(false); - React.useEffect(() => { - setMounted(true); - }, []); - - if (!mounted) { - // for server-side rendering - // learn more at https://github.com/pacocoursey/next-themes#avoid-hydration-mismatch + if (!mode) { return null; } @@ -123,10 +98,8 @@ function ModeSwitcher() { } ``` - - :::success -The mode will be `system` by default to follow the user's preference. +After React's hydrate the tree, the mode will be `system` to follow the user's preference. ::: ### Determining the system mode @@ -190,7 +163,13 @@ Next, if you have a custom selector that is **not** `media`, add the `InitColorS The `attribute` has to be the same as the one you set in the `colorSchemeSelector` property: ```js - +createTheme({ + cssVariables: { + colorSchemeSelector: 'class' + } +}) + + ``` ::: @@ -207,7 +186,7 @@ export default function RootLayout({ children }) { {/* must come before the
element */} - +
{children}
@@ -226,11 +205,11 @@ import InitColorSchemeScript from '@mui/material/InitColorSchemeScript'; export default class MyDocument extends Document { render() { return ( - + ... {/* must come before the
element */} - +
@@ -249,7 +228,7 @@ import * as React from 'react'; import InitColorSchemeScript from '@mui/material/InitColorSchemeScript'; export function onRenderBody({ setPreBodyComponents }) { - setPreBodyComponents([]); + setPreBodyComponents([]); } ``` @@ -289,12 +268,11 @@ In the example below, all the components inside the `div` will always be dark: ## Disabling CSS color scheme -By default, the `extendTheme` attach [CSS color-scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme) based on the palette mode. If you want to disable it, set `disableCssColorScheme` to `true`: +By default, the `createTheme` attach [CSS color-scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme) based on the palette mode. If you want to disable it, set `disableCssColorScheme` to `true`: ```js -extendTheme({ - colorSchemes: { light: true, dark: true }, - disableCssColorScheme: true, +createTheme({ + cssVariables: { disableCssColorScheme: true }, }); ``` @@ -315,5 +293,5 @@ The generated CSS will not include the `color-scheme` property: To disable CSS transition when switching between modes, use `disableTransitionOnChange` prop: ```js - + ``` diff --git a/docs/data/material/customization/css-theme-variables/overview.md b/docs/data/material/customization/css-theme-variables/overview.md index 22b4b3a8bc23d3..ffc875ab4a5c15 100644 --- a/docs/data/material/customization/css-theme-variables/overview.md +++ b/docs/data/material/customization/css-theme-variables/overview.md @@ -15,12 +15,6 @@ CSS theme variables replace raw values in Material UI components for a better d In addition with these variables, you can inject a theme into your app's stylesheet _at build time_ to apply the user's selected settings before the whole app is rendered. -:::info -The `CssVarsProvider` is built on top of the [`ThemeProvider`](/material-ui/customization/theming/#themeprovider) with extra features like CSS variable generation, storage synchronization, unlimited color schemes, and more. - -If you have an existing theme, you can migrate to CSS theme variables by following the [migration guide](/material-ui/migration/migration-css-theme-variables/). -::: - ## Advantages - It lets you prevent [dark-mode SSR flickering](https://github.com/mui/material-ui/issues/27651). @@ -67,10 +61,10 @@ const darkTheme = createTheme({ **CSS theme variables**: Light and dark colors are consolidated into a theme. ```js -import { extendTheme } from '@mui/material/styles'; +import { createTheme } from '@mui/material/styles'; -// `extendTheme` is a new API -const theme = extendTheme({ +const theme = createTheme({ + cssVariables: true, colorSchemes: { light: { // palette for light mode palette: {...} @@ -101,20 +95,18 @@ createTheme({ }); ``` -**CSS theme variables**: Styling leans toward cascading and specificity by using the appropriate selector which lets you prevent [dark-mode SSR flickering](https://github.com/mui/material-ui/issues/27651): +**CSS theme variables**: Styling leans toward cascading and specificity by using `theme.applyStyles()` function which lets you prevent [dark-mode SSR flickering](https://github.com/mui/material-ui/issues/27651): ```js -extendTheme({ +createTheme({ components: { MuiButton: { styleOverrides: { root: ({ theme }) => ({ color: theme.vars.palette.primary.main, - // When the mode switches to dark, the attribute selector is attached to - // the tag by default. - '*:where([data-mui-color-scheme="dark"]) &': { + ...theme.applyStyles('dark', { color: '#fff', - }, + }), }), }, }, diff --git a/docs/data/material/customization/css-theme-variables/usage.md b/docs/data/material/customization/css-theme-variables/usage.md index 54e15baeba694d..a905e51aade959 100644 --- a/docs/data/material/customization/css-theme-variables/usage.md +++ b/docs/data/material/customization/css-theme-variables/usage.md @@ -4,8 +4,7 @@ ## Getting started -The CSS variables API relies on a provider called `CssVarsProvider` to inject styles into Material UI components. -`CssVarsProvider` generates CSS variables out of all tokens in the theme that are serializable, and makes them available in the React context along with the theme itself via [`ThemeProvider`](/material-ui/customization/theming/#theme-provider). +To enable CSS theme variables, create a theme with `cssVariables: true` and pass it to the `ThemeProvider`. Once the `App` renders on the screen, you will see the CSS theme variables in the HTML `:root` stylesheet. The variables are flattened and prefixed with `--mui` by default: @@ -13,10 +12,12 @@ The variables are flattened and prefixed with `--mui` by default: ```jsx JSX -import { CssVarsProvider } from '@mui/material/styles'; +import { ThemeProvider, createTheme } from '@mui/material/styles'; + +const theme = createTheme({ cssVariables: true }); function App() { - return {/* ...you app */}; + return {/* ...you app */}; } ``` @@ -33,44 +34,46 @@ function App() { :::info -The `CssVarsProvider` is built on top of the [`ThemeProvider`](/material-ui/customization/theming/#themeprovider) with extra features like CSS variable generation, storage synchronization, unlimited color schemes, and more. +If you are using an experimental API, namely `CssVarsProvider`, replace it with the `ThemeProvider`. -If you have an existing theme, you can migrate to CSS theme variables by following the [migration guide](/material-ui/migration/migration-css-theme-variables/). +To learn more about it, check out the [migration guide](/material-ui/migration/migration-css-theme-variables/). ::: ## Dark mode only application -To switch the default light to dark palette, set `colorSchemes: { dark: true }` to the `extendTheme`. +To switch the default light to dark palette, set `colorSchemes: { dark: true }` to the `createTheme`. Material UI will generate the dark palette instead. ```jsx -import { CssVarsProvider, extendTheme } from '@mui/material/styles'; +import { ThemeProvider, createTheme } from '@mui/material/styles'; -const theme = extendTheme({ +const theme = createTheme({ + cssVariables: true, colorSchemes: { dark: true }, }); function App() { - return {/* ...you app */}; + return {/* ...you app */}; } ``` ## Light and dark mode application -To support both light and dark modes, set `colorSchemes: { light: true, dark: true }` to the `extendTheme`. -Material UI will generate both light and dark palette with [`@media (prefers-color-scheme)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme). +To support both light and dark modes, set `colorSchemes: { light: true, dark: true }` to the `createTheme`. +Material UI will generate both light and dark palette with [`@media (prefers-color-scheme)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) as the default method. ```jsx JSX -import { CssVarsProvider, extendTheme } from '@mui/material/styles'; +import { ThemeProvider, createTheme } from '@mui/material/styles'; -const theme = extendTheme({ +const theme = createTheme({ + cssVariables: true, colorSchemes: { light: true, dark: true }, }); function App() { - return {/* ...you app */}; + return {/* ...you app */}; } ``` @@ -149,121 +152,24 @@ The structure of this object is a serializable theme structure with the values r } ``` -## Theming - -:::warning -`extendTheme` is not the same as [`createTheme`](/material-ui/customization/theming/#createtheme-options-args-theme). -Do not use them interchangeably. - -- `createTheme()` returns a theme for `ThemeProvider`. -- `extendTheme()` returns a theme for `CssVarsProvider`. - -::: - -The major difference from the [`createTheme`](/material-ui/customization/theming/#createtheme-options-args-theme) approach is in palette customization. -With the `extendTheme` API, you can specify the palette for `light` and `dark` color schemes at once. The rest of the theme structure remains the same. - -Here are examples of customizing each part of the theme: - - - -```js color-schemes -import { pink } from '@mui/material/colors'; - -extendTheme({ - colorSchemes: { - light: { - palette: { - primary: { - main: pink[600], - }, - }, - }, - dark: { - palette: { - primary: { - main: pink[400], - }, - }, - }, - }, -}); -``` - -```js typography -extendTheme({ - typography: { - fontFamily: '"Inter", "sans-serif"', - h1: { - fontSize: customTheme.typography.pxToRem(60), - fontWeight: 600, - lineHeight: 1.2, - letterSpacing: -0.5, - }, - h2: { - fontSize: customTheme.typography.pxToRem(48), - fontWeight: 600, - lineHeight: 1.2, - }, - }, -}); -``` - -```js spacing -extendTheme({ - spacing: '0.5rem', -}); -``` - -```js shape -extendTheme({ - shape: { - borderRadius: 12, - }, -}); -``` - -```js components -extendTheme({ - components: { - MuiChip: { - styleOverrides: { - root: ({ theme }) => ({ - variants: [ - { - props: { variant: 'outlined', color: 'primary' }, - style: { - backgroundColor: theme.vars.palette.background.paper, - }, - }, - ], - }), - }, - }, - }, -}); -``` - - - -### Channel tokens +## Color channel tokens A channel token is used for creating translucent color. It is a variable that consists of [color space channels](https://www.w3.org/TR/css-color-4/#color-syntax) but without the alpha component. The value of a channel token is separated by a space, for example `12 223 31`, which can be combined with the [color functions](https://www.w3.org/TR/css-color-4/#color-functions) to create a translucent color. -The `extendTheme()` automatically generates channel tokens that are likely to be used frequently from the theme palette. Those colors are suffixed with `Channel`, for example: +When `cssVariables` is enabled, channel tokens are generated automatically. Those colors are suffixed with `Channel`, for example: ```js -const theme = extendTheme(); -const light = theme.colorSchemes.light; +const theme = createTheme({ cssVariables: true }); -console.log(light.palette.primary.mainChannel); // '25 118 210' +console.log(theme.palette.primary.mainChannel); // '25 118 210' // This token is generated from `theme.colorSchemes.light.palette.primary.main`. ``` You can use the channel tokens to create a translucent color like this: ```js -const theme = extendTheme({ +const theme = createTheme({ + cssVariables: true, components: { MuiChip: { styleOverrides: { @@ -293,12 +199,13 @@ Don't use a comma (`,`) as a separator because the channel colors use empty spac ::: -### Adding new theme tokens +## Adding new theme tokens You can add other key-value pairs to the theme input which will be generated as a part of the CSS theme variables: ```js -const theme = extendTheme({ +const theme = createTheme({ + cssVariables: true, colorSchemes: { light: { palette: { @@ -323,7 +230,7 @@ const theme = extendTheme({ }); function App() { - return ...; + return ...; } ``` diff --git a/docs/data/material/customization/dark-mode/ToggleColorMode.js b/docs/data/material/customization/dark-mode/ToggleColorMode.js index 05146c58b678ee..28e9eec2094f5b 100644 --- a/docs/data/material/customization/dark-mode/ToggleColorMode.js +++ b/docs/data/material/customization/dark-mode/ToggleColorMode.js @@ -1,15 +1,14 @@ import * as React from 'react'; -import IconButton from '@mui/material/IconButton'; import Box from '@mui/material/Box'; -import { useTheme, ThemeProvider, createTheme } from '@mui/material/styles'; -import Brightness4Icon from '@mui/icons-material/Brightness4'; -import Brightness7Icon from '@mui/icons-material/Brightness7'; - -const ColorModeContext = React.createContext({ toggleColorMode: () => {} }); +import Select from '@mui/material/Select'; +import MenuItem from '@mui/material/MenuItem'; +import { ThemeProvider, createTheme, useColorScheme } from '@mui/material/styles'; function MyApp() { - const theme = useTheme(); - const colorMode = React.useContext(ColorModeContext); + const { mode, setMode } = useColorScheme(); + if (!mode) { + return null; + } return ( - {theme.palette.mode} mode - - {theme.palette.mode === 'dark' ? : } - + ); } -export default function ToggleColorMode() { - const [mode, setMode] = React.useState('light'); - const colorMode = React.useMemo( - () => ({ - toggleColorMode: () => { - setMode((prevMode) => (prevMode === 'light' ? 'dark' : 'light')); - }, - }), - [], - ); - - const theme = React.useMemo( - () => - createTheme({ - palette: { - mode, - }, - }), - [mode], - ); +const theme = createTheme({ + colorSchemes: { + dark: true, + }, +}); +export default function ToggleColorMode() { return ( - - - - - + + + ); } diff --git a/docs/data/material/customization/dark-mode/ToggleColorMode.tsx b/docs/data/material/customization/dark-mode/ToggleColorMode.tsx index cb09cb09c489f7..443e3661401017 100644 --- a/docs/data/material/customization/dark-mode/ToggleColorMode.tsx +++ b/docs/data/material/customization/dark-mode/ToggleColorMode.tsx @@ -1,15 +1,14 @@ import * as React from 'react'; -import IconButton from '@mui/material/IconButton'; import Box from '@mui/material/Box'; -import { useTheme, ThemeProvider, createTheme } from '@mui/material/styles'; -import Brightness4Icon from '@mui/icons-material/Brightness4'; -import Brightness7Icon from '@mui/icons-material/Brightness7'; - -const ColorModeContext = React.createContext({ toggleColorMode: () => {} }); +import Select from '@mui/material/Select'; +import MenuItem from '@mui/material/MenuItem'; +import { ThemeProvider, createTheme, useColorScheme } from '@mui/material/styles'; function MyApp() { - const theme = useTheme(); - const colorMode = React.useContext(ColorModeContext); + const { mode, setMode } = useColorScheme(); + if (!mode) { + return null; + } return ( - {theme.palette.mode} mode - - {theme.palette.mode === 'dark' ? : } - + ); } -export default function ToggleColorMode() { - const [mode, setMode] = React.useState<'light' | 'dark'>('light'); - const colorMode = React.useMemo( - () => ({ - toggleColorMode: () => { - setMode((prevMode) => (prevMode === 'light' ? 'dark' : 'light')); - }, - }), - [], - ); - - const theme = React.useMemo( - () => - createTheme({ - palette: { - mode, - }, - }), - [mode], - ); +const theme = createTheme({ + colorSchemes: { + dark: true, + }, +}); +export default function ToggleColorMode() { return ( - - - - - + + + ); } diff --git a/docs/data/material/customization/dark-mode/ToggleColorMode.tsx.preview b/docs/data/material/customization/dark-mode/ToggleColorMode.tsx.preview index d3ebb19c78b194..95f392ac920cbb 100644 --- a/docs/data/material/customization/dark-mode/ToggleColorMode.tsx.preview +++ b/docs/data/material/customization/dark-mode/ToggleColorMode.tsx.preview @@ -1,5 +1,3 @@ - - - - - \ No newline at end of file + + + \ No newline at end of file diff --git a/docs/data/material/customization/dark-mode/dark-mode.md b/docs/data/material/customization/dark-mode/dark-mode.md index 2a805d555b74b2..cba900cae36fa2 100644 --- a/docs/data/material/customization/dark-mode/dark-mode.md +++ b/docs/data/material/customization/dark-mode/dark-mode.md @@ -2,11 +2,13 @@

Material UI comes with two palette modes: light (the default) and dark.

-## Dark mode by default +## Dark mode only You can make your application use the dark theme as the default—regardless of the user's preference—by adding `mode: 'dark'` to the `createTheme` helper: -```js + + +```js Default import { ThemeProvider, createTheme } from '@mui/material/styles'; import CssBaseline from '@mui/material/CssBaseline'; @@ -26,6 +28,30 @@ export default function App() { } ``` +```js Custom +import { ThemeProvider, createTheme } from '@mui/material/styles'; +import { pink } from '@mui/material/colors'; + +const darkTheme = createTheme({ + palette: { + mode: 'dark', + primary: { + main: pink[200], // to learn more, check out the Color customization page + }, + }, +}); + +export default function App() { + return ( + +
This app is using the dark mode
+
+ ); +} +``` + +
+ Adding `mode: 'dark'` to the `createTheme` helper modifies several palette values, as shown in the following demo: {{"demo": "DarkTheme.js", "bg": "inline", "hideToolbar": true}} @@ -36,84 +62,59 @@ Adding `` inside of the `` component will also ena Setting the dark mode this way only works if you are using [the default palette](/material-ui/customization/default-theme/). If you have a custom palette, make sure that you have the correct values based on the `mode`. The next section explains how to do this. ::: -## Dark mode with a custom palette +## System preference -To use custom palettes for light and dark modes, you can create a function that will return the correct palette depending on the selected mode, as shown here: +Users might have a preference for light or dark mode that they've set through their operating system—either systemwide, or for a single user agent. -```ts -const getDesignTokens = (mode: PaletteMode) => ({ - palette: { - mode, - ...(mode === 'light' - ? { - // palette values for light mode - primary: amber, - divider: amber[200], - text: { - primary: grey[900], - secondary: grey[800], - }, - } - : { - // palette values for dark mode - primary: deepOrange, - divider: deepOrange[700], - background: { - default: deepOrange[900], - paper: deepOrange[900], - }, - text: { - primary: '#fff', - secondary: grey[500], - }, - }), - }, -}); -``` +### Built-in support -You can see on the example that there are different colors used based on whether the mode is light or dark. The next step is to use this function when creating the theme. +Material UI has built-in support for system preference when dark color scheme is provided: -```tsx -export default function App() { - const [mode, setMode] = React.useState('light'); - const colorMode = React.useMemo( - () => ({ - // The dark mode switch would invoke this method - toggleColorMode: () => { - setMode((prevMode: PaletteMode) => - prevMode === 'light' ? 'dark' : 'light', - ); - }, - }), - [], - ); + - // Update the theme only if the mode changes - const theme = React.useMemo(() => createTheme(getDesignTokens(mode)), [mode]); +```js Default +import { ThemeProvider, createTheme } from '@mui/material/styles'; - return ( - - - - - - ); +const theme = createTheme({ + colorSchemes: { + dark: true, + }, +}); + +function App() { + return ...; } ``` -Here is a fully working example: +```js Custom +import { pink } from '@mui/material/colors'; -{{"demo": "DarkThemeWithCustomPalette.js", "defaultCodeOpen": false}} +const theme = createTheme({ + colorSchemes: { + dark: { + palette: { + primary: { + main: pink[200], // to learn more, check out the Palette tokens page + }, + }, + }, + }, +}); +``` -## Toggling color mode + -To give your users a way to toggle between modes, you can add React's context to a button's `onClick` event, as shown in the following demo: +The built-in support includes the following features: -{{"demo": "ToggleColorMode.js", "defaultCodeOpen": false}} +- Automatic switching between light and dark color schemes based on the user's preference. +- Synchronize between window tabs. If the user changes the color scheme in one tab, the other tabs will also update. +- An option to [disable transitions](#disable-transitions) when the color scheme changes. -## System preference +:::success +To test the system preference feature, follow the guide on [emulating the CSS media feature `prefers-color-scheme`](https://developer.chrome.com/docs/devtools/rendering/emulate-css#emulate_css_media_feature_prefers-color-scheme). +::: -Users might have a preference for light or dark mode that they've set through their operating system—either systemwide, or for a single user agent. +### Manual implementation You can make use of this preference with the [useMediaQuery](/material-ui/react-use-media-query/) hook and the [prefers-color-scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) media query. @@ -147,21 +148,39 @@ function App() { } ``` +## Toggling color mode + +To give your users a way to toggle between modes, use `useColorScheme` hook to read and update the mode. + +:::info +`mode` is always `undefined` on the first render, so make sure to handle this case. +::: + +{{"demo": "ToggleColorMode.js", "defaultCodeOpen": false}} + +## Disable transitions + +To instantly switch between color schemes, you can disable transitions by setting `disableTransitionOnChange` prop on the `ThemeProvider` component: + +```jsx + + ... + +``` + ## Styling in dark mode Use the `theme.applyStyles` utility to apply styles for a specific mode. We recommend using this function over checking `theme.palette.mode` to switch between styles as it has more benefits: -- It works with or without `CssVarsProvider`. The function automatically switches between overriding object styles or injecting pseudo-classes based on the upper provider. -- It lets you prevent [dark-mode SSR flickering](https://github.com/mui/material-ui/issues/27651) when using with `CssVarsProvider`. - It can be used with [Pigment CSS](https://github.com/mui/material-ui/tree/master/packages/pigment-css-react), our in-house zero-runtime CSS-in-JS solution. - It is generally more readable and maintainable. - It is slightly more performant as it doesn't require to do style recalculation but the bundle size of SSR generated styles is larger. ### Usage -With the `**styled**` function: +With the `styled` function: ```jsx import { styled } from '@mui/material/styles'; @@ -182,7 +201,7 @@ const MyComponent = styled('div')(({ theme }) => ({ })); ``` -With the `**sx**` prop: +With the `sx` prop: ```jsx import Button from '@mui/material/Button'; diff --git a/docs/data/material/customization/palette/palette.md b/docs/data/material/customization/palette/palette.md index 4cfb782426dcba..0e6fbbedac6ea4 100644 --- a/docs/data/material/customization/palette/palette.md +++ b/docs/data/material/customization/palette/palette.md @@ -310,6 +310,73 @@ Please verify that the [APCA](https://contrast.tools/?tab=apca) color contrast i Need inspiration? The Material Design team has built an [palette configuration tool](/material-ui/customization/color/#picking-colors) to help you. +## Color schemes + +To add both built-in light and dark color schemes, use the `colorSchemes: { light: true, dark: true }`. +It will generate the default tokens for both color schemes: + +```js +import { createTheme } from '@mui/material/styles'; + +const theme = createTheme({ + colorSchemes: { + light: true, + dark: true, + }, +}); +``` + +If you want to override the default tokens for each color scheme, use the same [palette object](#customization) as shown below: + +```js +const theme = createTheme({ + colorSchemes: { + light: { + palette: { + primary: { + main: '#FF5733', + }, + // ...other tokens + }, + }, + dark: { + palette: { + primary: { + main: '#E0C2FF', + }, + // ...other tokens + }, + }, + }, +}); +``` + +:::warning +If you provide both `colorSchemes` and `palette`, the `palette` will override the palette defined in color schemes. + +```js +const theme = createTheme({ + palette: { + primary: { + main: '...', + }, + }, + colorSchemes: { + light: { + // This will be replaced by the palette defined above + palette: { + primary: { + main: '...', + }, + }, + }, + dark: { ... }, + }, +}); +``` + +::: + ## Dark mode For details of how you can set up a dark mode for your theme, head to the [dark mode guide](/material-ui/customization/dark-mode/). diff --git a/docs/data/material/customization/theming/theming.md b/docs/data/material/customization/theming/theming.md index abd5d2612e6b97..ad18729fb97c88 100644 --- a/docs/data/material/customization/theming/theming.md +++ b/docs/data/material/customization/theming/theming.md @@ -115,11 +115,35 @@ You can extend the outer theme by providing a function: {{"demo": "ThemeNestingExtend.js"}} -## CSS variables provider +## CSS theme variables -The `CssVarsProvider` is built on top of the `ThemeProvider` with extra features like theme CSS variables generation, built-in color scheme synchronization with the user's system preference, and more. +To generate CSS variables from the theme, set `cssVariables` to `true` in the theme configuration and pass it to the `ThemeProvider`: -To start using the `CssVarsProvider`, check out the [basic usage guide](/material-ui/customization/css-theme-variables/usage/). If you are using the `ThemeProvider`, read the [migration guide](/material-ui/migration/migration-css-theme-variables/). +```jsx +const theme = createTheme({ + cssVariables: true, +}); + +function App() { + return ...; +} +``` + +This will generate a global stylesheet with the CSS theme variables: + +```css +:root { + --mui-palette-primary-main: #1976d2; + /* ...other variables */ +} +``` + +All the components under the `ThemeProvider` will start using those CSS theme variables instead of raw values. + +```diff title="Button styles" +- color: #1976d2; ++ color: var(--mui-palette-primary-main); +``` ## API From f9bf0c72d915b0ef9273f59f9f546095a2b719bd Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 1 Aug 2024 10:14:08 +0700 Subject: [PATCH 39/82] update migration docs --- .../material/migration/migrating-to-v6/migrating-to-v6.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md b/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md index 40fc7c1421dbf9..b8ec00653af727 100644 --- a/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md +++ b/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md @@ -314,12 +314,13 @@ The following deprecated types were removed: ### CssVarsProvider and extendTheme -The `CssVarsProvider` and `extendTheme` APIs are now stable. -If you already use them in v5, you can now drop the experimental prefix. +The `CssVarsProvider` and `extendTheme` has been merged into `ThemeProvider` and `createTheme`. +If you are using them in v5 or v6-beta, you should migrate as shown below: ```diff - import { experimental_extendTheme as extendTheme, Experimental_CssVarsProvider as CssVarsProvider } from '@mui/material/styles'; -+ import { extendTheme, CssVarsProvider } from '@mui/material/styles'; +- import { extendTheme, CssVarsProvider } from '@mui/material/styles'; ++ import { createTheme, ThemeProvider } from '@mui/material/styles'; ``` Check out the [CSS theme variables page](/material-ui/customization/css-theme-variables/overview/) to learn more about it. From 12e92045fc969aa9a0ce424ba87aa9972d7ad1d0 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 1 Aug 2024 10:14:38 +0700 Subject: [PATCH 40/82] optimize useCurrentColorScheme --- .../src/cssVars/useCurrentColorScheme.test.js | 21 +++++++++++++++++++ .../src/cssVars/useCurrentColorScheme.ts | 20 +++++++++++------- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/packages/mui-system/src/cssVars/useCurrentColorScheme.test.js b/packages/mui-system/src/cssVars/useCurrentColorScheme.test.js index f49c4c4545bc63..d120daa8bc3d00 100644 --- a/packages/mui-system/src/cssVars/useCurrentColorScheme.test.js +++ b/packages/mui-system/src/cssVars/useCurrentColorScheme.test.js @@ -58,6 +58,27 @@ describe('useCurrentColorScheme', () => { window.matchMedia = originalMatchmedia; }); + it('does not trigger a re-render for a single color scheme', () => { + function Data() { + const { mode } = useCurrentColorScheme({ + defaultMode: 'dark', + supportedColorSchemes: ['dark'], + }); + const count = React.useRef(0); + React.useEffect(() => { + count.current += 1; + }); + return ( +
+ {mode}:{count.current} +
+ ); + } + const { container } = render(); + + expect(container.firstChild.textContent).to.equal('dark:0'); + }); + describe('getColorScheme', () => { it('use lightColorScheme given mode=light', () => { expect(getColorScheme({ mode: 'light', lightColorScheme: 'light' })).to.equal('light'); diff --git a/packages/mui-system/src/cssVars/useCurrentColorScheme.ts b/packages/mui-system/src/cssVars/useCurrentColorScheme.ts index dd35a3fec8d877..53f5307dc9a705 100644 --- a/packages/mui-system/src/cssVars/useCurrentColorScheme.ts +++ b/packages/mui-system/src/cssVars/useCurrentColorScheme.ts @@ -136,6 +136,7 @@ export default function useCurrentColorScheme 1; const [state, setState] = React.useState(() => { const initialMode = initializeValue(modeStorageKey, defaultMode); @@ -158,9 +159,11 @@ export default function useCurrentColorScheme { - setHasMounted(true); // to rerender the component after hydration + if (isMultiSchemes) { + setHasMounted(true); // to rerender the component after hydration + } hasMounted.current = true; - }, []); + }, [isMultiSchemes]); const colorScheme = getColorScheme(state); @@ -286,7 +289,7 @@ export default function useCurrentColorScheme { - if (typeof window.matchMedia !== 'function') { + if (typeof window.matchMedia !== 'function' || !isMultiSchemes) { return undefined; } const handler = (...args: any) => mediaListener.current(...args); @@ -300,11 +303,11 @@ export default function useCurrentColorScheme { media.removeListener(handler); }; - }, []); + }, [isMultiSchemes]); // Handle when localStorage has changed React.useEffect(() => { - if (storageWindow) { + if (storageWindow && isMultiSchemes) { const handleStorage = (event: StorageEvent) => { const value = event.newValue; if ( @@ -342,13 +345,14 @@ export default function useCurrentColorScheme Date: Thu, 1 Aug 2024 10:19:49 +0700 Subject: [PATCH 41/82] remove error throwing from useColorScheme --- docs/public/static/error-codes.json | 12 +++++------- .../src/cssVars/createCssVarsProvider.js | 19 ++++++++++++------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/docs/public/static/error-codes.json b/docs/public/static/error-codes.json index 68f720382acf75..a691395d872a9a 100644 --- a/docs/public/static/error-codes.json +++ b/docs/public/static/error-codes.json @@ -16,10 +16,8 @@ "15": "MUI: withStyles is no longer exported from @mui/material/styles.\nYou have to import it from @mui/styles.\nSee https://mui.com/r/migration-v4/#mui-material-styles for more details.", "16": "MUI: withTheme is no longer exported from @mui/material/styles.\nYou have to import it from @mui/styles.\nSee https://mui.com/r/migration-v4/#mui-material-styles for more details.", "17": "MUI: Expected valid input target. Did you use a custom `slots.input` and forget to forward refs? See https://mui.com/r/input-component-ref-interface for more info.", - "18": "MUI: `vars` is a private field used for CSS variables support.\nPlease use another name.", - "19": "MUI: `useColorScheme` must be called under ", - "20": "MUI: The `experimental_sx` has been moved to `theme.unstable_sx`.For more details, see https://github.com/mui/material-ui/pull/35150.", - "21": "MUI: The provided shorthand %s is invalid. The format should be `@` or `@/`.\nFor example, `@sm` or `@600` or `@40rem/sidebar`.", - "22": "MUI: Missing or invalid value of `colorSchemes.%s` from the `extendTheme` function.", - "24": "MUI: The provided `colorSchemes.%s` is either missing or invalid." -} + "18": "MUI: The provided shorthand %s is invalid. The format should be `@` or `@/`.\nFor example, `@sm` or `@600` or `@40rem/sidebar`.", + "19": "MUI: The `experimental_sx` has been moved to `theme.unstable_sx`.For more details, see https://github.com/mui/material-ui/pull/35150.", + "20": "MUI: `vars` is a private field used for CSS variables support.\nPlease use another name.", + "21": "MUI: The provided `colorSchemes.%s` is either missing or invalid." +} \ No newline at end of file diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.js b/packages/mui-system/src/cssVars/createCssVarsProvider.js index 4385def1bd42c8..e5905ce87d306f 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.js +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.js @@ -30,19 +30,24 @@ export default function createCssVarsProvider(options) { resolveTheme, } = options; + const defaultContext = { + allColorSchemes: [], + colorScheme: undefined, + darkColorScheme: undefined, + lightColorScheme: undefined, + mode: undefined, + setColorScheme: () => {}, + setMode: () => {}, + systemMode: undefined, + }; + const ColorSchemeContext = React.createContext(undefined); if (process.env.NODE_ENV !== 'production') { ColorSchemeContext.displayName = 'ColorSchemeContext'; } - const useColorScheme = () => { - const value = React.useContext(ColorSchemeContext); - if (!value) { - throw new MuiError('MUI: `useColorScheme` must be called under '); - } - return value; - }; + const useColorScheme = () => React.useContext(ColorSchemeContext) || defaultContext; function CssVarsProvider(props) { const { From 9f0217ca2b278d29fc42420d274530efe4243cf5 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 1 Aug 2024 11:14:54 +0700 Subject: [PATCH 42/82] add more tests for createTheme --- .../src/styles/createTheme.test.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/mui-material/src/styles/createTheme.test.js b/packages/mui-material/src/styles/createTheme.test.js index 3f1d9925a45a8f..a7789c597e58bf 100644 --- a/packages/mui-material/src/styles/createTheme.test.js +++ b/packages/mui-material/src/styles/createTheme.test.js @@ -83,6 +83,25 @@ describe('createTheme', () => { ); }); + it('should have light and dark colorSchemes', () => { + const theme = createTheme({ + cssVariables: true, + colorSchemes: { dark: true }, + }); + expect(theme.colorSchemes.light).to.not.equal(undefined); + expect(theme.colorSchemes.dark).to.not.equal(undefined); + }); + + it('should not have light if default color scheme is set to dark', () => { + const theme = createTheme({ + cssVariables: true, + colorSchemes: { dark: true }, + defaultColorScheme: 'dark', + }); + expect(theme.colorSchemes.light).to.equal(undefined); + expect(theme.colorSchemes.dark).to.not.equal(undefined); + }); + describe('spacing', () => { it('should provide the default spacing', () => { const theme = createTheme({ cssVariables: true }); From 7fb6e02e71e38264799064ca0ca1cdf9562a0632 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 1 Aug 2024 10:14:38 +0700 Subject: [PATCH 43/82] optimize useCurrentColorScheme --- .../src/cssVars/useCurrentColorScheme.test.js | 21 +++++++++++++++++++ .../src/cssVars/useCurrentColorScheme.ts | 20 +++++++++++------- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/packages/mui-system/src/cssVars/useCurrentColorScheme.test.js b/packages/mui-system/src/cssVars/useCurrentColorScheme.test.js index f49c4c4545bc63..d120daa8bc3d00 100644 --- a/packages/mui-system/src/cssVars/useCurrentColorScheme.test.js +++ b/packages/mui-system/src/cssVars/useCurrentColorScheme.test.js @@ -58,6 +58,27 @@ describe('useCurrentColorScheme', () => { window.matchMedia = originalMatchmedia; }); + it('does not trigger a re-render for a single color scheme', () => { + function Data() { + const { mode } = useCurrentColorScheme({ + defaultMode: 'dark', + supportedColorSchemes: ['dark'], + }); + const count = React.useRef(0); + React.useEffect(() => { + count.current += 1; + }); + return ( +
+ {mode}:{count.current} +
+ ); + } + const { container } = render(); + + expect(container.firstChild.textContent).to.equal('dark:0'); + }); + describe('getColorScheme', () => { it('use lightColorScheme given mode=light', () => { expect(getColorScheme({ mode: 'light', lightColorScheme: 'light' })).to.equal('light'); diff --git a/packages/mui-system/src/cssVars/useCurrentColorScheme.ts b/packages/mui-system/src/cssVars/useCurrentColorScheme.ts index dd35a3fec8d877..53f5307dc9a705 100644 --- a/packages/mui-system/src/cssVars/useCurrentColorScheme.ts +++ b/packages/mui-system/src/cssVars/useCurrentColorScheme.ts @@ -136,6 +136,7 @@ export default function useCurrentColorScheme 1; const [state, setState] = React.useState(() => { const initialMode = initializeValue(modeStorageKey, defaultMode); @@ -158,9 +159,11 @@ export default function useCurrentColorScheme { - setHasMounted(true); // to rerender the component after hydration + if (isMultiSchemes) { + setHasMounted(true); // to rerender the component after hydration + } hasMounted.current = true; - }, []); + }, [isMultiSchemes]); const colorScheme = getColorScheme(state); @@ -286,7 +289,7 @@ export default function useCurrentColorScheme { - if (typeof window.matchMedia !== 'function') { + if (typeof window.matchMedia !== 'function' || !isMultiSchemes) { return undefined; } const handler = (...args: any) => mediaListener.current(...args); @@ -300,11 +303,11 @@ export default function useCurrentColorScheme { media.removeListener(handler); }; - }, []); + }, [isMultiSchemes]); // Handle when localStorage has changed React.useEffect(() => { - if (storageWindow) { + if (storageWindow && isMultiSchemes) { const handleStorage = (event: StorageEvent) => { const value = event.newValue; if ( @@ -342,13 +345,14 @@ export default function useCurrentColorScheme Date: Thu, 1 Aug 2024 10:19:49 +0700 Subject: [PATCH 44/82] remove error throwing from useColorScheme --- docs/public/static/error-codes.json | 12 +++++------- .../src/cssVars/createCssVarsProvider.js | 19 ++++++++++++------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/docs/public/static/error-codes.json b/docs/public/static/error-codes.json index 68f720382acf75..a691395d872a9a 100644 --- a/docs/public/static/error-codes.json +++ b/docs/public/static/error-codes.json @@ -16,10 +16,8 @@ "15": "MUI: withStyles is no longer exported from @mui/material/styles.\nYou have to import it from @mui/styles.\nSee https://mui.com/r/migration-v4/#mui-material-styles for more details.", "16": "MUI: withTheme is no longer exported from @mui/material/styles.\nYou have to import it from @mui/styles.\nSee https://mui.com/r/migration-v4/#mui-material-styles for more details.", "17": "MUI: Expected valid input target. Did you use a custom `slots.input` and forget to forward refs? See https://mui.com/r/input-component-ref-interface for more info.", - "18": "MUI: `vars` is a private field used for CSS variables support.\nPlease use another name.", - "19": "MUI: `useColorScheme` must be called under ", - "20": "MUI: The `experimental_sx` has been moved to `theme.unstable_sx`.For more details, see https://github.com/mui/material-ui/pull/35150.", - "21": "MUI: The provided shorthand %s is invalid. The format should be `@` or `@/`.\nFor example, `@sm` or `@600` or `@40rem/sidebar`.", - "22": "MUI: Missing or invalid value of `colorSchemes.%s` from the `extendTheme` function.", - "24": "MUI: The provided `colorSchemes.%s` is either missing or invalid." -} + "18": "MUI: The provided shorthand %s is invalid. The format should be `@` or `@/`.\nFor example, `@sm` or `@600` or `@40rem/sidebar`.", + "19": "MUI: The `experimental_sx` has been moved to `theme.unstable_sx`.For more details, see https://github.com/mui/material-ui/pull/35150.", + "20": "MUI: `vars` is a private field used for CSS variables support.\nPlease use another name.", + "21": "MUI: The provided `colorSchemes.%s` is either missing or invalid." +} \ No newline at end of file diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.js b/packages/mui-system/src/cssVars/createCssVarsProvider.js index 4385def1bd42c8..e5905ce87d306f 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.js +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.js @@ -30,19 +30,24 @@ export default function createCssVarsProvider(options) { resolveTheme, } = options; + const defaultContext = { + allColorSchemes: [], + colorScheme: undefined, + darkColorScheme: undefined, + lightColorScheme: undefined, + mode: undefined, + setColorScheme: () => {}, + setMode: () => {}, + systemMode: undefined, + }; + const ColorSchemeContext = React.createContext(undefined); if (process.env.NODE_ENV !== 'production') { ColorSchemeContext.displayName = 'ColorSchemeContext'; } - const useColorScheme = () => { - const value = React.useContext(ColorSchemeContext); - if (!value) { - throw new MuiError('MUI: `useColorScheme` must be called under '); - } - return value; - }; + const useColorScheme = () => React.useContext(ColorSchemeContext) || defaultContext; function CssVarsProvider(props) { const { From c2c6c0c106aea39f4e7143e3e1bfab7c1010bc93 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 1 Aug 2024 11:14:54 +0700 Subject: [PATCH 45/82] add more tests for createTheme --- .../src/styles/createTheme.test.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/mui-material/src/styles/createTheme.test.js b/packages/mui-material/src/styles/createTheme.test.js index 3f1d9925a45a8f..a7789c597e58bf 100644 --- a/packages/mui-material/src/styles/createTheme.test.js +++ b/packages/mui-material/src/styles/createTheme.test.js @@ -83,6 +83,25 @@ describe('createTheme', () => { ); }); + it('should have light and dark colorSchemes', () => { + const theme = createTheme({ + cssVariables: true, + colorSchemes: { dark: true }, + }); + expect(theme.colorSchemes.light).to.not.equal(undefined); + expect(theme.colorSchemes.dark).to.not.equal(undefined); + }); + + it('should not have light if default color scheme is set to dark', () => { + const theme = createTheme({ + cssVariables: true, + colorSchemes: { dark: true }, + defaultColorScheme: 'dark', + }); + expect(theme.colorSchemes.light).to.equal(undefined); + expect(theme.colorSchemes.dark).to.not.equal(undefined); + }); + describe('spacing', () => { it('should provide the default spacing', () => { const theme = createTheme({ cssVariables: true }); From ea872b0ed093e43d13a9875c9a50e4a9e6191f90 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 1 Aug 2024 12:49:48 +0700 Subject: [PATCH 46/82] prettier --- docs/public/static/error-codes.json | 2 +- packages/mui-system/src/cssVars/createCssVarsProvider.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/public/static/error-codes.json b/docs/public/static/error-codes.json index a691395d872a9a..7414cbb649d8fe 100644 --- a/docs/public/static/error-codes.json +++ b/docs/public/static/error-codes.json @@ -20,4 +20,4 @@ "19": "MUI: The `experimental_sx` has been moved to `theme.unstable_sx`.For more details, see https://github.com/mui/material-ui/pull/35150.", "20": "MUI: `vars` is a private field used for CSS variables support.\nPlease use another name.", "21": "MUI: The provided `colorSchemes.%s` is either missing or invalid." -} \ No newline at end of file +} diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.js b/packages/mui-system/src/cssVars/createCssVarsProvider.js index e5905ce87d306f..2bda9137a8638f 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.js +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.js @@ -1,6 +1,5 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import MuiError from '@mui/internal-babel-macros/MuiError.macro'; import { GlobalStyles } from '@mui/styled-engine'; import { useTheme as muiUseTheme } from '@mui/private-theming'; import ThemeProvider from '../ThemeProvider'; From d3ebf57c53ac13b67acb68cc0630e7a55efec6e0 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 1 Aug 2024 13:33:26 +0700 Subject: [PATCH 47/82] revert unnecessary change --- packages/mui-material/src/styles/stringifyTheme.test.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/mui-material/src/styles/stringifyTheme.test.ts b/packages/mui-material/src/styles/stringifyTheme.test.ts index 28715c26f95794..8164cc7a1e7ca1 100644 --- a/packages/mui-material/src/styles/stringifyTheme.test.ts +++ b/packages/mui-material/src/styles/stringifyTheme.test.ts @@ -127,10 +127,7 @@ export default theme;`); }); it('works with framework toRuntimeSource', () => { - const theme = { - palette: { primary: { main: '#ff5252' } }, - toRuntimeSource: stringifyTheme, - }; + const theme = { palette: { primary: { main: '#ff5252' } }, toRuntimeSource: stringifyTheme }; expect(theme.toRuntimeSource.call(theme, theme)).to .equal(`import { unstable_createBreakpoints as createBreakpoints, createTransitions } from '@mui/material/styles'; From 8c3f2e0189c227de61578dd5842e582cca301202 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 1 Aug 2024 20:18:12 +0700 Subject: [PATCH 48/82] fix test --- packages/mui-material/src/styles/createTheme.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/mui-material/src/styles/createTheme.test.js b/packages/mui-material/src/styles/createTheme.test.js index a7789c597e58bf..3491e70c142c19 100644 --- a/packages/mui-material/src/styles/createTheme.test.js +++ b/packages/mui-material/src/styles/createTheme.test.js @@ -21,9 +21,9 @@ describe('createTheme', () => { it('color schemes dark: true', () => { const theme = createTheme({ cssVariables: false, colorSchemes: { dark: true } }); - const { light, dark } = theme.colorSchemes || {}; - expect(light?.palette.primary.main).to.deep.equal(lightPalette.primary.main); - expect(dark?.palette.primary.main).to.deep.equal(darkPalette.primary.main); + const { light, dark } = theme.colorSchemes; + expect(light.palette.primary.main).to.deep.equal(lightPalette.primary.main); + expect(dark.palette.primary.main).to.deep.equal(darkPalette.primary.main); }); it('color schemes light: true', () => { From 26d992c3576e6524349e8424e2a2bfae9bac79fc Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 1 Aug 2024 20:26:25 +0700 Subject: [PATCH 49/82] remove unused type --- packages/mui-material/src/styles/createThemeWithVars.d.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/mui-material/src/styles/createThemeWithVars.d.ts b/packages/mui-material/src/styles/createThemeWithVars.d.ts index 5d5ff73ccde54d..4cc426dda8fe56 100644 --- a/packages/mui-material/src/styles/createThemeWithVars.d.ts +++ b/packages/mui-material/src/styles/createThemeWithVars.d.ts @@ -239,7 +239,6 @@ export interface ColorSystemOptions { } export interface CssVarsPalette { - colorScheme: SupportedColorScheme; // TODO: remove common: PaletteCommonChannel; primary: PaletteColorChannel; secondary: PaletteColorChannel; From b122f12027d1f102ac66d7f42b223470e716434c Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Fri, 2 Aug 2024 16:39:23 +0700 Subject: [PATCH 50/82] update migration guide --- .../migrating-to-v6/migrating-to-v6.md | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md b/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md index 0af54dc57ed32e..2e9ce874d9c16c 100644 --- a/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md +++ b/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md @@ -34,7 +34,7 @@ These updates reduced the Material UI package size by 2.5MB, 25% of the total s Aside from that, v6 also includes a few quality-of-life improvements regarding styling: -- The `CssVarsProvider` API is now stable. That enables you to rely on CSS variables, allowing for more intricate and performant customization possibilities, along with improved overall developer experience. +- The CSS theme variables feature is now stable. It powers components with CSS variables, allowing for more intricate and performant customization possibilities, along with improved overall developer experience. - Support for container queries within the theme. - A new theme utility for adding styles to specific color modes. @@ -312,17 +312,33 @@ The following deprecated types were removed: ## Stabilized APIs -### CssVarsProvider and extendTheme +### Merged CssVarsProvider into ThemeProvider The `CssVarsProvider` and `extendTheme` has been merged into `ThemeProvider` and `createTheme`. If you are using them in v5 or v6-beta, you should migrate as shown below: ```diff -- import { experimental_extendTheme as extendTheme, Experimental_CssVarsProvider as CssVarsProvider } from '@mui/material/styles'; +- import { +- experimental_extendTheme as extendTheme, +- Experimental_CssVarsProvider as CssVarsProvider +- } from '@mui/material/styles'; - import { extendTheme, CssVarsProvider } from '@mui/material/styles'; + import { createTheme, ThemeProvider } from '@mui/material/styles'; ``` +Then you will need to set `cssVariables: true` and pass the theme to the `ThemeProvider`: + +```js +const theme = createTheme({ + cssVariables: true, + // ...your overrides +}); + +function App() { + return ...; +} +``` + Check out the [CSS theme variables page](/material-ui/customization/css-theme-variables/overview/) to learn more about it. ### Add styles for specific color modes @@ -342,6 +358,8 @@ It's designed to replace `theme.palette.mode` when applying light or dark styles })) ``` +Staring from v6, this is an official way to apply styles based on the color mode. We recommend migrating to this method to smoothly adopt new features and improvements in the next major updates. + Use these codemods to migrate your project to `theme.applyStyles`: ```bash From 4da44de74e689d95cd9f01715c1ac04e37aa01cb Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Fri, 2 Aug 2024 16:39:32 +0700 Subject: [PATCH 51/82] remove migrating to css-theme-variables page --- .../css-theme-variables/overview.md | 1 - .../css-theme-variables/usage.md | 2 - .../material-ui-sync/material-ui-sync.md | 13 +- .../migration-css-theme-variables.md | 284 ------------------ docs/data/material/pages.ts | 4 - .../migration-css-theme-variables.js | 11 - docs/public/_redirects | 1 - docs/translations/translations.json | 1 - 8 files changed, 5 insertions(+), 312 deletions(-) delete mode 100644 docs/data/material/migration/migrating-to-v6/migration-css-theme-variables.md delete mode 100644 docs/pages/material-ui/migration/migration-css-theme-variables.js diff --git a/docs/data/material/customization/css-theme-variables/overview.md b/docs/data/material/customization/css-theme-variables/overview.md index ffc875ab4a5c15..226601cd7152b8 100644 --- a/docs/data/material/customization/css-theme-variables/overview.md +++ b/docs/data/material/customization/css-theme-variables/overview.md @@ -117,5 +117,4 @@ createTheme({ ## What's next - To start a new project with CSS theme variables, check out the [basic usage guide](/material-ui/customization/css-theme-variables/usage/). -- For an existing Material UI project, check out the [migration guide](/material-ui/migration/migration-css-theme-variables/). - For theming and customization, check out the [how-to guide](/material-ui/customization/css-theme-variables/configuration/). diff --git a/docs/data/material/customization/css-theme-variables/usage.md b/docs/data/material/customization/css-theme-variables/usage.md index a905e51aade959..e4f99c976f70c3 100644 --- a/docs/data/material/customization/css-theme-variables/usage.md +++ b/docs/data/material/customization/css-theme-variables/usage.md @@ -35,8 +35,6 @@ function App() { :::info If you are using an experimental API, namely `CssVarsProvider`, replace it with the `ThemeProvider`. - -To learn more about it, check out the [migration guide](/material-ui/migration/migration-css-theme-variables/). ::: ## Dark mode only application diff --git a/docs/data/material/design-resources/material-ui-sync/material-ui-sync.md b/docs/data/material/design-resources/material-ui-sync/material-ui-sync.md index 4188ecebca412b..90ba412e3ebd37 100644 --- a/docs/data/material/design-resources/material-ui-sync/material-ui-sync.md +++ b/docs/data/material/design-resources/material-ui-sync/material-ui-sync.md @@ -236,17 +236,14 @@ You can also check out the Storybook preview to test the Material UI version of ## Using the generated theme -:::warning -Themes generated by Sync must be used with Material UI's [`CssVarsProvider`](/material-ui/migration/migration-css-theme-variables/)—the [`ThemeProvider`](/material-ui/customization/theming/#theme-provider) is not supported. -::: - Here's an example of how to add a Sync-generated theme to your codebase: ```tsx title="_app.tsx" -import { extendTheme, CssVarsProvider } from '@mui/material/styles'; +import { createTheme, ThemeProvider } from '@mui/material/styles'; export default function MyApp({ Component, pageProps }) { - const theme = extendTheme({ + const theme = createTheme({ + cssVariables: true, shape: { borderRadiusRound: 999, }, @@ -285,9 +282,9 @@ export default function MyApp({ Component, pageProps }) { }); return ( - + - +
); } ``` diff --git a/docs/data/material/migration/migrating-to-v6/migration-css-theme-variables.md b/docs/data/material/migration/migrating-to-v6/migration-css-theme-variables.md deleted file mode 100644 index d048c08110ccbe..00000000000000 --- a/docs/data/material/migration/migrating-to-v6/migration-css-theme-variables.md +++ /dev/null @@ -1,284 +0,0 @@ -# Migrating to CSS theme variables - -

A step-by-step migration guide to start using CSS theme variables in your project.

- -This is a guide that shows how to migrate an existing Material UI project to CSS theme variables. -This migration offers a solution to a longstanding issue in which a user who prefers dark mode will see a flash of light mode when the page first loads. - -## 1. Add the new provider - -### Without a custom theme - -If you aren't using [`ThemeProvider`](/material-ui/customization/theming/#theme-provider), then all you need to do is wrap your application with the `CssVarsProvider`: - -```js -import { CssVarsProvider } from '@mui/material/styles'; - -function App() { - return ...your existing application; -} -``` - -You should see the generated CSS theme variables in the stylesheet. Material UI components that render inside the new provider will automatically consume the variables. - -### Custom theme - -If you have a custom theme, you must replace `createTheme()` with the `extendTheme()` API. - -This moves palette customization to within the `colorSchemes` node. -Other properties can be copied and pasted. - -```diff --import { createTheme } from '@mui/material/styles'; -+import { extendTheme } from '@mui/material/styles'; - --const lightTheme = createTheme({ -- palette: { -- primary: { -- main: '#ff5252', -- }, -- ... -- }, -- // ...other properties, for example breakpoints, spacing, shape, typography, components --}); - --const darkTheme = createTheme({ -- palette: { -- mode: 'dark', -- primary: { -- main: '#000', -- }, -- ... -- }, --}); - -+const theme = extendTheme({ -+ colorSchemes: { -+ light: { -+ palette: { -+ primary: { -+ main: '#ff5252', -+ }, -+ ... -+ }, -+ }, -+ dark: { -+ palette: { -+ primary: { -+ main: '#000', -+ }, -+ ... -+ }, -+ }, -+ }, -+ // ...other properties -+}); -``` - -Then, replace the `ThemeProvider` with the `CssVarsProvider`: - -```diff --import { ThemeProvider } from '@mui/material/styles'; -+import { CssVarsProvider } from '@mui/material/styles'; - - const theme = extendTheme(...); - - function App() { -- return ... -+ return ... - } -``` - -Save the file and start the development server. -Your application should be able to run without crashing. - -:::info -If you encounter any errors, please [open an issue](https://github.com/mui/material-ui/issues/new/choose) to share it with us. We'd love to help. -::: - -If you inspect the page, you will see the generated CSS variables in the stylesheet. Material UI components that render inside the new provider will automatically use the CSS theme variables. - -## 2. Remove the toggle mode logic - -You can remove your existing logic that handles the user-selected mode and replace it with the `useColorScheme` hook. - -**Before**: - -```jsx -// This is only a minimal example to demonstrate the migration. -function App() { - const [mode, setMode] = React.useState(() => { - if (typeof window !== 'undefined') { - return localStorage.getItem('mode') ?? 'light'; - } - return 'light'; - }); - - // a new theme is created every time the mode changes - const theme = createTheme({ - palette: { - mode, - }, - // ...your custom theme - }); - return ( - - - ... - - ); -} -``` - -**After**: - -```js -import { CssVarsProvider, extendTheme, useColorScheme } from '@mui/material/styles'; - -function ModeToggle() { - const { mode, setMode } = useColorScheme(); - return ( - - ); -} - -const theme = extendTheme({ - // ...your custom theme -}); - -function App() { - return ( - - - ... - - ); -} -``` - -The `useColorScheme` hook provides the user-selected `mode` and a function `setMode` to update the value. - -The `mode` is stored inside `CssVarsProvider` which handles local storage synchronization for you. - -## 3. Prevent dark-mode flickering in server-side applications - -The `InitColorSchemeScript` component prevents dark-mode flickering by returning a script that must be run before React. - -### Next.js Pages Router - -Place the component before `
` in your [`pages/_document.js`](https://nextjs.org/docs/pages/building-your-application/routing/custom-document): - -```jsx -import Document, { Html, Head, Main, NextScript } from 'next/document'; -import InitColorSchemeScript from '@mui/material/InitColorSchemeScript'; - -export default class MyDocument extends Document { - render() { - return ( - - ... - - -
- - - - ); - } -} -``` - -### Gatsby - -Place the script in your [`gatsby-ssr.js`](https://www.gatsbyjs.com/docs/reference/config-files/gatsby-ssr/) file: - -```jsx -import * as React from 'react'; -import InitColorSchemeScript from '@mui/material/InitColorSchemeScript'; - -export function onRenderBody({ setPreBodyComponents }) { - setPreBodyComponents([]); -} -``` - -## 4. Refactor custom styles to use the attribute selector - -Users will continue to encounter dark-mode flickering if your custom styles include conditional expressions, as shown below: - -```js -// theming example -extendTheme({ - components: { - MuiChip: { - styleOverrides: { - root: ({ theme }) => ({ - backgroundColor: - theme.palette.mode === 'dark' - ? 'rgba(255 255 255 / 0.2)' - : 'rgba(0 0 0 / 0.2)', - }), - }, - }, - }, -}); - -// or a custom component example -const Button = styled('button')(({ theme }) => ({ - backgroundColor: - theme.palette.mode === 'dark' ? 'rgba(255 255 255 / 0.2)' : 'rgba(0 0 0 / 0.2)', -})); -``` - -This is because the `theme.palette.mode` is always `light` on the server. - -To fix this problem, replace conditional expressions with `theme.applyStyles()` instead: - -```js -// theming example -extendTheme({ - components: { - MuiChip: { - styleOverrides: { - root: ({ theme }) => ({ - backgroundColor: 'rgba(0 0 0 / 0.2)', - ...theme.applyStyles('dark', { - backgroundColor: 'rgba(255 255 255 / 0.2)', - }), - }), - }, - }, - }, -}); - -// or a custom component example -const Button = styled('button')(({ theme }) => ({ - backgroundColor: 'rgba(0 0 0 / 0.2)', - ...theme.applyStyles('dark', { - backgroundColor: 'rgba(255 255 255 / 0.2)', - }), -})); -``` - -:::info -The `theme.applyStyles()` is a new utility function available in Material UI v6 that applies the provided styles to the specified mode. -::: - -## 5. Test dark-mode flickering - -1. Toggle dark mode in your application -2. Open DevTools and set the [CPU throttling](https://developer.chrome.com/docs/devtools/performance/#simulate_a_mobile_cpu) to the lowest value (don't close the DevTools). -3. Refresh the page. You should see the all components in dark mode at first glance. diff --git a/docs/data/material/pages.ts b/docs/data/material/pages.ts index bac35ba97326ea..fc827c18a9f560 100644 --- a/docs/data/material/pages.ts +++ b/docs/data/material/pages.ts @@ -284,10 +284,6 @@ const pages: MuiPage[] = [ pathname: '/material-ui/migration/migrating-from-deprecated-apis', title: 'Migrating from deprecated APIs', }, - { - pathname: '/material-ui/migration/migration-css-theme-variables', - title: 'Migrating to CSS theme variables', - }, { pathname: '/material-ui/migration/migrating-to-pigment-css', title: 'Migrating to Pigment CSS', diff --git a/docs/pages/material-ui/migration/migration-css-theme-variables.js b/docs/pages/material-ui/migration/migration-css-theme-variables.js deleted file mode 100644 index 3a59ea771728b8..00000000000000 --- a/docs/pages/material-ui/migration/migration-css-theme-variables.js +++ /dev/null @@ -1,11 +0,0 @@ -import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; -import { - demos, - docs, - demoComponents, -} from 'docs/data/material/migration/migrating-to-v6/migration-css-theme-variables.md?muiMarkdown'; - -export default function Page() { - return ; -} diff --git a/docs/public/_redirects b/docs/public/_redirects index 2ff4fc06fd2533..e35dd899666fa9 100644 --- a/docs/public/_redirects +++ b/docs/public/_redirects @@ -508,7 +508,6 @@ https://v4.material-ui.com/* https://v4.mui.com/:splat 301! /material-ui/guides/right-to-left/ /material-ui/customization/right-to-left/ 301 /material-ui/guides/pickers-migration/ /material-ui/migration/pickers-migration/ 301 /material-ui/guides/styled-components/ /material-ui/integrations/styled-components/ 301 -/material-ui/experimental-api/css-theme-variables/migration/ /material-ui/migration/migration-css-theme-variables/ 301 /material-ui/experimental-api/css-theme-variables/overview/ /material-ui/customization/css-theme-variables/overview/ 301 /material-ui/experimental-api/css-theme-variables/usage/ /material-ui/customization/css-theme-variables/usage/ 301 /material-ui/experimental-api/css-theme-variables/customization/ /material-ui/customization/css-theme-variables/configuration/ 301 diff --git a/docs/translations/translations.json b/docs/translations/translations.json index 1ee4ef05be344a..8c579b0685e1a0 100644 --- a/docs/translations/translations.json +++ b/docs/translations/translations.json @@ -264,7 +264,6 @@ "Upgrade to v6": "Upgrade to v6", "/material-ui/migration/migrating-to-v6": "Migrating to v6: getting started", "/material-ui/migration/migrating-from-deprecated-apis": "Migrating from deprecated APIs", - "/material-ui/migration/migration-css-theme-variables": "Migrating to CSS theme variables", "/material-ui/migration/migrating-to-pigment-css": "Migrating to Pigment CSS", "Upgrade to v5": "Upgrade to v5", "/material-ui/migration/migration-v4": "Migrating to v5: getting started", From 786821a3c35b1fc135699c8b2eea7f47d4e8e424 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Fri, 2 Aug 2024 17:10:08 +0700 Subject: [PATCH 52/82] update guide --- .../css-theme-variables/overview.md | 76 ------------------- .../css-theme-variables/usage.md | 32 ++++++-- 2 files changed, 26 insertions(+), 82 deletions(-) diff --git a/docs/data/material/customization/css-theme-variables/overview.md b/docs/data/material/customization/css-theme-variables/overview.md index 226601cd7152b8..7c80ebeebbce97 100644 --- a/docs/data/material/customization/css-theme-variables/overview.md +++ b/docs/data/material/customization/css-theme-variables/overview.md @@ -38,82 +38,6 @@ For server-side applications, there are some trade-offs to consider: The comparison described in the table above may not be applicable to large and complex applications since there are so many factors that can impact performance metrics. ::: -## Mental model - -Adopting CSS variables requires some shifts in your mental model of theming and customizing user-selected modes. - -### Colors - -**[Default approach](/material-ui/customization/dark-mode/)**: Light and dark colors are created separately. - -```js -import { createTheme } from '@mui/material/styles'; - -const lightTheme = createTheme(); - -const darkTheme = createTheme({ - palette: { - mode: 'dark', - }, -}); -``` - -**CSS theme variables**: Light and dark colors are consolidated into a theme. - -```js -import { createTheme } from '@mui/material/styles'; - -const theme = createTheme({ - cssVariables: true, - colorSchemes: { - light: { // palette for light mode - palette: {...} - }, - dark: { // palette for dark mode - palette: {...} - } - } -}) -``` - -### Styling - -**Default approach**: Usually relies on JavaScript to switch the value between modes: - -```js -createTheme({ - components: { - MuiButton: { - styleOverrides: { - root: ({ theme }) => ({ - // use JavaScript conditional expression - color: theme.palette.mode === 'dark' ? '#fff' : theme.palette.primary.main, - }), - }, - }, - }, -}); -``` - -**CSS theme variables**: Styling leans toward cascading and specificity by using `theme.applyStyles()` function which lets you prevent [dark-mode SSR flickering](https://github.com/mui/material-ui/issues/27651): - -```js -createTheme({ - components: { - MuiButton: { - styleOverrides: { - root: ({ theme }) => ({ - color: theme.vars.palette.primary.main, - ...theme.applyStyles('dark', { - color: '#fff', - }), - }), - }, - }, - }, -}); -``` - ## What's next - To start a new project with CSS theme variables, check out the [basic usage guide](/material-ui/customization/css-theme-variables/usage/). diff --git a/docs/data/material/customization/css-theme-variables/usage.md b/docs/data/material/customization/css-theme-variables/usage.md index e4f99c976f70c3..45708de4fe8ffc 100644 --- a/docs/data/material/customization/css-theme-variables/usage.md +++ b/docs/data/material/customization/css-theme-variables/usage.md @@ -39,7 +39,7 @@ If you are using an experimental API, namely `CssVarsProvider`, replace it with ## Dark mode only application -To switch the default light to dark palette, set `colorSchemes: { dark: true }` to the `createTheme`. +To switch the default light to dark palette, set `palette: { mode: 'dark' }` to the `createTheme`. Material UI will generate the dark palette instead. ```jsx @@ -47,7 +47,7 @@ import { ThemeProvider, createTheme } from '@mui/material/styles'; const theme = createTheme({ cssVariables: true, - colorSchemes: { dark: true }, + palette: { mode: 'dark' }, }); function App() { @@ -57,8 +57,8 @@ function App() { ## Light and dark mode application -To support both light and dark modes, set `colorSchemes: { light: true, dark: true }` to the `createTheme`. -Material UI will generate both light and dark palette with [`@media (prefers-color-scheme)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) as the default method. +To support both light and dark modes, set `colorSchemes: { dark: true }` to the `createTheme`. +Material UI will generate both light (default) and dark palette with [`@media (prefers-color-scheme)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) as the default method. @@ -67,7 +67,7 @@ import { ThemeProvider, createTheme } from '@mui/material/styles'; const theme = createTheme({ cssVariables: true, - colorSchemes: { light: true, dark: true }, + colorSchemes: { dark: true }, }); function App() { @@ -93,7 +93,13 @@ function App() { -If you want to manually toggle the color scheme, check out the [advanced configuration](/material-ui/customization/css-theme-variables/configuration/#advanced-configuration). +:::info +You can explicitly set `colorSchemes: { light: true, dark: true }` which will produce the same result as the snippet above because light is the default color scheme. +::: + +The CSS media `prefers-color-scheme` method works with server-side rendering without extra configuration but you will not be able to add an interface for switching between the modes because the styles is based on user preference. + +If you want to manually toggle the modes, check out the [Toggling dark mode manually](/material-ui/customization/css-theme-variables/configuration/#toggling-dark-mode-manually) guide. ## Applying dark styles @@ -115,6 +121,20 @@ import Card from '@mui/material/Card'; />; ``` +:::warning +**Don't** use `theme.palette.mode` to apply between light and dark styles because it will produce a flickering effect. + +```js + +``` + +::: + ## Using theme variables All of these variables are accessible in an object in the theme called `vars`. From 415fe27e7660ee067d5fc9cd941dc7c246d823b4 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Fri, 2 Aug 2024 17:39:12 +0700 Subject: [PATCH 53/82] add demos --- .../DarkThemeCssVariables.js | 35 +++++++++ .../DarkThemeCssVariables.tsx | 35 +++++++++ .../DisableTransitionOnChange.js | 69 ++++++++++++++++++ .../DisableTransitionOnChange.tsx | 71 +++++++++++++++++++ .../css-theme-variables/configuration.md | 2 + .../css-theme-variables/usage.md | 17 +---- 6 files changed, 215 insertions(+), 14 deletions(-) create mode 100644 docs/data/material/customization/css-theme-variables/DarkThemeCssVariables.js create mode 100644 docs/data/material/customization/css-theme-variables/DarkThemeCssVariables.tsx create mode 100644 docs/data/material/customization/css-theme-variables/DisableTransitionOnChange.js create mode 100644 docs/data/material/customization/css-theme-variables/DisableTransitionOnChange.tsx diff --git a/docs/data/material/customization/css-theme-variables/DarkThemeCssVariables.js b/docs/data/material/customization/css-theme-variables/DarkThemeCssVariables.js new file mode 100644 index 00000000000000..797cd776d7e953 --- /dev/null +++ b/docs/data/material/customization/css-theme-variables/DarkThemeCssVariables.js @@ -0,0 +1,35 @@ +import * as React from 'react'; +import { createTheme, ThemeProvider } from '@mui/material/styles'; +import Box from '@mui/material/Box'; +import Alert from '@mui/material/Alert'; +import Typography from '@mui/material/Typography'; + +const theme = createTheme({ + cssVariables: true, + palette: { + mode: 'dark', + }, +}); + +export default function DarkThemeCssVariables() { + return ( + + + + You are seeing me in dark palette. + + + + ); +} diff --git a/docs/data/material/customization/css-theme-variables/DarkThemeCssVariables.tsx b/docs/data/material/customization/css-theme-variables/DarkThemeCssVariables.tsx new file mode 100644 index 00000000000000..797cd776d7e953 --- /dev/null +++ b/docs/data/material/customization/css-theme-variables/DarkThemeCssVariables.tsx @@ -0,0 +1,35 @@ +import * as React from 'react'; +import { createTheme, ThemeProvider } from '@mui/material/styles'; +import Box from '@mui/material/Box'; +import Alert from '@mui/material/Alert'; +import Typography from '@mui/material/Typography'; + +const theme = createTheme({ + cssVariables: true, + palette: { + mode: 'dark', + }, +}); + +export default function DarkThemeCssVariables() { + return ( + + + + You are seeing me in dark palette. + + + + ); +} diff --git a/docs/data/material/customization/css-theme-variables/DisableTransitionOnChange.js b/docs/data/material/customization/css-theme-variables/DisableTransitionOnChange.js new file mode 100644 index 00000000000000..f1822ea689bc55 --- /dev/null +++ b/docs/data/material/customization/css-theme-variables/DisableTransitionOnChange.js @@ -0,0 +1,69 @@ +import * as React from 'react'; +import { createTheme, ThemeProvider, useColorScheme } from '@mui/material/styles'; +import Stack from '@mui/material/Stack'; +import MenuItem from '@mui/material/MenuItem'; +import Switch from '@mui/material/Switch'; +import Select from '@mui/material/Select'; +import FormControlLabel from '@mui/material/FormControlLabel'; + +const theme = createTheme({ + cssVariables: { + colorSchemeSelector: '.demo-disable-transition-%s', + }, + colorSchemes: { dark: true }, +}); + +function ModeSwitcher() { + const { mode, setMode } = useColorScheme(); + if (!mode) { + return null; + } + return ( + + ); +} + +export default function DisableTransitionOnChange() { + const [disableTransition, setDisableTransition] = React.useState(false); + return ( + + + + setDisableTransition(event.target.checked)} + /> + } + label="Disable transition" + /> + + + ); +} diff --git a/docs/data/material/customization/css-theme-variables/DisableTransitionOnChange.tsx b/docs/data/material/customization/css-theme-variables/DisableTransitionOnChange.tsx new file mode 100644 index 00000000000000..23a1358fc23ffd --- /dev/null +++ b/docs/data/material/customization/css-theme-variables/DisableTransitionOnChange.tsx @@ -0,0 +1,71 @@ +import * as React from 'react'; +import { createTheme, ThemeProvider, useColorScheme } from '@mui/material/styles'; +import Stack from '@mui/material/Stack'; +import MenuItem from '@mui/material/MenuItem'; +import Switch from '@mui/material/Switch'; +import Select from '@mui/material/Select'; +import FormControlLabel from '@mui/material/FormControlLabel'; + +const theme = createTheme({ + cssVariables: { + colorSchemeSelector: '.demo-disable-transition-%s', + }, + colorSchemes: { dark: true }, +}); + +function ModeSwitcher() { + const { mode, setMode } = useColorScheme(); + if (!mode) { + return null; + } + return ( + + ); +} + +export default function DisableTransitionOnChange() { + const [disableTransition, setDisableTransition] = React.useState(false); + return ( + + + + setDisableTransition(event.target.checked)} + /> + } + label="Disable transition" + /> + + + ); +} diff --git a/docs/data/material/customization/css-theme-variables/configuration.md b/docs/data/material/customization/css-theme-variables/configuration.md index f3bc0689f95fd3..8b008795d3a043 100644 --- a/docs/data/material/customization/css-theme-variables/configuration.md +++ b/docs/data/material/customization/css-theme-variables/configuration.md @@ -295,3 +295,5 @@ To disable CSS transition when switching between modes, use `disableTransitionOn ```js ``` + +{{"demo": "DisableTransitionOnChange.js"}} diff --git a/docs/data/material/customization/css-theme-variables/usage.md b/docs/data/material/customization/css-theme-variables/usage.md index 45708de4fe8ffc..c9fb205bd8c0aa 100644 --- a/docs/data/material/customization/css-theme-variables/usage.md +++ b/docs/data/material/customization/css-theme-variables/usage.md @@ -37,25 +37,14 @@ function App() { If you are using an experimental API, namely `CssVarsProvider`, replace it with the `ThemeProvider`. ::: -## Dark mode only application +## Dark mode only variables To switch the default light to dark palette, set `palette: { mode: 'dark' }` to the `createTheme`. Material UI will generate the dark palette instead. -```jsx -import { ThemeProvider, createTheme } from '@mui/material/styles'; - -const theme = createTheme({ - cssVariables: true, - palette: { mode: 'dark' }, -}); - -function App() { - return {/* ...you app */}; -} -``` +{{"demo": "DarkThemeCssVariables.js"}} -## Light and dark mode application +## Light and dark modes To support both light and dark modes, set `colorSchemes: { dark: true }` to the `createTheme`. Material UI will generate both light (default) and dark palette with [`@media (prefers-color-scheme)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) as the default method. From b98e8dce43258c1e143f9f75eb2668638cf8d8e5 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Fri, 2 Aug 2024 22:10:34 +0700 Subject: [PATCH 54/82] replace fireEvent with user.selectOptions --- packages/mui-material/src/styles/ThemeProvider.test.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/mui-material/src/styles/ThemeProvider.test.tsx b/packages/mui-material/src/styles/ThemeProvider.test.tsx index 82e086c0a21921..5f6f58d31d522e 100644 --- a/packages/mui-material/src/styles/ThemeProvider.test.tsx +++ b/packages/mui-material/src/styles/ThemeProvider.test.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { expect } from 'chai'; -import { createRenderer, fireEvent } from '@mui/internal-test-utils'; +import { createRenderer } from '@mui/internal-test-utils'; import { ThemeProvider, createTheme, useColorScheme } from '@mui/material/styles'; describe('ThemeProvider', () => { @@ -76,11 +76,11 @@ describe('ThemeProvider', () => { ).not.toErrorDev(); }); - it('should be able to switch between modes', () => { + it('should be able to switch between modes', async () => { const theme = createTheme({ colorSchemes: { dark: true }, }); - const { getByTestId } = render( + const { getByTestId, user } = render( , @@ -88,7 +88,7 @@ describe('ThemeProvider', () => { expect(getByTestId('mode-switcher')).to.have.property('value', 'system'); - fireEvent.change(getByTestId('mode-switcher'), { target: { value: 'dark' } }); + await user.selectOptions(getByTestId('mode-switcher'), 'dark'); expect(getByTestId('mode-switcher')).to.have.property('value', 'dark'); }); From 66331ae7d6c741410c7d08cfe55d31dcb0a55777 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Fri, 2 Aug 2024 22:14:02 +0700 Subject: [PATCH 55/82] fix as suggested --- docs/public/static/error-codes.json | 2 +- packages/mui-material/src/styles/createTheme.test.js | 2 +- packages/mui-material/src/styles/createThemeWithVars.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/public/static/error-codes.json b/docs/public/static/error-codes.json index 7414cbb649d8fe..c4514997394204 100644 --- a/docs/public/static/error-codes.json +++ b/docs/public/static/error-codes.json @@ -19,5 +19,5 @@ "18": "MUI: The provided shorthand %s is invalid. The format should be `@` or `@/`.\nFor example, `@sm` or `@600` or `@40rem/sidebar`.", "19": "MUI: The `experimental_sx` has been moved to `theme.unstable_sx`.For more details, see https://github.com/mui/material-ui/pull/35150.", "20": "MUI: `vars` is a private field used for CSS variables support.\nPlease use another name.", - "21": "MUI: The provided `colorSchemes.%s` is either missing or invalid." + "21": "MUI: The `colorSchemes.%s` option is either missing or invalid." } diff --git a/packages/mui-material/src/styles/createTheme.test.js b/packages/mui-material/src/styles/createTheme.test.js index 3491e70c142c19..926a80321b6ef9 100644 --- a/packages/mui-material/src/styles/createTheme.test.js +++ b/packages/mui-material/src/styles/createTheme.test.js @@ -13,7 +13,7 @@ const darkPalette = createPalette({ mode: 'dark' }); describe('createTheme', () => { const { render } = createRenderer(); - it('should not have custom properties', () => { + it('should not create vars if cssVariables: false', () => { const theme = createTheme({ cssVariables: false }); expect(theme.cssVariables).to.equal(false); expect('vars' in theme).to.equal(false); diff --git a/packages/mui-material/src/styles/createThemeWithVars.js b/packages/mui-material/src/styles/createThemeWithVars.js index 84a6b997ee0cb8..1ac1e9cf1fb4f9 100644 --- a/packages/mui-material/src/styles/createThemeWithVars.js +++ b/packages/mui-material/src/styles/createThemeWithVars.js @@ -176,7 +176,7 @@ export default function createThemeWithVars(options = {}, ...args) { if (!defaultScheme) { throw new MuiError( - 'MUI: The provided `colorSchemes.%s` is either missing or invalid.', + 'MUI: The `colorSchemes.%s` option is either missing or invalid.', defaultColorScheme, ); } From 023c7567050afed631ea48acd5328142e6ea90d0 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Fri, 2 Aug 2024 22:43:30 +0700 Subject: [PATCH 56/82] fix test --- packages/mui-material/src/styles/extendTheme.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/mui-material/src/styles/extendTheme.test.js b/packages/mui-material/src/styles/extendTheme.test.js index 2aebefacfd42e4..3e2360871a0de5 100644 --- a/packages/mui-material/src/styles/extendTheme.test.js +++ b/packages/mui-material/src/styles/extendTheme.test.js @@ -74,12 +74,12 @@ describe('extendTheme', () => { it('should throw error if the default color scheme is invalid', () => { expect(() => extendTheme({ colorSchemes: { dark: false }, defaultColorScheme: 'dark' }), - ).to.throw('MUI: The provided `colorSchemes.dark` is either missing or invalid.'); + ).to.throw('MUI: The `colorSchemes.dark` option is either missing or invalid.'); }); it('should throw error if the default color scheme is missing', () => { expect(() => extendTheme({ defaultColorScheme: 'paper' })).to.throw( - 'MUI: The provided `colorSchemes.paper` is either missing or invalid.', + 'MUI: The `colorSchemes.paper` option is either missing or invalid.', ); }); From 7d2dde92fcd1f00d10440edde04b6fdbf989df0b Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Fri, 2 Aug 2024 22:51:01 +0700 Subject: [PATCH 57/82] use createTheme --- packages/mui-material/src/styles/ThemeProviderWithVars.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/mui-material/src/styles/ThemeProviderWithVars.tsx b/packages/mui-material/src/styles/ThemeProviderWithVars.tsx index b7d747a75f36c5..815b82e3ec7482 100644 --- a/packages/mui-material/src/styles/ThemeProviderWithVars.tsx +++ b/packages/mui-material/src/styles/ThemeProviderWithVars.tsx @@ -1,8 +1,9 @@ 'use client'; import * as React from 'react'; -import { unstable_createCssVarsProvider as createCssVarsProvider, SxProps } from '@mui/system'; import styleFunctionSx from '@mui/system/styleFunctionSx'; -import createThemeWithVars, { SupportedColorScheme, CssVarsTheme } from './createThemeWithVars'; +import { unstable_createCssVarsProvider as createCssVarsProvider, SxProps } from '@mui/system'; +import { SupportedColorScheme, CssVarsTheme } from './createThemeWithVars'; +import createTheme from './createTheme'; import createTypography from './createTypography'; import THEME_ID from './identifier'; import { defaultConfig } from '../InitColorSchemeScript/InitColorSchemeScript'; @@ -13,7 +14,7 @@ const { getInitColorSchemeScript: deprecatedGetInitColorSchemeScript, } = createCssVarsProvider({ themeId: THEME_ID, - theme: createThemeWithVars, + theme: () => createTheme({ cssVariables: true }), colorSchemeStorageKey: defaultConfig.colorSchemeStorageKey, modeStorageKey: defaultConfig.modeStorageKey, defaultColorScheme: { From a56e5c8745c91c987f2aa3380faef80aac612ebf Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Fri, 2 Aug 2024 23:03:56 +0700 Subject: [PATCH 58/82] prevent theme augmentation tests --- packages/mui-material/src/styles/ThemeProviderWithVars.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/mui-material/src/styles/ThemeProviderWithVars.tsx b/packages/mui-material/src/styles/ThemeProviderWithVars.tsx index 815b82e3ec7482..93479f04587d10 100644 --- a/packages/mui-material/src/styles/ThemeProviderWithVars.tsx +++ b/packages/mui-material/src/styles/ThemeProviderWithVars.tsx @@ -14,6 +14,7 @@ const { getInitColorSchemeScript: deprecatedGetInitColorSchemeScript, } = createCssVarsProvider({ themeId: THEME_ID, + // @ts-ignore ignore module augmentation tests theme: () => createTheme({ cssVariables: true }), colorSchemeStorageKey: defaultConfig.colorSchemeStorageKey, modeStorageKey: defaultConfig.modeStorageKey, From 4306f26838a20eb6b72d8c22d1f6a0016b37da36 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Mon, 5 Aug 2024 10:56:11 +0700 Subject: [PATCH 59/82] perf: remove unnecessary iteration --- .../mui-system/src/cssVars/createCssVarsProvider.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.js b/packages/mui-system/src/cssVars/createCssVarsProvider.js index 2bda9137a8638f..66a23b7a0451f8 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.js +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.js @@ -142,8 +142,9 @@ export default function createCssVarsProvider(options) { } // 4. Resolve the color scheme and merge it to the theme - Object.entries(colorSchemes).forEach(([key, scheme]) => { - if (key === calculatedColorScheme) { + if (calculatedColorScheme) { + const scheme = colorSchemes[calculatedColorScheme]; + if (scheme && typeof scheme === 'object') { // 4.1 Merge the selected color scheme to the theme Object.keys(scheme).forEach((schemeKey) => { if (scheme[schemeKey] && typeof scheme[schemeKey] === 'object') { @@ -156,11 +157,8 @@ export default function createCssVarsProvider(options) { theme[schemeKey] = scheme[schemeKey]; } }); - if (theme.palette) { - theme.palette.colorScheme = key; - } } - }); + } // 5. Declaring effects // 5.1 Updates the selector value to use the current color scheme which tells CSS to use the proper stylesheet. From 47d98eb0a3da5d406c72a493a5ecc7fc6169a833 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Mon, 5 Aug 2024 10:56:27 +0700 Subject: [PATCH 60/82] fix: custom color schemes --- packages/mui-material/src/styles/createTheme.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/mui-material/src/styles/createTheme.ts b/packages/mui-material/src/styles/createTheme.ts index 813f20734455d4..5bf0b5ed8072ba 100644 --- a/packages/mui-material/src/styles/createTheme.ts +++ b/packages/mui-material/src/styles/createTheme.ts @@ -82,14 +82,14 @@ export default function createTheme( } theme.defaultColorScheme = defaultColorSchemeInput; - theme.colorSchemes = {}; + theme.colorSchemes = colorSchemesInput as Record; if (theme.palette.mode === 'light') { - theme.colorSchemes = { light: { palette: theme.palette } as ColorSystem }; + theme.colorSchemes.light = { palette: theme.palette } as ColorSystem; attachColorScheme(theme, 'dark', colorSchemesInput.dark); } if (theme.palette.mode === 'dark') { - theme.colorSchemes = { dark: { palette: theme.palette } as ColorSystem }; + theme.colorSchemes.dark = { palette: theme.palette } as ColorSystem; attachColorScheme(theme, 'light', colorSchemesInput.light); } From 9ca6e73bd999966c4764270a235d606c5a652d55 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Mon, 5 Aug 2024 11:21:42 +0700 Subject: [PATCH 61/82] add createColorScheme --- .../src/styles/createColorScheme.ts | 33 ++++++++++++++++++ .../src/styles/createThemeWithVars.js | 34 +++++-------------- packages/mui-material/src/styles/index.d.ts | 1 + packages/mui-material/src/styles/index.js | 1 + 4 files changed, 44 insertions(+), 25 deletions(-) create mode 100644 packages/mui-material/src/styles/createColorScheme.ts diff --git a/packages/mui-material/src/styles/createColorScheme.ts b/packages/mui-material/src/styles/createColorScheme.ts new file mode 100644 index 00000000000000..14d41cabf38e27 --- /dev/null +++ b/packages/mui-material/src/styles/createColorScheme.ts @@ -0,0 +1,33 @@ +import type { ColorSystemOptions } from './createThemeWithVars'; +import createPalette from './createPalette'; +import getOverlayAlpha from './getOverlayAlpha'; + +const defaultDarkOverlays = [...Array(25)].map((_, index) => { + if (index === 0) { + return undefined; + } + const overlay = getOverlayAlpha(index); + return `linear-gradient(rgba(255 255 255 / ${overlay}), rgba(255 255 255 / ${overlay}))`; +}); + +export function getOpacity(mode: 'light' | 'dark') { + return { + inputPlaceholder: mode === 'dark' ? 0.5 : 0.42, + inputUnderline: mode === 'dark' ? 0.7 : 0.42, + switchTrackDisabled: mode === 'dark' ? 0.2 : 0.12, + switchTrack: mode === 'dark' ? 0.3 : 0.38, + }; +} +export function getOverlays(mode: 'light' | 'dark') { + return mode === 'dark' ? defaultDarkOverlays : []; +} + +export default function createColorScheme(options: ColorSystemOptions) { + const { palette = {}, opacity, overlays, ...rest } = options; + return { + palette: createPalette(palette), + opacity: { ...getOpacity(palette.mode || 'light'), ...opacity }, + overlays: overlays || getOverlays(palette.mode || 'light'), + ...rest, + } as unknown as ColorSystemOptions; +} diff --git a/packages/mui-material/src/styles/createThemeWithVars.js b/packages/mui-material/src/styles/createThemeWithVars.js index 1ac1e9cf1fb4f9..b8adb2deefb75e 100644 --- a/packages/mui-material/src/styles/createThemeWithVars.js +++ b/packages/mui-material/src/styles/createThemeWithVars.js @@ -21,19 +21,11 @@ import { } from '@mui/system/colorManipulator'; import createThemeNoVars from './createThemeNoVars'; +import createColorScheme, { getOpacity, getOverlays } from './createColorScheme'; import defaultShouldSkipGeneratingVar from './shouldSkipGeneratingVar'; -import getOverlayAlpha from './getOverlayAlpha'; import defaultGetSelector from './createGetSelector'; import { stringifyTheme } from './stringifyTheme'; -const defaultDarkOverlays = [...Array(25)].map((_, index) => { - if (index === 0) { - return undefined; - } - const overlay = getOverlayAlpha(index); - return `linear-gradient(rgba(255 255 255 / ${overlay}), rgba(255 255 255 / ${overlay}))`; -}); - function assignNode(obj, keys) { keys.forEach((k) => { if (!obj[k]) { @@ -95,30 +87,22 @@ const silent = (fn) => { export const createGetCssVar = (cssVarPrefix = 'mui') => systemCreateGetCssVar(cssVarPrefix); -function getOpacity(mode) { - return { - inputPlaceholder: mode === 'dark' ? 0.5 : 0.42, - inputUnderline: mode === 'dark' ? 0.7 : 0.42, - switchTrackDisabled: mode === 'dark' ? 0.2 : 0.12, - switchTrack: mode === 'dark' ? 0.3 : 0.38, - }; -} -function getOverlays(mode) { - return mode === 'dark' ? defaultDarkOverlays : []; -} - function attachColorScheme(colorSchemes, scheme, restTheme, colorScheme) { if (!scheme) { return undefined; } scheme = scheme === true ? {} : scheme; const mode = colorScheme === 'dark' ? 'dark' : 'light'; + if (!restTheme) { + colorSchemes[colorScheme] = createColorScheme({ + ...scheme, + palette: { mode, ...scheme?.palette }, + }); + return undefined; + } const { palette, ...muiTheme } = createThemeNoVars({ ...restTheme, - palette: { - mode, - ...scheme?.palette, - }, + palette: { mode, ...scheme?.palette }, }); colorSchemes[colorScheme] = { ...scheme, diff --git a/packages/mui-material/src/styles/index.d.ts b/packages/mui-material/src/styles/index.d.ts index 38dbdac7b6078b..afdf2e7ec77c9e 100644 --- a/packages/mui-material/src/styles/index.d.ts +++ b/packages/mui-material/src/styles/index.d.ts @@ -21,6 +21,7 @@ export { TypeAction, TypeBackground, } from './createPalette'; +export { default as createColorScheme } from './createColorScheme'; export { default as createStyles } from './createStyles'; export { Typography as TypographyVariants, diff --git a/packages/mui-material/src/styles/index.js b/packages/mui-material/src/styles/index.js index 08a68e212b13c3..b38149b9eb1274 100644 --- a/packages/mui-material/src/styles/index.js +++ b/packages/mui-material/src/styles/index.js @@ -33,6 +33,7 @@ export { default as createStyles } from './createStyles'; export { getUnit as unstable_getUnit, toUnitless as unstable_toUnitless } from './cssUtils'; export { default as responsiveFontSizes } from './responsiveFontSizes'; export { default as createTransitions, duration, easing } from './createTransitions'; +export { default as createColorScheme } from './createColorScheme'; export { default as useTheme } from './useTheme'; export { default as useThemeProps } from './useThemeProps'; export { default as styled } from './styled'; From 9c35d2378607930b228890c5d64f058fb9f454cd Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Mon, 5 Aug 2024 11:45:00 +0700 Subject: [PATCH 62/82] fix types --- .../mui-material/src/styles/createColorScheme.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/mui-material/src/styles/createColorScheme.ts b/packages/mui-material/src/styles/createColorScheme.ts index 14d41cabf38e27..58815c7e9e7718 100644 --- a/packages/mui-material/src/styles/createColorScheme.ts +++ b/packages/mui-material/src/styles/createColorScheme.ts @@ -1,5 +1,5 @@ import type { ColorSystemOptions } from './createThemeWithVars'; -import createPalette from './createPalette'; +import createPalette, { PaletteOptions } from './createPalette'; import getOverlayAlpha from './getOverlayAlpha'; const defaultDarkOverlays = [...Array(25)].map((_, index) => { @@ -23,11 +23,17 @@ export function getOverlays(mode: 'light' | 'dark') { } export default function createColorScheme(options: ColorSystemOptions) { - const { palette = {}, opacity, overlays, ...rest } = options; + const { + palette: paletteInput = { mode: 'light' } as PaletteOptions, // need to cast to avoid module augmentation test + opacity, + overlays, + ...rest + } = options; + const palette = createPalette(paletteInput); return { - palette: createPalette(palette), - opacity: { ...getOpacity(palette.mode || 'light'), ...opacity }, - overlays: overlays || getOverlays(palette.mode || 'light'), + palette, + opacity: { ...getOpacity(palette.mode), ...opacity }, + overlays: overlays || getOverlays(palette.mode), ...rest, } as unknown as ColorSystemOptions; } From a1c3f4f98f39cc50080f3069ebb7f3d82d5b8e59 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Mon, 5 Aug 2024 16:08:28 +0700 Subject: [PATCH 63/82] adjust dark mode content --- .../customization/dark-mode/DarkTheme.js | 6 -- .../customization/dark-mode/dark-mode.md | 101 +++++++++--------- 2 files changed, 53 insertions(+), 54 deletions(-) diff --git a/docs/data/material/customization/dark-mode/DarkTheme.js b/docs/data/material/customization/dark-mode/DarkTheme.js index cd48b9a9c4e581..7e48bd611922ae 100644 --- a/docs/data/material/customization/dark-mode/DarkTheme.js +++ b/docs/data/material/customization/dark-mode/DarkTheme.js @@ -97,7 +97,6 @@ function Demo() { ); } -const lightTheme = createTheme(); const darkTheme = createTheme({ palette: { // Switching the dark mode on is a single property value change. @@ -106,16 +105,11 @@ const darkTheme = createTheme({ }); export default function DarkTheme() { - // Note that if you intend to use two or more themes at the same time on your site, - // you need to wrap them with a single ThemeProvider at the root (not like in this example). return ( - - - ); } diff --git a/docs/data/material/customization/dark-mode/dark-mode.md b/docs/data/material/customization/dark-mode/dark-mode.md index cba900cae36fa2..c48788e8e6b1f9 100644 --- a/docs/data/material/customization/dark-mode/dark-mode.md +++ b/docs/data/material/customization/dark-mode/dark-mode.md @@ -6,9 +6,7 @@ You can make your application use the dark theme as the default—regardless of the user's preference—by adding `mode: 'dark'` to the `createTheme` helper: - - -```js Default +```js import { ThemeProvider, createTheme } from '@mui/material/styles'; import CssBaseline from '@mui/material/CssBaseline'; @@ -28,39 +26,32 @@ export default function App() { } ``` -```js Custom -import { ThemeProvider, createTheme } from '@mui/material/styles'; -import { pink } from '@mui/material/colors'; +Adding `mode: 'dark'` to the `createTheme` helper modifies several palette values, as shown in the following demo: + +{{"demo": "DarkTheme.js", "bg": "inline", "hideToolbar": true}} + +Adding `` inside of the `` component will also enable dark mode for the app's background. +:::warning +Setting the dark mode this way only works if you are using [the default palette](/material-ui/customization/default-theme/). If you have a custom palette, make sure that you have the correct values based on the `mode`. The next section explains how to do this. +::: + +### Overriding dark palette + +To override the default palette, provide a [palette object](/material-ui/customization/palette/#default-colors) with custom colors in hex, RGB, or HSL format: + +```jsx const darkTheme = createTheme({ palette: { mode: 'dark', primary: { - main: pink[200], // to learn more, check out the Color customization page + main: '#ff5252', }, }, }); - -export default function App() { - return ( - -
This app is using the dark mode
-
- ); -} ``` -
- -Adding `mode: 'dark'` to the `createTheme` helper modifies several palette values, as shown in the following demo: - -{{"demo": "DarkTheme.js", "bg": "inline", "hideToolbar": true}} - -Adding `` inside of the `` component will also enable dark mode for the app's background. - -:::warning -Setting the dark mode this way only works if you are using [the default palette](/material-ui/customization/default-theme/). If you have a custom palette, make sure that you have the correct values based on the `mode`. The next section explains how to do this. -::: +For a comprehensive understanding of the palette structure, refer to the [palette page](/material-ui/customization/palette/). ## System preference @@ -68,11 +59,12 @@ Users might have a preference for light or dark mode that they've set through th ### Built-in support -Material UI has built-in support for system preference when dark color scheme is provided: +To build an application with multiple color schemes, use `colorSchemes` node. +The built-in color schemes are `light` and `dark` which can be enabled by setting the value to `true`. - +The light color scheme is enabled by default, so you only need to set the dark color scheme: -```js Default +```js import { ThemeProvider, createTheme } from '@mui/material/styles'; const theme = createTheme({ @@ -86,25 +78,7 @@ function App() { } ``` -```js Custom -import { pink } from '@mui/material/colors'; - -const theme = createTheme({ - colorSchemes: { - dark: { - palette: { - primary: { - main: pink[200], // to learn more, check out the Palette tokens page - }, - }, - }, - }, -}); -``` - - - -The built-in support includes the following features: +When `colorSchemes` is provided, the following features are activated: - Automatic switching between light and dark color schemes based on the user's preference. - Synchronize between window tabs. If the user changes the color scheme in one tab, the other tabs will also update. @@ -251,3 +225,34 @@ Apply styles for a specific mode. - `mode` (`'light' | 'dark'`) - The mode for which the styles should be applied. - `styles` (`CSSObject`) - An object which contains the styles to be applied for the specified mode. + +## Dark mode flicker + +### The problem + +Server-rendered apps are built before they reach the user's device. This means they can't automatically adjust to the user's preferred color scheme when first loaded. + +Here's what typically happens: + +1. You load the app and set it to dark mode. +2. You refresh the page. +3. The app briefly shows in light mode (the default). +4. Then it switches back to dark mode once the app fully loads. + +This "flash" of light mode happens every time you open the app, as long as your browser remembers your dark mode preference. + +This sudden change can be jarring, especially in low-light environments. It can strain your eyes and disrupt your experience, particularly if you interact with the app during this transition. + +To better understand this issue, take a look at the GIF below: + +An example video that shows a page that initially loads correctly in dark mode but quickly flickers to light mode. + +### The solution: CSS variables + +Solving this problem required us to take a novel approach to styling and theming. +(See this [RFC on CSS variables support](https://github.com/mui/material-ui/issues/27651) to learn more about the implementation of this feature.) + +For applications that want to support light and dark mode using CSS media `prefers-color-scheme`, enabling the [CSS variables feature](/material-ui/customization/css-theme-variables/usage/#light-and-dark-modes) will fix the issue. + +However, if you want to toggle between modes manually, it requires a combination of CSS variables and the `InitColorSchemeScript` component to avoid the flicker. +Check out the [Preventing SSR flicker](/material-ui/customization/css-theme-variables/configuration/#preventing-ssr-flickering) section for more details. From 9971cbd9f760ba97049928d1925a78e3397935f0 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Mon, 5 Aug 2024 19:26:35 +0700 Subject: [PATCH 64/82] update usage --- .../material/customization/css-theme-variables/usage.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/data/material/customization/css-theme-variables/usage.md b/docs/data/material/customization/css-theme-variables/usage.md index c9fb205bd8c0aa..40cf889f349a01 100644 --- a/docs/data/material/customization/css-theme-variables/usage.md +++ b/docs/data/material/customization/css-theme-variables/usage.md @@ -111,7 +111,7 @@ import Card from '@mui/material/Card'; ``` :::warning -**Don't** use `theme.palette.mode` to apply between light and dark styles because it will produce a flickering effect. +**Don't** use `theme.palette.mode` to switch between light and dark styles because it will produce a [flickering effect](/material-ui/customization/dark-mode/#dark-mode-flicker). ```js Date: Tue, 6 Aug 2024 11:04:33 +0700 Subject: [PATCH 65/82] update content --- .../css-theme-variables/configuration.md | 4 ++-- .../customization/css-theme-variables/usage.md | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/data/material/customization/css-theme-variables/configuration.md b/docs/data/material/customization/css-theme-variables/configuration.md index 8b008795d3a043..93a5fc81b21970 100644 --- a/docs/data/material/customization/css-theme-variables/configuration.md +++ b/docs/data/material/customization/css-theme-variables/configuration.md @@ -99,7 +99,7 @@ function ModeSwitcher() { ``` :::success -After React's hydrate the tree, the mode will be `system` to follow the user's preference. +After React hydrates the tree, the mode will be `system` to follow the user's preference. ::: ### Determining the system mode @@ -268,7 +268,7 @@ In the example below, all the components inside the `div` will always be dark: ## Disabling CSS color scheme -By default, the `createTheme` attach [CSS color-scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme) based on the palette mode. If you want to disable it, set `disableCssColorScheme` to `true`: +By default, `createTheme` attaches [CSS color-scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme) based on the palette mode. If you want to disable it, use `disableCssColorScheme`: ```js createTheme({ diff --git a/docs/data/material/customization/css-theme-variables/usage.md b/docs/data/material/customization/css-theme-variables/usage.md index 40cf889f349a01..419c15c57fb285 100644 --- a/docs/data/material/customization/css-theme-variables/usage.md +++ b/docs/data/material/customization/css-theme-variables/usage.md @@ -4,10 +4,10 @@ ## Getting started -To enable CSS theme variables, create a theme with `cssVariables: true` and pass it to the `ThemeProvider`. +To use CSS theme variables, create a theme with `cssVariables: true` and wrap your app with `ThemeProvider`. -Once the `App` renders on the screen, you will see the CSS theme variables in the HTML `:root` stylesheet. -The variables are flattened and prefixed with `--mui` by default: +After rendering, you'll see CSS variables in the `:root` stylesheet of your HTML document. +By default, these variables are flattened and prefixed with `--mui`: @@ -34,7 +34,7 @@ function App() { :::info -If you are using an experimental API, namely `CssVarsProvider`, replace it with the `ThemeProvider`. +If you're using the experimental `CssVarsProvider` API, replace it with `ThemeProvider`. ::: ## Dark mode only variables @@ -46,8 +46,8 @@ Material UI will generate the dark palette instead. ## Light and dark modes -To support both light and dark modes, set `colorSchemes: { dark: true }` to the `createTheme`. -Material UI will generate both light (default) and dark palette with [`@media (prefers-color-scheme)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) as the default method. +To enable both light and dark modes, add `colorSchemes: { dark: true }` to `createTheme`. +This generates light (default) and dark palettes using `@media (prefers-color-scheme)` as a default method. @@ -86,7 +86,7 @@ function App() { You can explicitly set `colorSchemes: { light: true, dark: true }` which will produce the same result as the snippet above because light is the default color scheme. ::: -The CSS media `prefers-color-scheme` method works with server-side rendering without extra configuration but you will not be able to add an interface for switching between the modes because the styles is based on user preference. +The CSS media `prefers-color-scheme` method works with server-side rendering without extra configuration but you will not be able to toggle between the modes because the styles is based on the browser media. If you want to manually toggle the modes, check out the [Toggling dark mode manually](/material-ui/customization/css-theme-variables/configuration/#toggling-dark-mode-manually) guide. @@ -126,7 +126,7 @@ import Card from '@mui/material/Card'; ## Using theme variables -When the CSS variables feature is enabled, the `vars` node is added to the theme. This `vars` object mirrors the structure of a serializable theme, with each value corresponding to a CSS variable. +When CSS variables feature is enabled, the `vars` node is added to the theme. This `vars` object mirrors the structure of a serializable theme, with each value corresponding to a CSS variable. - `theme.vars` (recommended): an object that refers to the CSS theme variables. From d7860b2482d3aff770076bde5c7300642e351963 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 7 Aug 2024 16:09:22 +0700 Subject: [PATCH 66/82] add deprecation message --- .../src/styles/ThemeProviderWithVars.tsx | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/packages/mui-material/src/styles/ThemeProviderWithVars.tsx b/packages/mui-material/src/styles/ThemeProviderWithVars.tsx index 93479f04587d10..8c22656c4b3b91 100644 --- a/packages/mui-material/src/styles/ThemeProviderWithVars.tsx +++ b/packages/mui-material/src/styles/ThemeProviderWithVars.tsx @@ -9,7 +9,7 @@ import THEME_ID from './identifier'; import { defaultConfig } from '../InitColorSchemeScript/InitColorSchemeScript'; const { - CssVarsProvider, + CssVarsProvider: InternalCssVarsProvider, useColorScheme, getInitColorSchemeScript: deprecatedGetInitColorSchemeScript, } = createCssVarsProvider({ @@ -44,16 +44,17 @@ function Experimental_CssVarsProvider(props: any) { if (!warnedOnce) { console.warn( [ - 'MUI: The Experimental_CssVarsProvider component has been stabilized.', + 'MUI: The Experimental_CssVarsProvider component has been merged to ThemeProvider.', '', - "You should use `import { CssVarsProvider } from '@mui/material/styles'`", + "You should use `import { ThemeProvider } from '@mui/material/styles'` instead.", + 'For more details, check out https://mui.com/material-ui/customization/css-theme-variables/usage/', ].join('\n'), ); warnedOnce = true; } - return ; + return ; } let warnedInitScriptOnce = false; @@ -75,4 +76,28 @@ const getInitColorSchemeScript: typeof deprecatedGetInitColorSchemeScript = (par return deprecatedGetInitColorSchemeScript(params); }; -export { useColorScheme, CssVarsProvider, getInitColorSchemeScript, Experimental_CssVarsProvider }; +/** + * @deprecated + * The `CssVarsProvider` component has been deprecated and merged to `ThemeProvider`. + * + * You should use `ThemeProvider` and `createTheme` instead: + * + * ```diff + * - import { CssVarsProvider, extendTheme } from '@mui/material/styles'; + * + import { ThemeProvider, createTheme } from '@mui/material/styles'; + * + * - const theme = extendTheme(); + * + const theme = createTheme({ + * + cssVariables: true, + * + colorSchemes: { light: true, dark: true }, + * + }); + * + * - + * + + * ``` + * + * To see the full documentation, check out https://mui.com/material-ui/customization/css-theme-variables/usage/. + */ +export const CssVarsProvider = InternalCssVarsProvider; + +export { useColorScheme, getInitColorSchemeScript, Experimental_CssVarsProvider }; From 401ba0283558f051b895e23cb3c3fc371d049a47 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 7 Aug 2024 16:10:01 +0700 Subject: [PATCH 67/82] add comment --- packages/mui-material/src/styles/ThemeProviderWithVars.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/mui-material/src/styles/ThemeProviderWithVars.tsx b/packages/mui-material/src/styles/ThemeProviderWithVars.tsx index 8c22656c4b3b91..6595b805926374 100644 --- a/packages/mui-material/src/styles/ThemeProviderWithVars.tsx +++ b/packages/mui-material/src/styles/ThemeProviderWithVars.tsx @@ -77,6 +77,7 @@ const getInitColorSchemeScript: typeof deprecatedGetInitColorSchemeScript = (par }; /** + * TODO: remove this export in v7 * @deprecated * The `CssVarsProvider` component has been deprecated and merged to `ThemeProvider`. * From a7c3a270396af4c37f58cee1dc7ca8b69a3ffced Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 7 Aug 2024 16:42:50 +0700 Subject: [PATCH 68/82] run link-check --- docs/.link-check-errors.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/.link-check-errors.txt b/docs/.link-check-errors.txt index 6164ccad846069..7a96d1bc6f5222 100644 --- a/docs/.link-check-errors.txt +++ b/docs/.link-check-errors.txt @@ -1,6 +1,5 @@ Broken links found by `pnpm docs:link-check` that exist: -- https://mui.com/material-ui/customization/css-theme-variables/configuration/#advanced-configuration - https://mui.com/material-ui/customization/css-theme-variables/configuration/#changing-variable-prefixes - https://mui.com/material-ui/customization/theme-components/#creating-new-component-variants - https://mui.com/material-ui/customization/theme-components/#overrides-based-on-props From e8a578426772c3f5b0ebcdd924f8919ad0d5c73f Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Fri, 9 Aug 2024 11:43:15 +0700 Subject: [PATCH 69/82] remove CssVarsProvider --- docs/data/material/customization/theming/theming.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/data/material/customization/theming/theming.md b/docs/data/material/customization/theming/theming.md index ad18729fb97c88..ad6b0f9eb0aa61 100644 --- a/docs/data/material/customization/theming/theming.md +++ b/docs/data/material/customization/theming/theming.md @@ -10,7 +10,7 @@ To promote greater consistency between apps, light and dark theme types are avai ## Theme provider -Use `ThemeProvider` or [`CssVarsProvider`](#css-variables-provider) to inject a custom theme into your application. +Use `ThemeProvider` to inject a custom theme into your application. However, this is optional; Material UI components come with a default theme. `ThemeProvider` relies on the [context feature of React](https://react.dev/learn/passing-data-deeply-with-context) to pass the theme down to the components, so you need to make sure that `ThemeProvider` is a parent of the components you are trying to customize. @@ -145,6 +145,8 @@ All the components under the `ThemeProvider` will start using those CSS theme va + color: var(--mui-palette-primary-main); ``` +To learn more about this feature, see the [CSS theme variables guide](/material-ui/customization/css-theme-variables/overview/). + ## API ### `createTheme(options, ...args) => theme` From 6071865fcef66501e57fd32f447fe26eae375080 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Fri, 9 Aug 2024 11:48:07 +0700 Subject: [PATCH 70/82] add suppressHydrationWarning --- .../customization/css-theme-variables/configuration.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/data/material/customization/css-theme-variables/configuration.md b/docs/data/material/customization/css-theme-variables/configuration.md index 93a5fc81b21970..0c27a6bcf5f6f3 100644 --- a/docs/data/material/customization/css-theme-variables/configuration.md +++ b/docs/data/material/customization/css-theme-variables/configuration.md @@ -183,7 +183,7 @@ import InitColorSchemeScript from '@mui/material/InitColorSchemeScript'; export default function RootLayout({ children }) { return ( - + {/* must come before the
element */} @@ -194,6 +194,10 @@ export default function RootLayout({ children }) { } ``` +:::warning +If you do not add `suppressHydrationWarning` to your , you will get warnings `"Extra attributes from the server"` because the InitColorSchemeScript updates that element. +::: + ### Next.js Pages Router Add the following code to the custom [`pages/_document.js`](https://nextjs.org/docs/pages/building-your-application/routing/custom-document) file: From a490227a90afc72c9740fd58eb4851a1667c24dd Mon Sep 17 00:00:00 2001 From: Siriwat K Date: Fri, 9 Aug 2024 13:47:07 +0700 Subject: [PATCH 71/82] Update docs/data/material/customization/dark-mode/dark-mode.md Co-authored-by: Diego Andai Signed-off-by: Siriwat K --- docs/data/material/customization/dark-mode/dark-mode.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/data/material/customization/dark-mode/dark-mode.md b/docs/data/material/customization/dark-mode/dark-mode.md index c48788e8e6b1f9..3854de69efbb6a 100644 --- a/docs/data/material/customization/dark-mode/dark-mode.md +++ b/docs/data/material/customization/dark-mode/dark-mode.md @@ -56,6 +56,7 @@ For a comprehensive understanding of the palette structure, refer to the [palett ## System preference Users might have a preference for light or dark mode that they've set through their operating system—either systemwide, or for a single user agent. +The following sections explain how to enable it. ### Built-in support From 6780db5453a82efe96e7dcf4c8f186d2e406084f Mon Sep 17 00:00:00 2001 From: Siriwat K Date: Mon, 12 Aug 2024 13:13:12 +0700 Subject: [PATCH 72/82] Apply suggestions from code review Co-authored-by: Sycamore <71297412+samuelsycamore@users.noreply.github.com> Signed-off-by: Siriwat K --- .../DarkThemeCssVariables.tsx | 2 +- .../css-theme-variables/configuration.md | 9 ++--- .../css-theme-variables/usage.md | 22 ++++++------ .../customization/dark-mode/dark-mode.md | 36 ++++++++++--------- .../material/customization/palette/palette.md | 6 ++-- .../material/customization/theming/theming.md | 4 +-- .../migrating-to-v6/migrating-to-v6.md | 5 +-- 7 files changed, 45 insertions(+), 39 deletions(-) diff --git a/docs/data/material/customization/css-theme-variables/DarkThemeCssVariables.tsx b/docs/data/material/customization/css-theme-variables/DarkThemeCssVariables.tsx index 797cd776d7e953..7279f3ad0ebb8d 100644 --- a/docs/data/material/customization/css-theme-variables/DarkThemeCssVariables.tsx +++ b/docs/data/material/customization/css-theme-variables/DarkThemeCssVariables.tsx @@ -27,7 +27,7 @@ export default function DarkThemeCssVariables() { severity="info" sx={{ p: 2, width: 'fit-content', mx: 'auto' }} > - You are seeing me in dark palette. + This is the dark palette. diff --git a/docs/data/material/customization/css-theme-variables/configuration.md b/docs/data/material/customization/css-theme-variables/configuration.md index 0c27a6bcf5f6f3..b15ab96ed8ecfb 100644 --- a/docs/data/material/customization/css-theme-variables/configuration.md +++ b/docs/data/material/customization/css-theme-variables/configuration.md @@ -99,7 +99,7 @@ function ModeSwitcher() { ``` :::success -After React hydrates the tree, the mode will be `system` to follow the user's preference. +After React hydrates the tree, the mode is set to `system` to follow the user's preference. ::: ### Determining the system mode @@ -195,7 +195,7 @@ export default function RootLayout({ children }) { ``` :::warning -If you do not add `suppressHydrationWarning` to your , you will get warnings `"Extra attributes from the server"` because the InitColorSchemeScript updates that element. +If you don't add `suppressHydrationWarning` to your `` tag, you will see warnings about `"Extra attributes from the server"` because `InitColorSchemeScript` updates that element. ::: ### Next.js Pages Router @@ -272,7 +272,8 @@ In the example below, all the components inside the `div` will always be dark: ## Disabling CSS color scheme -By default, `createTheme` attaches [CSS color-scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme) based on the palette mode. If you want to disable it, use `disableCssColorScheme`: +By default, `createTheme` attaches a [CSS `color-scheme` property](https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme) based on the palette mode. +You can disable this by setting `disableCssColorScheme` to `true`: ```js createTheme({ @@ -294,7 +295,7 @@ The generated CSS will not include the `color-scheme` property: ## Instant transition between color schemes -To disable CSS transition when switching between modes, use `disableTransitionOnChange` prop: +To disable CSS transitions when switching between modes, apply the `disableTransitionOnChange` prop: ```js diff --git a/docs/data/material/customization/css-theme-variables/usage.md b/docs/data/material/customization/css-theme-variables/usage.md index 419c15c57fb285..25128899798c74 100644 --- a/docs/data/material/customization/css-theme-variables/usage.md +++ b/docs/data/material/customization/css-theme-variables/usage.md @@ -39,7 +39,7 @@ If you're using the experimental `CssVarsProvider` API, replace it with `ThemePr ## Dark mode only variables -To switch the default light to dark palette, set `palette: { mode: 'dark' }` to the `createTheme`. +To switch to the dark palette from the default light, set `palette: { mode: 'dark' }` in the `createTheme` function. Material UI will generate the dark palette instead. {{"demo": "DarkThemeCssVariables.js"}} @@ -47,7 +47,7 @@ Material UI will generate the dark palette instead. ## Light and dark modes To enable both light and dark modes, add `colorSchemes: { dark: true }` to `createTheme`. -This generates light (default) and dark palettes using `@media (prefers-color-scheme)` as a default method. +This generates both palettes and defaults to `@media (prefers-color-scheme)`. @@ -60,7 +60,7 @@ const theme = createTheme({ }); function App() { - return {/* ...you app */}; + return {/* ...your app */}; } ``` @@ -83,12 +83,12 @@ function App() { :::info -You can explicitly set `colorSchemes: { light: true, dark: true }` which will produce the same result as the snippet above because light is the default color scheme. +It's also possible to set `colorSchemes: { light: true, dark: true }`, which produces the same result as the snippet above because light is the default color scheme. ::: -The CSS media `prefers-color-scheme` method works with server-side rendering without extra configuration but you will not be able to toggle between the modes because the styles is based on the browser media. +The CSS media `prefers-color-scheme` method works with server-side rendering without extra configuration, but users won't be able to toggle between modes because the styles are based on the browser media. -If you want to manually toggle the modes, check out the [Toggling dark mode manually](/material-ui/customization/css-theme-variables/configuration/#toggling-dark-mode-manually) guide. +If you want to be able to manually toggle modes, see the guide to [toggling dark mode manually](/material-ui/customization/css-theme-variables/configuration/#toggling-dark-mode-manually). ## Applying dark styles @@ -111,7 +111,7 @@ import Card from '@mui/material/Card'; ``` :::warning -**Don't** use `theme.palette.mode` to switch between light and dark styles because it will produce a [flickering effect](/material-ui/customization/dark-mode/#dark-mode-flicker). +Do not use `theme.palette.mode` to switch between light and dark styles—this produces an [unwanted flickering effect](/material-ui/customization/dark-mode/#dark-mode-flicker). ```js ` inside of the `` component will also ena Setting the dark mode this way only works if you are using [the default palette](/material-ui/customization/default-theme/). If you have a custom palette, make sure that you have the correct values based on the `mode`. The next section explains how to do this. ::: -### Overriding dark palette +### Overriding the dark palette To override the default palette, provide a [palette object](/material-ui/customization/palette/#default-colors) with custom colors in hex, RGB, or HSL format: @@ -51,16 +51,16 @@ const darkTheme = createTheme({ }); ``` -For a comprehensive understanding of the palette structure, refer to the [palette page](/material-ui/customization/palette/). +Learn more about palette structure in the [Palette documentation](/material-ui/customization/palette/). ## System preference -Users might have a preference for light or dark mode that they've set through their operating system—either systemwide, or for a single user agent. -The following sections explain how to enable it. +Some users sets a preference for light or dark mode through their operation system—either systemwide, or for individual user agents. +The following sections explain how to apply these preferences to an app's theme. ### Built-in support -To build an application with multiple color schemes, use `colorSchemes` node. +Use the `colorSchemes` node to build an application with multiple color schemes. The built-in color schemes are `light` and `dark` which can be enabled by setting the value to `true`. The light color scheme is enabled by default, so you only need to set the dark color scheme: @@ -82,8 +82,8 @@ function App() { When `colorSchemes` is provided, the following features are activated: - Automatic switching between light and dark color schemes based on the user's preference. -- Synchronize between window tabs. If the user changes the color scheme in one tab, the other tabs will also update. -- An option to [disable transitions](#disable-transitions) when the color scheme changes. +- Synchronization between window tabs—changes to the color scheme in one tab are applied to all other tabs +- An option to [disable transitions](#disable-transitions) when the color scheme changes :::success To test the system preference feature, follow the guide on [emulating the CSS media feature `prefers-color-scheme`](https://developer.chrome.com/docs/devtools/rendering/emulate-css#emulate_css_media_feature_prefers-color-scheme). @@ -91,7 +91,7 @@ To test the system preference feature, follow the guide on [emulating the CSS me ### Manual implementation -You can make use of this preference with the [useMediaQuery](/material-ui/react-use-media-query/) hook and the [prefers-color-scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) media query. +You can make use of this preference with the [`useMediaQuery`](/material-ui/react-use-media-query/) hook and the [`prefers-color-scheme`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) media query. The following demo shows how to enable dark mode automatically by checking for the user's preference in their OS or browser settings: @@ -125,7 +125,7 @@ function App() { ## Toggling color mode -To give your users a way to toggle between modes, use `useColorScheme` hook to read and update the mode. +To give your users a way to toggle between modes, use the `useColorScheme` hook to read and update the mode. :::info `mode` is always `undefined` on the first render, so make sure to handle this case. @@ -135,7 +135,7 @@ To give your users a way to toggle between modes, use `useColorScheme` hook to r ## Disable transitions -To instantly switch between color schemes, you can disable transitions by setting `disableTransitionOnChange` prop on the `ThemeProvider` component: +To instantly switch between color schemes with no transition, apply the `disableTransitionOnChange` prop to the `ThemeProvider` component: ```jsx @@ -231,29 +231,31 @@ Apply styles for a specific mode. ### The problem -Server-rendered apps are built before they reach the user's device. This means they can't automatically adjust to the user's preferred color scheme when first loaded. +Server-rendered apps are built before they reach the user's device. +This means they can't automatically adjust to the user's preferred color scheme when first loaded. Here's what typically happens: 1. You load the app and set it to dark mode. 2. You refresh the page. -3. The app briefly shows in light mode (the default). +3. The app briefly appears in light mode (the default). 4. Then it switches back to dark mode once the app fully loads. This "flash" of light mode happens every time you open the app, as long as your browser remembers your dark mode preference. -This sudden change can be jarring, especially in low-light environments. It can strain your eyes and disrupt your experience, particularly if you interact with the app during this transition. +This sudden change can be jarring, especially in low-light environments. +It can strain your eyes and disrupt your experience, particularly if you interact with the app during this transition. -To better understand this issue, take a look at the GIF below: +To better understand this issue, take a look at the animated image below: An example video that shows a page that initially loads correctly in dark mode but quickly flickers to light mode. ### The solution: CSS variables -Solving this problem required us to take a novel approach to styling and theming. +Solving this problem requires a novel approach to styling and theming. (See this [RFC on CSS variables support](https://github.com/mui/material-ui/issues/27651) to learn more about the implementation of this feature.) -For applications that want to support light and dark mode using CSS media `prefers-color-scheme`, enabling the [CSS variables feature](/material-ui/customization/css-theme-variables/usage/#light-and-dark-modes) will fix the issue. +For applications that need to support light and dark mode using CSS media `prefers-color-scheme`, enabling the [CSS variables feature](/material-ui/customization/css-theme-variables/usage/#light-and-dark-modes) fixes the issue. -However, if you want to toggle between modes manually, it requires a combination of CSS variables and the `InitColorSchemeScript` component to avoid the flicker. +But if you want to be able to toggle between modes manually, avoiding the flicker requires a combination of CSS variables and the `InitColorSchemeScript` component. Check out the [Preventing SSR flicker](/material-ui/customization/css-theme-variables/configuration/#preventing-ssr-flickering) section for more details. diff --git a/docs/data/material/customization/palette/palette.md b/docs/data/material/customization/palette/palette.md index 0e6fbbedac6ea4..75adeb229a7d9f 100644 --- a/docs/data/material/customization/palette/palette.md +++ b/docs/data/material/customization/palette/palette.md @@ -313,7 +313,7 @@ Need inspiration? The Material Design team has built an [palette configuration t ## Color schemes To add both built-in light and dark color schemes, use the `colorSchemes: { light: true, dark: true }`. -It will generate the default tokens for both color schemes: +This generates the default tokens for both color schemes: ```js import { createTheme } from '@mui/material/styles'; @@ -326,7 +326,7 @@ const theme = createTheme({ }); ``` -If you want to override the default tokens for each color scheme, use the same [palette object](#customization) as shown below: +To override the default tokens for each color scheme, use the same [palette object](#customization) as shown below: ```js const theme = createTheme({ @@ -352,7 +352,7 @@ const theme = createTheme({ ``` :::warning -If you provide both `colorSchemes` and `palette`, the `palette` will override the palette defined in color schemes. +If you provide both `colorSchemes` and `palette`, the latter will override any styles defined in the former. ```js const theme = createTheme({ diff --git a/docs/data/material/customization/theming/theming.md b/docs/data/material/customization/theming/theming.md index ad6b0f9eb0aa61..866cc70cb8e71d 100644 --- a/docs/data/material/customization/theming/theming.md +++ b/docs/data/material/customization/theming/theming.md @@ -129,7 +129,7 @@ function App() { } ``` -This will generate a global stylesheet with the CSS theme variables: +This generates a global stylesheet with the CSS theme variables: ```css :root { @@ -138,7 +138,7 @@ This will generate a global stylesheet with the CSS theme variables: } ``` -All the components under the `ThemeProvider` will start using those CSS theme variables instead of raw values. +All components under the `ThemeProvider` will use those CSS theme variables instead of raw values. ```diff title="Button styles" - color: #1976d2; diff --git a/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md b/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md index 420789f3bb79b1..e1e99037cc0685 100644 --- a/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md +++ b/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md @@ -350,7 +350,7 @@ The following deprecated types were removed: ### Merged CssVarsProvider into ThemeProvider The `CssVarsProvider` and `extendTheme` has been merged into `ThemeProvider` and `createTheme`. -If you are using them in v5 or v6-beta, you should migrate as shown below: +If you are using them in v5 or v6-beta, you must migrate as shown below: ```diff -import { experimental_extendTheme as extendTheme, Experimental_CssVarsProvider as CssVarsProvider } from '@mui/material/styles'; @@ -376,7 +376,8 @@ It's designed to replace `theme.palette.mode` when applying light or dark styles })) ``` -Staring from v6, this is an official way to apply styles based on the color mode. We recommend migrating to this method to smoothly adopt new features and improvements in the next major updates. +Starting from v6, this is the official way to apply styles based on the color mode. +We highly recommend migrating to this method in order to keep up with new features and improvements in future major versions. Use these codemods to migrate your project to `theme.applyStyles`: From 10e9ba2a3049dcaa2bc45a84241671ef5095444e Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Mon, 12 Aug 2024 13:31:12 +0700 Subject: [PATCH 73/82] update docs --- .../DarkThemeCssVariables.js | 35 ------------ .../DarkThemeCssVariables.tsx | 35 ------------ .../css-theme-variables/usage.md | 53 ++----------------- .../customization/dark-mode/dark-mode.md | 8 +-- 4 files changed, 8 insertions(+), 123 deletions(-) delete mode 100644 docs/data/material/customization/css-theme-variables/DarkThemeCssVariables.js delete mode 100644 docs/data/material/customization/css-theme-variables/DarkThemeCssVariables.tsx diff --git a/docs/data/material/customization/css-theme-variables/DarkThemeCssVariables.js b/docs/data/material/customization/css-theme-variables/DarkThemeCssVariables.js deleted file mode 100644 index 797cd776d7e953..00000000000000 --- a/docs/data/material/customization/css-theme-variables/DarkThemeCssVariables.js +++ /dev/null @@ -1,35 +0,0 @@ -import * as React from 'react'; -import { createTheme, ThemeProvider } from '@mui/material/styles'; -import Box from '@mui/material/Box'; -import Alert from '@mui/material/Alert'; -import Typography from '@mui/material/Typography'; - -const theme = createTheme({ - cssVariables: true, - palette: { - mode: 'dark', - }, -}); - -export default function DarkThemeCssVariables() { - return ( - - - - You are seeing me in dark palette. - - - - ); -} diff --git a/docs/data/material/customization/css-theme-variables/DarkThemeCssVariables.tsx b/docs/data/material/customization/css-theme-variables/DarkThemeCssVariables.tsx deleted file mode 100644 index 7279f3ad0ebb8d..00000000000000 --- a/docs/data/material/customization/css-theme-variables/DarkThemeCssVariables.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import * as React from 'react'; -import { createTheme, ThemeProvider } from '@mui/material/styles'; -import Box from '@mui/material/Box'; -import Alert from '@mui/material/Alert'; -import Typography from '@mui/material/Typography'; - -const theme = createTheme({ - cssVariables: true, - palette: { - mode: 'dark', - }, -}); - -export default function DarkThemeCssVariables() { - return ( - - - - This is the dark palette. - - - - ); -} diff --git a/docs/data/material/customization/css-theme-variables/usage.md b/docs/data/material/customization/css-theme-variables/usage.md index 25128899798c74..38af27ee15c5ed 100644 --- a/docs/data/material/customization/css-theme-variables/usage.md +++ b/docs/data/material/customization/css-theme-variables/usage.md @@ -37,56 +37,11 @@ function App() { If you're using the experimental `CssVarsProvider` API, replace it with `ThemeProvider`. ::: -## Dark mode only variables - -To switch to the dark palette from the default light, set `palette: { mode: 'dark' }` in the `createTheme` function. -Material UI will generate the dark palette instead. - -{{"demo": "DarkThemeCssVariables.js"}} - ## Light and dark modes -To enable both light and dark modes, add `colorSchemes: { dark: true }` to `createTheme`. -This generates both palettes and defaults to `@media (prefers-color-scheme)`. - - - -```jsx JSX -import { ThemeProvider, createTheme } from '@mui/material/styles'; - -const theme = createTheme({ - cssVariables: true, - colorSchemes: { dark: true }, -}); - -function App() { - return {/* ...your app */}; -} -``` - -```css CSS -/* generated global stylesheet */ - -:root { - --mui-palette-primary-main: #1976d2; - /* ...other variables */ -} - -@media (prefers-color-scheme: dark) { - :root { - --mui-palette-primary-main: #90caf9; - /* ...other variables */ - } -} -``` - - - -:::info -It's also possible to set `colorSchemes: { light: true, dark: true }`, which produces the same result as the snippet above because light is the default color scheme. -::: +When the [built-in dark color scheme](/material-ui/customization/dark-mode/#built-in-support) and `cssVariables` are enabled, both light and dark CSS variables are generated with the default CSS media `prefers-color-scheme` method. -The CSS media `prefers-color-scheme` method works with server-side rendering without extra configuration, but users won't be able to toggle between modes because the styles are based on the browser media. +This method works with server-side rendering without extra configuration. However, users won't be able to toggle between modes because the styles are based on the browser media. If you want to be able to manually toggle modes, see the guide to [toggling dark mode manually](/material-ui/customization/css-theme-variables/configuration/#toggling-dark-mode-manually). @@ -126,7 +81,7 @@ Do not use `theme.palette.mode` to switch between light and dark styles—this p ## Using theme variables -When the CSS variables feature is enabled, the `vars` node is added to the theme. +When the CSS variables feature is enabled, the `vars` node is added to the theme. This `vars` object mirrors the structure of a serializable theme, with each value corresponding to a CSS variable. - `theme.vars` (recommended): an object that refers to the CSS theme variables. @@ -161,7 +116,7 @@ This `vars` object mirrors the structure of a serializable theme, with each valu ## Color channel tokens -Enabling `cssVariables` automatically generates channel tokens, which are used to create translucent colors. +Enabling `cssVariables` automatically generates channel tokens, which are used to create translucent colors. These tokens consist of color space channels without the alpha component, separated by spaces. The colors are suffixed with `Channel`—for example: diff --git a/docs/data/material/customization/dark-mode/dark-mode.md b/docs/data/material/customization/dark-mode/dark-mode.md index 5bd6857a446ae0..1ec2010b98f490 100644 --- a/docs/data/material/customization/dark-mode/dark-mode.md +++ b/docs/data/material/customization/dark-mode/dark-mode.md @@ -125,10 +125,10 @@ function App() { ## Toggling color mode -To give your users a way to toggle between modes, use the `useColorScheme` hook to read and update the mode. +To give your users a way to toggle between modes for [built-in support](#built-in-support), use the `useColorScheme` hook to read and update the mode. :::info -`mode` is always `undefined` on the first render, so make sure to handle this case. +`mode` is always `undefined` on the first render, so make sure to handle this case. Otherwise, you might see a hydration mismatch error. ::: {{"demo": "ToggleColorMode.js", "defaultCodeOpen": false}} @@ -231,7 +231,7 @@ Apply styles for a specific mode. ### The problem -Server-rendered apps are built before they reach the user's device. +Server-rendered apps are built before they reach the user's device. This means they can't automatically adjust to the user's preferred color scheme when first loaded. Here's what typically happens: @@ -243,7 +243,7 @@ Here's what typically happens: This "flash" of light mode happens every time you open the app, as long as your browser remembers your dark mode preference. -This sudden change can be jarring, especially in low-light environments. +This sudden change can be jarring, especially in low-light environments. It can strain your eyes and disrupt your experience, particularly if you interact with the app during this transition. To better understand this issue, take a look at the animated image below: From e7f173d3a23012103f763e29459004c99501504f Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Mon, 12 Aug 2024 13:31:28 +0700 Subject: [PATCH 74/82] prettier --- .../material/customization/css-theme-variables/configuration.md | 2 +- docs/data/material/migration/migrating-to-v6/migrating-to-v6.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/data/material/customization/css-theme-variables/configuration.md b/docs/data/material/customization/css-theme-variables/configuration.md index b15ab96ed8ecfb..e1cf82d49d2c82 100644 --- a/docs/data/material/customization/css-theme-variables/configuration.md +++ b/docs/data/material/customization/css-theme-variables/configuration.md @@ -272,7 +272,7 @@ In the example below, all the components inside the `div` will always be dark: ## Disabling CSS color scheme -By default, `createTheme` attaches a [CSS `color-scheme` property](https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme) based on the palette mode. +By default, `createTheme` attaches a [CSS `color-scheme` property](https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme) based on the palette mode. You can disable this by setting `disableCssColorScheme` to `true`: ```js diff --git a/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md b/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md index e1e99037cc0685..6bb63ed4e38eb3 100644 --- a/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md +++ b/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md @@ -376,7 +376,7 @@ It's designed to replace `theme.palette.mode` when applying light or dark styles })) ``` -Starting from v6, this is the official way to apply styles based on the color mode. +Starting from v6, this is the official way to apply styles based on the color mode. We highly recommend migrating to this method in order to keep up with new features and improvements in future major versions. Use these codemods to migrate your project to `theme.applyStyles`: From df26e306ebbe111a01837b62d7219ebced5b449b Mon Sep 17 00:00:00 2001 From: Siriwat K Date: Wed, 14 Aug 2024 21:02:06 +0700 Subject: [PATCH 75/82] Apply suggestions from code review Co-authored-by: Diego Andai Co-authored-by: Flavien DELANGLE Signed-off-by: Siriwat K --- .../material/customization/css-theme-variables/usage.md | 1 + docs/data/material/customization/dark-mode/dark-mode.md | 6 ++++++ docs/data/material/customization/palette/palette.md | 3 ++- docs/data/material/customization/theming/theming.md | 3 ++- .../material/migration/migrating-to-v6/migrating-to-v6.md | 2 +- packages/mui-material/src/styles/ThemeProviderWithVars.tsx | 4 ++-- 6 files changed, 14 insertions(+), 5 deletions(-) diff --git a/docs/data/material/customization/css-theme-variables/usage.md b/docs/data/material/customization/css-theme-variables/usage.md index 38af27ee15c5ed..7bc6d77730fea9 100644 --- a/docs/data/material/customization/css-theme-variables/usage.md +++ b/docs/data/material/customization/css-theme-variables/usage.md @@ -35,6 +35,7 @@ function App() { :::info If you're using the experimental `CssVarsProvider` API, replace it with `ThemeProvider`. +All the features that were included in `CssVarsProvider` are now available in `ThemeProvider`. ::: ## Light and dark modes diff --git a/docs/data/material/customization/dark-mode/dark-mode.md b/docs/data/material/customization/dark-mode/dark-mode.md index 1ec2010b98f490..f33699ea8534a2 100644 --- a/docs/data/material/customization/dark-mode/dark-mode.md +++ b/docs/data/material/customization/dark-mode/dark-mode.md @@ -85,6 +85,12 @@ When `colorSchemes` is provided, the following features are activated: - Synchronization between window tabs—changes to the color scheme in one tab are applied to all other tabs - An option to [disable transitions](#disable-transitions) when the color scheme changes +:::info +The `colorSchemes` API is an enhanced version of the previous `palette` API. +We encourage you to use it as it enables the features mentioned above. +If both `colorSchemes` and `palette` are provided, `palette` will take precedence. +::: + :::success To test the system preference feature, follow the guide on [emulating the CSS media feature `prefers-color-scheme`](https://developer.chrome.com/docs/devtools/rendering/emulate-css#emulate_css_media_feature_prefers-color-scheme). ::: diff --git a/docs/data/material/customization/palette/palette.md b/docs/data/material/customization/palette/palette.md index 75adeb229a7d9f..66cd64b535df59 100644 --- a/docs/data/material/customization/palette/palette.md +++ b/docs/data/material/customization/palette/palette.md @@ -312,7 +312,7 @@ Need inspiration? The Material Design team has built an [palette configuration t ## Color schemes -To add both built-in light and dark color schemes, use the `colorSchemes: { light: true, dark: true }`. +To add both built-in light and dark color schemes without creating separate themes, use the `colorSchemes: { light: true, dark: true }`. This generates the default tokens for both color schemes: ```js @@ -352,6 +352,7 @@ const theme = createTheme({ ``` :::warning +The `colorSchemes` API is an enhanced version of the `palette` API. If you provide both `colorSchemes` and `palette`, the latter will override any styles defined in the former. ```js diff --git a/docs/data/material/customization/theming/theming.md b/docs/data/material/customization/theming/theming.md index 866cc70cb8e71d..a0d245e3d469ac 100644 --- a/docs/data/material/customization/theming/theming.md +++ b/docs/data/material/customization/theming/theming.md @@ -10,7 +10,8 @@ To promote greater consistency between apps, light and dark theme types are avai ## Theme provider -Use `ThemeProvider` to inject a custom theme into your application. +Use `ThemeProvider` if you want to use a custom theme in your application. +If this provider is not used, Material UI components will use the library's default theme. However, this is optional; Material UI components come with a default theme. `ThemeProvider` relies on the [context feature of React](https://react.dev/learn/passing-data-deeply-with-context) to pass the theme down to the components, so you need to make sure that `ThemeProvider` is a parent of the components you are trying to customize. diff --git a/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md b/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md index 6bb63ed4e38eb3..aa8bb7409757da 100644 --- a/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md +++ b/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md @@ -349,7 +349,7 @@ The following deprecated types were removed: ### Merged CssVarsProvider into ThemeProvider -The `CssVarsProvider` and `extendTheme` has been merged into `ThemeProvider` and `createTheme`. +The `CssVarsProvider` and `extendTheme` features have been ported into `ThemeProvider` and `createTheme`. If you are using them in v5 or v6-beta, you must migrate as shown below: ```diff diff --git a/packages/mui-material/src/styles/ThemeProviderWithVars.tsx b/packages/mui-material/src/styles/ThemeProviderWithVars.tsx index 6595b805926374..1a29b504f0afbf 100644 --- a/packages/mui-material/src/styles/ThemeProviderWithVars.tsx +++ b/packages/mui-material/src/styles/ThemeProviderWithVars.tsx @@ -44,7 +44,7 @@ function Experimental_CssVarsProvider(props: any) { if (!warnedOnce) { console.warn( [ - 'MUI: The Experimental_CssVarsProvider component has been merged to ThemeProvider.', + 'MUI: The Experimental_CssVarsProvider component has been ported into ThemeProvider.', '', "You should use `import { ThemeProvider } from '@mui/material/styles'` instead.", 'For more details, check out https://mui.com/material-ui/customization/css-theme-variables/usage/', @@ -79,7 +79,7 @@ const getInitColorSchemeScript: typeof deprecatedGetInitColorSchemeScript = (par /** * TODO: remove this export in v7 * @deprecated - * The `CssVarsProvider` component has been deprecated and merged to `ThemeProvider`. + * The `CssVarsProvider` component has been deprecated and ported into `ThemeProvider`. * * You should use `ThemeProvider` and `createTheme` instead: * From 830909e542d460e0dd1edde7fdb36c0f92d588a1 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 14 Aug 2024 21:03:58 +0700 Subject: [PATCH 76/82] remove duplicated --- docs/data/material/customization/theming/theming.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/data/material/customization/theming/theming.md b/docs/data/material/customization/theming/theming.md index a0d245e3d469ac..fef76aa2004c24 100644 --- a/docs/data/material/customization/theming/theming.md +++ b/docs/data/material/customization/theming/theming.md @@ -12,7 +12,6 @@ To promote greater consistency between apps, light and dark theme types are avai Use `ThemeProvider` if you want to use a custom theme in your application. If this provider is not used, Material UI components will use the library's default theme. -However, this is optional; Material UI components come with a default theme. `ThemeProvider` relies on the [context feature of React](https://react.dev/learn/passing-data-deeply-with-context) to pass the theme down to the components, so you need to make sure that `ThemeProvider` is a parent of the components you are trying to customize. You can learn more about this in [the API section](#themeprovider). From 4b9bfe502bfcd0c00e0b726a4a6abf6e2d1c540b Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 14 Aug 2024 21:10:21 +0700 Subject: [PATCH 77/82] update media prefers-color-scheme section --- .../customization/dark-mode/dark-mode.md | 22 +++---------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/docs/data/material/customization/dark-mode/dark-mode.md b/docs/data/material/customization/dark-mode/dark-mode.md index f33699ea8534a2..0e1c843474e262 100644 --- a/docs/data/material/customization/dark-mode/dark-mode.md +++ b/docs/data/material/customization/dark-mode/dark-mode.md @@ -95,11 +95,11 @@ If both `colorSchemes` and `palette` are provided, `palette` will take precedenc To test the system preference feature, follow the guide on [emulating the CSS media feature `prefers-color-scheme`](https://developer.chrome.com/docs/devtools/rendering/emulate-css#emulate_css_media_feature_prefers-color-scheme). ::: -### Manual implementation +### Accessing media prefers-color-scheme You can make use of this preference with the [`useMediaQuery`](/material-ui/react-use-media-query/) hook and the [`prefers-color-scheme`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) media query. -The following demo shows how to enable dark mode automatically by checking for the user's preference in their OS or browser settings: +The following demo shows how to check the user's preference in their OS or browser settings: ```jsx import * as React from 'react'; @@ -109,23 +109,7 @@ import CssBaseline from '@mui/material/CssBaseline'; function App() { const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)'); - - const theme = React.useMemo( - () => - createTheme({ - palette: { - mode: prefersDarkMode ? 'dark' : 'light', - }, - }), - [prefersDarkMode], - ); - - return ( - - - - - ); + return
prefersDarkMode: {prefersDarkMode.toString()}
; } ``` From c20365bf2ff4674022c9bff07d4125af13335e9a Mon Sep 17 00:00:00 2001 From: DiegoAndai Date: Wed, 14 Aug 2024 14:33:47 -0400 Subject: [PATCH 78/82] Use ThemeProvider in guide --- .../migrating-to-v6/migrating-to-v6.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md b/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md index aa8bb7409757da..8950b00a16e32a 100644 --- a/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md +++ b/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md @@ -354,7 +354,24 @@ If you are using them in v5 or v6-beta, you must migrate as shown below: ```diff -import { experimental_extendTheme as extendTheme, Experimental_CssVarsProvider as CssVarsProvider } from '@mui/material/styles'; -+import { extendTheme, CssVarsProvider } from '@mui/material/styles'; ++import { createTheme, ThemeProvider } from '@mui/material/styles'; + +-const theme = extendTheme( ++const theme = createTheme( + { ++ cssVariables: true, + // the rest of your theme + } + ); + + function App() { + return +- ++ + {/* ...you app */} +- ++ ; + } ``` Check out the [CSS theme variables page](/material-ui/customization/css-theme-variables/overview/) to learn more about it. From ab432e18219522c90d264afd57789272cb143988 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Fri, 16 Aug 2024 11:47:27 +0700 Subject: [PATCH 79/82] update redirect and fix hash --- docs/data/material/customization/css-theme-variables/usage.md | 2 +- docs/public/_redirects | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/data/material/customization/css-theme-variables/usage.md b/docs/data/material/customization/css-theme-variables/usage.md index 7bc6d77730fea9..32ae3172d1347d 100644 --- a/docs/data/material/customization/css-theme-variables/usage.md +++ b/docs/data/material/customization/css-theme-variables/usage.md @@ -219,7 +219,7 @@ Or use `var()` to refer to the CSS variable directly: ``` :::warning -If you're using a [custom prefix](/material-ui/customization/css-theme-variables/configuration/#changing-variable-prefixes), make sure to replace the default `--mui`. +If you're using a [custom prefix](/material-ui/customization/css-theme-variables/configuration/#customizing-variable-prefix), make sure to replace the default `--mui`. ::: For **TypeScript**, you need to augment the [palette interfaces](#palette-interfaces). diff --git a/docs/public/_redirects b/docs/public/_redirects index e35dd899666fa9..9e247268edd496 100644 --- a/docs/public/_redirects +++ b/docs/public/_redirects @@ -508,6 +508,7 @@ https://v4.material-ui.com/* https://v4.mui.com/:splat 301! /material-ui/guides/right-to-left/ /material-ui/customization/right-to-left/ 301 /material-ui/guides/pickers-migration/ /material-ui/migration/pickers-migration/ 301 /material-ui/guides/styled-components/ /material-ui/integrations/styled-components/ 301 +/material-ui/experimental-api/css-theme-variables/migration/ /material-ui/migration/upgrade-to-v6/#cssvarsprovider-and-extendtheme 301 /material-ui/experimental-api/css-theme-variables/overview/ /material-ui/customization/css-theme-variables/overview/ 301 /material-ui/experimental-api/css-theme-variables/usage/ /material-ui/customization/css-theme-variables/usage/ 301 /material-ui/experimental-api/css-theme-variables/customization/ /material-ui/customization/css-theme-variables/configuration/ 301 From 7f6c7b663976c0144a2325025f53e56f2b31925b Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Fri, 16 Aug 2024 13:54:01 +0700 Subject: [PATCH 80/82] fix link error --- docs/.link-check-errors.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/.link-check-errors.txt b/docs/.link-check-errors.txt index 7a96d1bc6f5222..24f1ff82c9158b 100644 --- a/docs/.link-check-errors.txt +++ b/docs/.link-check-errors.txt @@ -1,6 +1,5 @@ Broken links found by `pnpm docs:link-check` that exist: -- https://mui.com/material-ui/customization/css-theme-variables/configuration/#changing-variable-prefixes - https://mui.com/material-ui/customization/theme-components/#creating-new-component-variants - https://mui.com/material-ui/customization/theme-components/#overrides-based-on-props - https://mui.com/material-ui/react-grid2/#whats-changed From f08a601260e0955d595858c2e0dbb3518c3e12f5 Mon Sep 17 00:00:00 2001 From: Siriwat K Date: Tue, 20 Aug 2024 09:30:12 +0700 Subject: [PATCH 81/82] Apply suggestions from code review Co-authored-by: Sycamore <71297412+samuelsycamore@users.noreply.github.com> Signed-off-by: Siriwat K --- .../material/customization/css-theme-variables/usage.md | 4 ++-- docs/data/material/customization/dark-mode/dark-mode.md | 7 +++---- docs/data/material/customization/palette/palette.md | 2 +- docs/data/material/customization/theming/theming.md | 4 ++-- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/docs/data/material/customization/css-theme-variables/usage.md b/docs/data/material/customization/css-theme-variables/usage.md index 32ae3172d1347d..7aee4e3532f90a 100644 --- a/docs/data/material/customization/css-theme-variables/usage.md +++ b/docs/data/material/customization/css-theme-variables/usage.md @@ -35,7 +35,7 @@ function App() { :::info If you're using the experimental `CssVarsProvider` API, replace it with `ThemeProvider`. -All the features that were included in `CssVarsProvider` are now available in `ThemeProvider`. +All features that were previously available to the `CssVarsProvider` are now available with the `ThemeProvider`. ::: ## Light and dark modes @@ -117,7 +117,7 @@ This `vars` object mirrors the structure of a serializable theme, with each valu ## Color channel tokens -Enabling `cssVariables` automatically generates channel tokens, which are used to create translucent colors. +Enabling `cssVariables` automatically generates channel tokens which are used to create translucent colors. These tokens consist of color space channels without the alpha component, separated by spaces. The colors are suffixed with `Channel`—for example: diff --git a/docs/data/material/customization/dark-mode/dark-mode.md b/docs/data/material/customization/dark-mode/dark-mode.md index 0e1c843474e262..d1eda92da44f76 100644 --- a/docs/data/material/customization/dark-mode/dark-mode.md +++ b/docs/data/material/customization/dark-mode/dark-mode.md @@ -81,13 +81,12 @@ function App() { When `colorSchemes` is provided, the following features are activated: -- Automatic switching between light and dark color schemes based on the user's preference. +- Automatic switching between light and dark color schemes based on the user's preference - Synchronization between window tabs—changes to the color scheme in one tab are applied to all other tabs - An option to [disable transitions](#disable-transitions) when the color scheme changes :::info -The `colorSchemes` API is an enhanced version of the previous `palette` API. -We encourage you to use it as it enables the features mentioned above. +The `colorSchemes` API is an enhanced version of the earlier and more limited `palette` API—the aforementioned features are only accessible with the `colorSchemes` API, so we recommend using it over the `palette` API. If both `colorSchemes` and `palette` are provided, `palette` will take precedence. ::: @@ -118,7 +117,7 @@ function App() { To give your users a way to toggle between modes for [built-in support](#built-in-support), use the `useColorScheme` hook to read and update the mode. :::info -`mode` is always `undefined` on the first render, so make sure to handle this case. Otherwise, you might see a hydration mismatch error. +The `mode` is always `undefined` on first render, so make sure to handle this case as shown in the demo below—otherwise you may encounter a hydration mismatch error. ::: {{"demo": "ToggleColorMode.js", "defaultCodeOpen": false}} diff --git a/docs/data/material/customization/palette/palette.md b/docs/data/material/customization/palette/palette.md index 66cd64b535df59..36da0166b90e14 100644 --- a/docs/data/material/customization/palette/palette.md +++ b/docs/data/material/customization/palette/palette.md @@ -352,7 +352,7 @@ const theme = createTheme({ ``` :::warning -The `colorSchemes` API is an enhanced version of the `palette` API. +The `colorSchemes` API is an enhanced version of the `palette` API, and is the preferred API for this purpose starting from Material UI v6. If you provide both `colorSchemes` and `palette`, the latter will override any styles defined in the former. ```js diff --git a/docs/data/material/customization/theming/theming.md b/docs/data/material/customization/theming/theming.md index fef76aa2004c24..eec67eb40b9ee5 100644 --- a/docs/data/material/customization/theming/theming.md +++ b/docs/data/material/customization/theming/theming.md @@ -10,8 +10,8 @@ To promote greater consistency between apps, light and dark theme types are avai ## Theme provider -Use `ThemeProvider` if you want to use a custom theme in your application. -If this provider is not used, Material UI components will use the library's default theme. +Material UI components adhere to the library's default theme out of the box. +Use `ThemeProvider` to inject a custom theme into your application. `ThemeProvider` relies on the [context feature of React](https://react.dev/learn/passing-data-deeply-with-context) to pass the theme down to the components, so you need to make sure that `ThemeProvider` is a parent of the components you are trying to customize. You can learn more about this in [the API section](#themeprovider). From 185c758a6e347bf6b0371518a0cf2c561922a61c Mon Sep 17 00:00:00 2001 From: Siriwat K Date: Tue, 20 Aug 2024 09:46:23 +0700 Subject: [PATCH 82/82] Update docs/data/material/customization/theming/theming.md Signed-off-by: Siriwat K --- docs/data/material/customization/theming/theming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data/material/customization/theming/theming.md b/docs/data/material/customization/theming/theming.md index eec67eb40b9ee5..65fed60059f4be 100644 --- a/docs/data/material/customization/theming/theming.md +++ b/docs/data/material/customization/theming/theming.md @@ -10,7 +10,7 @@ To promote greater consistency between apps, light and dark theme types are avai ## Theme provider -Material UI components adhere to the library's default theme out of the box. +Material UI components adhere to the library's default theme out of the box. Use `ThemeProvider` to inject a custom theme into your application. `ThemeProvider` relies on the [context feature of React](https://react.dev/learn/passing-data-deeply-with-context) to pass the theme down to the components, so you need to make sure that `ThemeProvider` is a parent of the components you are trying to customize.