From cc346b67cea9787ddc448cde35748c89c0da6a29 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 17 Feb 2022 11:38:48 +0700 Subject: [PATCH 01/50] fix typings --- .../mui-joy/src/styles/CssVarsProvider.tsx | 18 ++------ .../mui-joy/src/styles/types/colorSystem.ts | 1 + .../cssVars/createCssVarsProvider.spec.tsx | 42 ++++++------------- 3 files changed, 18 insertions(+), 43 deletions(-) diff --git a/packages/mui-joy/src/styles/CssVarsProvider.tsx b/packages/mui-joy/src/styles/CssVarsProvider.tsx index 3e3f1e6a546291..f812d4aa107064 100644 --- a/packages/mui-joy/src/styles/CssVarsProvider.tsx +++ b/packages/mui-joy/src/styles/CssVarsProvider.tsx @@ -26,16 +26,6 @@ type Partial2Level = { : T[K]; }; -type Partial3Level = { - [K in keyof T]?: { - [J in keyof T[K]]?: T[K][J] extends Record - ? { - [P in keyof T[K][J]]?: T[K][J][P]; - } - : T[K][J]; - }; -}; - // Use Partial2Level instead of PartialDeep because nested value type is CSSObject which does not work with PartialDeep. type ThemeInput = Partial2Level< ThemeScales & { @@ -50,11 +40,11 @@ type ThemeInput = Partial2Level< }; type JoyThemeInput = ThemeInput & { - colorSchemes: Record>; + colorSchemes: Record>; }; type ApplicationThemeInput = ThemeInput & { - colorSchemes: Record>; + colorSchemes: Record>; }; const { palette, ...rest } = defaultTheme; @@ -68,8 +58,8 @@ const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssV theme: { ...rest, colorSchemes: { - light: lightColorSystem, - dark: darkColorSystem, + light: lightColorSystem as ColorSystem, + dark: darkColorSystem as ColorSystem, }, }, defaultColorScheme: { diff --git a/packages/mui-joy/src/styles/types/colorSystem.ts b/packages/mui-joy/src/styles/types/colorSystem.ts index 09709216f4cb53..01ae89c9a43a0c 100644 --- a/packages/mui-joy/src/styles/types/colorSystem.ts +++ b/packages/mui-joy/src/styles/types/colorSystem.ts @@ -15,6 +15,7 @@ export interface PaletteVariant { textActiveBg: string; // disabled state textDisabledColor: string; + textDisabledBg: string; outlinedColor: string; outlinedBorder: string; diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx b/packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx index 8fd5c6e769d22b..619d3f72831e73 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx @@ -122,6 +122,7 @@ createCssVarsProvider({ // ============================== // Test application layer +// 1. WITHOUT extending color scheme interface JoyColorSchemeOverrides {} @@ -149,11 +150,6 @@ interface ApplicationThemeInput { fontFamily: string; } -// Simulate color scheme extending, same as module augmentation in real application -interface JoyColorSchemeOverrides { - white: true; -} - const { CssVarsProvider } = createCssVarsProvider< JoyThemeInput, JoyColorScheme, @@ -187,8 +183,8 @@ function App() { return ( ); @@ -198,20 +194,11 @@ function App2() { return ( ); } @@ -225,9 +212,9 @@ type Joy2ExtendedColorScheme = OverridableStringUnion ); } From 2a3e286047b973e80cb0076c20cc8d1e936eea40 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 17 Feb 2022 11:42:01 +0700 Subject: [PATCH 02/50] add comment --- packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx b/packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx index 619d3f72831e73..5a67e4718be8d3 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx @@ -204,6 +204,8 @@ function App2() { } // ========================= +// 1. WITH extending color scheme +// When developers extend new color schemes, they have to specify those new color schemes in the theme. interface Joy2ColorSchemeOverrides {} From 3876b1960ff0738c9cc092e106354f46d8e0172e Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 17 Feb 2022 11:47:08 +0700 Subject: [PATCH 03/50] fix comment --- packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx b/packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx index 5a67e4718be8d3..33d474eb096c5f 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx @@ -183,6 +183,7 @@ function App() { return ( Date: Thu, 17 Feb 2022 11:50:59 +0700 Subject: [PATCH 04/50] move variants out --- packages/mui-joy/src/styles/CssVarsProvider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mui-joy/src/styles/CssVarsProvider.tsx b/packages/mui-joy/src/styles/CssVarsProvider.tsx index f812d4aa107064..be4ef9c4a6ecd8 100644 --- a/packages/mui-joy/src/styles/CssVarsProvider.tsx +++ b/packages/mui-joy/src/styles/CssVarsProvider.tsx @@ -31,9 +31,9 @@ type ThemeInput = Partial2Level< ThemeScales & { focus: Focus; typography: TypographySystem; - variants: Partial2Level; } > & { + variants?: Partial2Level; breakpoints?: BreakpointsOptions; spacing?: SpacingOptions; components?: Components; From 278b596c8206b37035a853be00c802ffc39efbf1 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 17 Feb 2022 13:57:41 +0700 Subject: [PATCH 05/50] change to interface --- .../mui-joy/src/styles/CssVarsProvider.tsx | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/packages/mui-joy/src/styles/CssVarsProvider.tsx b/packages/mui-joy/src/styles/CssVarsProvider.tsx index be4ef9c4a6ecd8..c43a8089b9a8bc 100644 --- a/packages/mui-joy/src/styles/CssVarsProvider.tsx +++ b/packages/mui-joy/src/styles/CssVarsProvider.tsx @@ -26,26 +26,35 @@ type Partial2Level = { : T[K]; }; +type Partial3Level = { + [K in keyof T]?: T[K] extends Record + ? { + [J in keyof T[K]]?: T[K][J] extends Record + ? { + [P in keyof T[K][J]]?: T[K][J][P]; + } + : T[K][J]; + } + : T[K]; +}; + // Use Partial2Level instead of PartialDeep because nested value type is CSSObject which does not work with PartialDeep. -type ThemeInput = Partial2Level< - ThemeScales & { - focus: Focus; - typography: TypographySystem; - } -> & { +interface ThemeInput extends Partial2Level { + focus?: Partial; + typography?: TypographySystem; variants?: Partial2Level; breakpoints?: BreakpointsOptions; spacing?: SpacingOptions; components?: Components; -}; +} -type JoyThemeInput = ThemeInput & { - colorSchemes: Record>; -}; +interface JoyThemeInput extends ThemeInput { + colorSchemes: Record>; +} -type ApplicationThemeInput = ThemeInput & { - colorSchemes: Record>; -}; +interface ApplicationThemeInput extends ThemeInput { + colorSchemes: Record>; +} const { palette, ...rest } = defaultTheme; From 948979244681255cf16aee53b52b7f96195e304e Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 17 Feb 2022 14:15:35 +0700 Subject: [PATCH 06/50] remove unused type --- packages/mui-system/src/cssVars/createCssVarsProvider.d.ts | 7 ------- packages/mui-system/src/cssVars/index.ts | 1 - 2 files changed, 8 deletions(-) diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts b/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts index 9a8b9dc8aac4b4..f5a5fd3173a187 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts @@ -2,13 +2,6 @@ import * as React from 'react'; import getInitColorSchemeScript from './getInitColorSchemeScript'; import { Mode, Result } from './useCurrentColorScheme'; -export type BuildCssVarsTheme = ThemeInput extends { - colorSchemes: Record; -} - ? Omit & - ColorSystems & { vars: Omit & ColorSystems } - : never; - /** * DesignSystemColorScheme: is what a design system provide by default. Mostly, `light` and `dark` * ApplicationColorScheme: is what developer can extend from a design system. Ex, `comfort` `trueDark` ...any name that they want diff --git a/packages/mui-system/src/cssVars/index.ts b/packages/mui-system/src/cssVars/index.ts index 5b509f609f7148..8e24f2897db82d 100644 --- a/packages/mui-system/src/cssVars/index.ts +++ b/packages/mui-system/src/cssVars/index.ts @@ -1,2 +1 @@ export { default } from './createCssVarsProvider'; -export type { BuildCssVarsTheme } from './createCssVarsProvider'; From c670070643d0549fcc5fffbae7a6449b0824ec51 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 17 Feb 2022 14:15:44 +0700 Subject: [PATCH 07/50] test theme types --- .../mui-joy/src/styles/CssVarsProvider.tsx | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/packages/mui-joy/src/styles/CssVarsProvider.tsx b/packages/mui-joy/src/styles/CssVarsProvider.tsx index c43a8089b9a8bc..82c7634550ac82 100644 --- a/packages/mui-joy/src/styles/CssVarsProvider.tsx +++ b/packages/mui-joy/src/styles/CssVarsProvider.tsx @@ -58,7 +58,11 @@ interface ApplicationThemeInput extends ThemeInput { const { palette, ...rest } = defaultTheme; -const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssVarsProvider< +const { + CssVarsProvider: SystemCssVarsProvider, + useColorScheme, + getInitColorSchemeScript, +} = createCssVarsProvider< JoyThemeInput, DefaultColorScheme, ApplicationThemeInput, @@ -114,4 +118,38 @@ const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssV keys[0] === 'breakpoints', }); +type DecideTheme< + DesignSystemTheme extends { colorSchemes: Record }, + DesignSystemColorScheme extends string, + ApplicationTheme extends { colorSchemes: Record }, + ApplicationColorScheme extends string | never, +> = [ApplicationColorScheme] extends [never] + ? { + theme?: Omit & { + colorSchemes?: Partial< + Record< + DesignSystemColorScheme, + DesignSystemTheme['colorSchemes'][DesignSystemColorScheme] + > + >; + }; + } + : { + theme: Omit & { + colorSchemes: Partial< + Record< + DesignSystemColorScheme, + DesignSystemTheme['colorSchemes'][DesignSystemColorScheme] + > + > & + Record; + }; + }; + +const CssVarsProvider = SystemCssVarsProvider as ( + props: React.PropsWithChildren< + DecideTheme + >, +) => React.ReactElement; + export { CssVarsProvider, useColorScheme, getInitColorSchemeScript }; From 79ffa208816d01cece385c84ca20dccda30a6698 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 17 Feb 2022 14:54:03 +0700 Subject: [PATCH 08/50] refactor types --- docs/pages/experiments/joy/variant.tsx | 16 +- .../mui-joy/src/styles/CssVarsProvider.tsx | 57 +--- .../src/cssVars/createCssVarsProvider.d.ts | 125 ++----- .../cssVars/createCssVarsProvider.spec.tsx | 309 ------------------ 4 files changed, 51 insertions(+), 456 deletions(-) delete mode 100644 packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx diff --git a/docs/pages/experiments/joy/variant.tsx b/docs/pages/experiments/joy/variant.tsx index 09568657c8c156..67ec054066af21 100644 --- a/docs/pages/experiments/joy/variant.tsx +++ b/docs/pages/experiments/joy/variant.tsx @@ -4,7 +4,7 @@ import { ThemeProvider, createTheme } from '@mui/material/styles'; import Box, { BoxProps } from '@mui/joy/Box'; import Button from '@mui/joy/Button'; import Typography from '@mui/joy/Typography'; -import { CssVarsProvider, ColorPaletteProp } from '@mui/joy/styles'; +import { CssVarsProvider, ColorPaletteProp, PaletteVariant } from '@mui/joy/styles'; import Info from '@mui/icons-material/Info'; import Code from '@mui/icons-material/Code'; import PlayArrow from '@mui/icons-material/PlayArrow'; @@ -19,6 +19,20 @@ declare module '@mui/joy/styles' { } interface Palette { + secondary: { + 700: string; + 600: string; + 500: string; + 200: string; + 100: string; + } & PaletteVariant; + alternate: { + 700: string; + 600: string; + 500: string; + 200: string; + 100: string; + } & PaletteVariant; outlinedFocusBorder: string; } diff --git a/packages/mui-joy/src/styles/CssVarsProvider.tsx b/packages/mui-joy/src/styles/CssVarsProvider.tsx index 82c7634550ac82..4320495dfd8b2d 100644 --- a/packages/mui-joy/src/styles/CssVarsProvider.tsx +++ b/packages/mui-joy/src/styles/CssVarsProvider.tsx @@ -39,34 +39,21 @@ type Partial3Level = { }; // Use Partial2Level instead of PartialDeep because nested value type is CSSObject which does not work with PartialDeep. -interface ThemeInput extends Partial2Level { +interface JoyThemeInput extends Partial2Level { focus?: Partial; typography?: TypographySystem; variants?: Partial2Level; breakpoints?: BreakpointsOptions; spacing?: SpacingOptions; components?: Components; -} - -interface JoyThemeInput extends ThemeInput { - colorSchemes: Record>; -} - -interface ApplicationThemeInput extends ThemeInput { - colorSchemes: Record>; + colorSchemes?: Partial>>; } const { palette, ...rest } = defaultTheme; -const { - CssVarsProvider: SystemCssVarsProvider, - useColorScheme, - getInitColorSchemeScript, -} = createCssVarsProvider< - JoyThemeInput, - DefaultColorScheme, - ApplicationThemeInput, - ExtendedColorScheme +const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssVarsProvider< + DefaultColorScheme | ExtendedColorScheme, + JoyThemeInput >({ theme: { ...rest, @@ -118,38 +105,4 @@ const { keys[0] === 'breakpoints', }); -type DecideTheme< - DesignSystemTheme extends { colorSchemes: Record }, - DesignSystemColorScheme extends string, - ApplicationTheme extends { colorSchemes: Record }, - ApplicationColorScheme extends string | never, -> = [ApplicationColorScheme] extends [never] - ? { - theme?: Omit & { - colorSchemes?: Partial< - Record< - DesignSystemColorScheme, - DesignSystemTheme['colorSchemes'][DesignSystemColorScheme] - > - >; - }; - } - : { - theme: Omit & { - colorSchemes: Partial< - Record< - DesignSystemColorScheme, - DesignSystemTheme['colorSchemes'][DesignSystemColorScheme] - > - > & - Record; - }; - }; - -const CssVarsProvider = SystemCssVarsProvider as ( - props: React.PropsWithChildren< - DecideTheme - >, -) => React.ReactElement; - export { CssVarsProvider, useColorScheme, getInitColorSchemeScript }; diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts b/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts index f5a5fd3173a187..0488de6bfd0b31 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts @@ -2,66 +2,16 @@ import * as React from 'react'; import getInitColorSchemeScript from './getInitColorSchemeScript'; import { Mode, Result } from './useCurrentColorScheme'; -/** - * DesignSystemColorScheme: is what a design system provide by default. Mostly, `light` and `dark` - * ApplicationColorScheme: is what developer can extend from a design system. Ex, `comfort` `trueDark` ...any name that they want - * - * This type enhance customization experience by checking if developer has extended the colorScheme or not (usually via module augmentation) - * If yes, they must provide the palette of the extended colorScheme. Otherwise `theme` is optional. - */ -type DecideTheme< - DesignSystemTheme extends { colorSchemes: Record }, - DesignSystemColorScheme extends string, - ApplicationTheme extends { colorSchemes: Record }, - ApplicationColorScheme extends string | never, -> = [ApplicationColorScheme] extends [never] - ? { - theme?: Omit & { - colorSchemes?: Partial< - Record< - DesignSystemColorScheme, - DesignSystemTheme['colorSchemes'][DesignSystemColorScheme] - > - >; - }; - } - : { - theme: Omit & { - colorSchemes: Partial< - Record< - DesignSystemColorScheme, - DesignSystemTheme['colorSchemes'][DesignSystemColorScheme] - > - > & - Record; - }; - }; - export interface ColorSchemeContextValue extends Result { allColorSchemes: SupportedColorScheme[]; } -export default function createCssVarsProvider< - DesignSystemThemeInput extends { - colorSchemes: Record; - }, - DesignSystemColorScheme extends string, - ApplicationThemeInput extends { - colorSchemes: Record; - } = never, - ApplicationColorScheme extends string = never, ->(options: { - /** - * Design system default theme - */ - theme: DesignSystemThemeInput; +export interface CssVarsProviderConfig { /** * Design system default color scheme */ - defaultColorScheme: - | DesignSystemColorScheme - | { light: DesignSystemColorScheme; dark: DesignSystemColorScheme }; + defaultColorScheme: ColorScheme | { light: ColorScheme; dark: ColorScheme }; /** * Design system default mode * @default 'light' @@ -82,39 +32,35 @@ export default function createCssVarsProvider< * @default '' */ prefix?: string; - /** - * 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; - /** - * A function to be called after the CSS variables are attached. The result of this function will be the final theme pass to ThemeProvider. - * - * The example usage is the variant generation in Joy. We need to combine the token from user-input and the default theme first, then generate - * variants from those tokens. - */ - resolveTheme?: (theme: any) => any; // the type is any because it depends on the design system. -}): { +} + +export default function createCssVarsProvider( + options: CssVarsProviderConfig & { + /** + * Design system default theme + */ + theme: any; + /** + * A function to determine if the key, value should be attached as CSS Variable + * `keys` is an array that represents the object path keys. + * Ex, if the theme is { foo: { bar: 'var(--test)' } } + * then, keys = ['foo', 'bar'] + * value = 'var(--test)' + */ + shouldSkipGeneratingVar?: (keys: string[], value: string | number) => boolean; + /** + * A function to be called after the CSS variables are attached. The result of this function will be the final theme pass to ThemeProvider. + * + * The example usage is the variant generation in Joy. We need to combine the token from user-input and the default theme first, then generate + * variants from those tokens. + */ + resolveTheme?: (theme: any) => any; // the type is any because it depends on the design system. + }, +): { CssVarsProvider: ( props: React.PropsWithChildren< - { - /** - * Application default mode (overrides design system `defaultMode` if specified) - */ - defaultMode?: Mode; - /** - * Application default colorScheme (overrides design system `defaultColorScheme` if specified) - */ - defaultColorScheme?: - | DesignSystemColorScheme - | ApplicationColorScheme - | { - light: DesignSystemColorScheme | ApplicationColorScheme; - dark: DesignSystemColorScheme | ApplicationColorScheme; - }; + Partial> & { + theme?: ThemeInput; /** * localStorage key used to store application `mode` * @default 'mui-mode' @@ -125,19 +71,10 @@ export default function createCssVarsProvider< * @default 'data-mui-color-scheme' */ attribute?: string; - /** - * CSS variable prefix (overrides design system `prefix` if specified) - */ - prefix?: string; - } & DecideTheme< - DesignSystemThemeInput, - DesignSystemColorScheme, - ApplicationThemeInput, - ApplicationColorScheme - > + } >, ) => React.ReactElement; - useColorScheme: () => ColorSchemeContextValue; + useColorScheme: () => ColorSchemeContextValue; getInitColorSchemeScript: typeof getInitColorSchemeScript; }; diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx b/packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx deleted file mode 100644 index 33d474eb096c5f..00000000000000 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx +++ /dev/null @@ -1,309 +0,0 @@ -import * as React from 'react'; -import { OverridableStringUnion } from '@mui/types'; -import { unstable_createCssVarsProvider as createCssVarsProvider } from '@mui/system'; - -// Test design system layer - -type DesignSystemColorScheme = 'light' | 'dark'; - -interface Colors { - palette: { - primary: { - 500: string; - }; - }; -} - -interface DesignSystemThemeInput { - colorSchemes: Record; - fontSize: { - md: string; - }; -} - -createCssVarsProvider({ - theme: { - fontSize: { - md: '1rem', - }, - // @ts-expect-error 'dark' is missing - colorSchemes: { - light: { - palette: { - primary: { - 500: '#007FFF', - }, - }, - }, - }, - }, -}); - -createCssVarsProvider( - // @ts-expect-error 'defaultColorScheme' is missing - { - theme: { - fontSize: { - md: '1rem', - }, - colorSchemes: { - light: { - palette: { - primary: { - 500: '#007FFF', - }, - }, - }, - dark: { - palette: { - primary: { - 500: '#007FFF', - }, - }, - }, - }, - }, - }, -); - -createCssVarsProvider({ - theme: { - fontSize: { - md: '1rem', - }, - // @ts-expect-error `lineHeight` is not in DesignSystemTheme - lineHeight: {}, - colorSchemes: { - light: { - palette: { - primary: { - 500: '#007FFF', - }, - }, - }, - dark: { - palette: { - primary: { - 500: '#007FFF', - }, - }, - }, - }, - }, - // @ts-expect-error `yellow` is not in DesignSystemColorScheme - defaultColorScheme: 'yellow', -}); - -createCssVarsProvider({ - theme: { - fontSize: { - md: '1rem', - }, - colorSchemes: { - light: { - palette: { - primary: { - 500: '#007FFF', - }, - }, - }, - dark: { - palette: { - primary: { - // @ts-expect-error `main` is not in Palette - main: '#007FFF', - }, - }, - }, - }, - }, - defaultColorScheme: 'dark', -}); - -// ============================== -// Test application layer -// 1. WITHOUT extending color scheme - -interface JoyColorSchemeOverrides {} - -type JoyExtendedColorScheme = OverridableStringUnion; - -type JoyColorScheme = 'light' | 'dark'; - -interface JoyColors { - palette: { - primary: { - main: string; - }; - }; -} - -interface JoyThemeInput { - colorSchemes: Record; - fontSize: string; - fontFamily: string; -} - -interface ApplicationThemeInput { - colorSchemes: Record; - fontSize: string; - fontFamily: string; -} - -const { CssVarsProvider } = createCssVarsProvider< - JoyThemeInput, - JoyColorScheme, - ApplicationThemeInput, - JoyExtendedColorScheme ->({ - theme: { - fontSize: '1rem', - fontFamily: 'IBM Plex Sans', - colorSchemes: { - light: { - palette: { - primary: { - main: '#007FFF', - }, - }, - }, - dark: { - palette: { - primary: { - main: '#007FFF', - }, - }, - }, - }, - }, - defaultColorScheme: 'light', -}); - -function App() { - return ( - - ); -} - -function App2() { - return ( - - ); -} - -// ========================= -// 1. WITH extending color scheme -// When developers extend new color schemes, they have to specify those new color schemes in the theme. - -interface Joy2ColorSchemeOverrides {} - -type Joy2ExtendedColorScheme = OverridableStringUnion; - -type Joy2ColorScheme = 'light' | 'dark'; - -interface Joy2Colors { - palette?: { - primary?: { - main?: string; - }; - }; -} - -interface Joy2ThemeInput { - colorSchemes: Record; - fontSize: string; - fontFamily: string; -} - -interface Application2ThemeInput { - colorSchemes: Record; - fontSize: string; - fontFamily: string; -} - -// Simulate color scheme extending, same as module augmentation in real application -interface Joy2ColorSchemeOverrides { - comfort: true; - trueDark: true; -} - -const { CssVarsProvider: CssVarsProvider2, useColorScheme } = createCssVarsProvider< - Joy2ThemeInput, - Joy2ColorScheme, - Application2ThemeInput, - Joy2ExtendedColorScheme ->({ - theme: { - fontSize: '1rem', - fontFamily: 'IBM Plex Sans', - colorSchemes: { - light: { - palette: { - primary: { - main: '#007FFF', - }, - }, - }, - dark: { - palette: { - primary: { - main: '#007FFF', - }, - }, - }, - }, - }, - defaultColorScheme: 'light', -}); - -function Content() { - const { setColorScheme } = useColorScheme(); - React.useEffect(() => { - // @ts-expect-error 'yellow' is not typed in JoyExtendedColorScheme - setColorScheme('yellow'); - - setColorScheme('comfort'); - }, [setColorScheme]); - return null; -} - -function App3() { - return ( - - ); -} - -function App4() { - return ( - - ); -} From 5fff83ac5d633ec2c77d72da5194793ce252cb11 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 17 Feb 2022 15:24:31 +0700 Subject: [PATCH 09/50] wip --- .../src/styles/CssVarsProvider.spec.tsx | 76 +++++++++++++++++++ .../mui-joy/src/styles/CssVarsProvider.tsx | 4 +- packages/mui-joy/src/styles/defaultTheme.ts | 68 ++--------------- .../mui-joy/src/styles/types/colorSystem.ts | 32 ++++---- 4 files changed, 99 insertions(+), 81 deletions(-) create mode 100644 packages/mui-joy/src/styles/CssVarsProvider.spec.tsx diff --git a/packages/mui-joy/src/styles/CssVarsProvider.spec.tsx b/packages/mui-joy/src/styles/CssVarsProvider.spec.tsx new file mode 100644 index 00000000000000..ff515344b650d3 --- /dev/null +++ b/packages/mui-joy/src/styles/CssVarsProvider.spec.tsx @@ -0,0 +1,76 @@ +import * as React from 'react'; +import { CssVarsProvider, PaletteScale, PaletteVariant } from '@mui/joy/styles'; + +declare module '@mui/joy/styles' { + interface ColorSchemeOverrides { + trueDark: true; + } + + interface Palette { + secondary: PaletteScale & PaletteVariant; + } +} + +function App() { + return ; +} + +function App2() { + // theme can be empty + return ; +} + +function App3() { + // theme can be empty + return ( + + ); +} + +function App4() { + // theme can be empty + return ( + + ); +} + +function App5() { + // theme can be empty + return ( + + ); +} diff --git a/packages/mui-joy/src/styles/CssVarsProvider.tsx b/packages/mui-joy/src/styles/CssVarsProvider.tsx index 4320495dfd8b2d..0e53177f5bb38b 100644 --- a/packages/mui-joy/src/styles/CssVarsProvider.tsx +++ b/packages/mui-joy/src/styles/CssVarsProvider.tsx @@ -46,7 +46,9 @@ interface JoyThemeInput extends Partial2Level { breakpoints?: BreakpointsOptions; spacing?: SpacingOptions; components?: Components; - colorSchemes?: Partial>>; + colorSchemes?: Partial< + Record> + >; } const { palette, ...rest } = defaultTheme; diff --git a/packages/mui-joy/src/styles/defaultTheme.ts b/packages/mui-joy/src/styles/defaultTheme.ts index 71333121337a11..4c02ba90972774 100644 --- a/packages/mui-joy/src/styles/defaultTheme.ts +++ b/packages/mui-joy/src/styles/defaultTheme.ts @@ -8,14 +8,7 @@ import { unstable_createGetCssVar as systemCreateGetCssVar, } from '@mui/system'; import colors from '../colors'; -import { - ColorSystem, - ColorPaletteProp, - Palette, - PaletteText, - PaletteRange, - PaletteBackground, -} from './types/colorSystem'; +import { ColorSystem, ColorPaletteProp } from './types/colorSystem'; import { Variants } from './types/variants'; import { DefaultColorScheme, ExtendedColorScheme } from './types/colorScheme'; import { Shadow } from './types/shadow'; @@ -51,42 +44,6 @@ export interface Focus { default: CSSObject; } -/** - * ============================================== - * Internal type for definfing default Joy theme. - * ============================================== - */ -type BasePaletteRange = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900; -type PartialRest = Pick & Partial>; -type BaseDesignTokens = { - palette: { - // variant tokens are optional because the style will be generated after CSS variables has been prepared. - primary: PartialRest; - neutral: PartialRest; - danger: PartialRest; - info: PartialRest; - success: PartialRest; - warning: PartialRest; - text: Pick; - background: Pick; - focusVisible: Palette['focusVisible']; - }; - radius: Pick; - shadowRing: CSSProperties['boxShadow']; - shadowChannel: string; - shadow: Pick; - fontSize: Pick< - FontSize, - 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xl2' | 'xl3' | 'xl4' | 'xl5' | 'xl6' - >; - fontFamily: Pick; - fontWeight: Pick; - lineHeight: Pick; - letterSpacing: Pick; -}; - -type BaseColorSystem = Pick; - const createLightModeVariantVariables = (color: ColorPaletteProp) => ({ textColor: `var(--joy-palette-${color}-600)`, textHoverBg: `var(--joy-palette-${color}-100)`, @@ -151,7 +108,7 @@ const createDarkModeVariantVariables = (color: ColorPaletteProp) => ({ overrideTextTertiary: `var(--joy-palette-${color}-500)`, }); -export const lightColorSystem: BaseColorSystem = { +export const lightColorSystem = { palette: { primary: { ...colors.blue, @@ -194,7 +151,7 @@ export const lightColorSystem: BaseColorSystem = { shadowChannel: '187 187 187', }; -export const darkColorSystem: BaseColorSystem = { +export const darkColorSystem = { palette: { primary: { ...colors.blue, @@ -241,7 +198,7 @@ export const darkColorSystem: BaseColorSystem = { * Base Joy design tokens * Any value with `var(--joy-*)` can be used. 'joy-' will be replaced by the application prefix if provided. */ -const baseDesignTokens: BaseDesignTokens = { +const baseDesignTokens = { ...lightColorSystem, radius: { xs: '4px', @@ -297,20 +254,7 @@ const baseDesignTokens: BaseDesignTokens = { const defaultSystemTheme = systemCreateTheme(); -// Internal usage for providing type safe. -// Module augmentation in this repo has no impact. -const internalDefaultTheme: BaseDesignTokens & { - colorSchemes: Record; - focus: Pick; - typography: Pick< - TypographySystem, - 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'body1' | 'body2' | 'body3' - >; - variants: {}; - vars: BaseDesignTokens & BaseColorSystem; - spacing: Spacing; - breakpoints: Breakpoints; -} = { +const internalDefaultTheme = { ...baseDesignTokens, colorSchemes: { light: lightColorSystem, @@ -427,6 +371,6 @@ export interface JoyTheme extends ThemeScales, ColorSystem { export type SxProps = SystemSxProps; -const defaultTheme = internalDefaultTheme as unknown as JoyTheme; +const defaultTheme = internalDefaultTheme as JoyTheme; export default defaultTheme; diff --git a/packages/mui-joy/src/styles/types/colorSystem.ts b/packages/mui-joy/src/styles/types/colorSystem.ts index 01ae89c9a43a0c..c45ad166286b7e 100644 --- a/packages/mui-joy/src/styles/types/colorSystem.ts +++ b/packages/mui-joy/src/styles/types/colorSystem.ts @@ -62,18 +62,14 @@ export interface PaletteVariant { overrideTextSecondary: string; overrideTextTertiary: string; } -export interface PaletteRange extends PaletteVariant { - 50: string; - 100: string; - 200: string; - 300: string; - 400: string; - 500: string; - 600: string; - 700: string; - 800: string; - 900: string; -} + +export interface PaletteScaleOverrides {} +export type ExtendedPaletteScale = OverridableStringUnion< + '50' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900', + PaletteScaleOverrides +>; + +export interface PaletteScale extends Record {} export interface PaletteText { primary: string; @@ -105,12 +101,12 @@ export type ColorPaletteProp = OverridableStringUnion< // Split interfaces into multiple chunks so that they can be augmented independently -export interface PalettePrimary extends PaletteRange {} -export interface PaletteNeutral extends PaletteRange {} -export interface PaletteDanger extends PaletteRange {} -export interface PaletteInfo extends PaletteRange {} -export interface PaletteSuccess extends PaletteRange {} -export interface PaletteWarning extends PaletteRange {} +export interface PalettePrimary extends PaletteScale, PaletteVariant {} +export interface PaletteNeutral extends PaletteScale, PaletteVariant {} +export interface PaletteDanger extends PaletteScale, PaletteVariant {} +export interface PaletteInfo extends PaletteScale, PaletteVariant {} +export interface PaletteSuccess extends PaletteScale, PaletteVariant {} +export interface PaletteWarning extends PaletteScale, PaletteVariant {} export interface Palette { primary: PalettePrimary; From cd8bc7e1b739421fef85404f993c81b4f6facdcd Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 17 Feb 2022 16:03:57 +0700 Subject: [PATCH 10/50] add spec --- .../src/styles/CssVarsProvider.spec.tsx | 125 +++++++++++++++++- .../mui-joy/src/styles/CssVarsProvider.tsx | 6 +- packages/mui-joy/src/styles/defaultTheme.ts | 3 +- .../mui-joy/src/styles/types/typography.ts | 19 ++- 4 files changed, 134 insertions(+), 19 deletions(-) diff --git a/packages/mui-joy/src/styles/CssVarsProvider.spec.tsx b/packages/mui-joy/src/styles/CssVarsProvider.spec.tsx index ff515344b650d3..8eb65a6a9f752c 100644 --- a/packages/mui-joy/src/styles/CssVarsProvider.spec.tsx +++ b/packages/mui-joy/src/styles/CssVarsProvider.spec.tsx @@ -1,6 +1,10 @@ import * as React from 'react'; +import { CSSObject } from '@mui/system'; import { CssVarsProvider, PaletteScale, PaletteVariant } from '@mui/joy/styles'; +// ----------------------------------- +// Extending palete + declare module '@mui/joy/styles' { interface ColorSchemeOverrides { trueDark: true; @@ -9,6 +13,11 @@ declare module '@mui/joy/styles' { interface Palette { secondary: PaletteScale & PaletteVariant; } + + interface PaletteScaleOverrides { + '100': false; + '120': true; + } } function App() { @@ -63,9 +72,9 @@ function App5() { light: { palette: { secondary: { - primary: { - '500': '', - }, + // @ts-expect-error `100` is removed + '100': '', + '120': '#ff5252', }, }, }, @@ -74,3 +83,113 @@ function App5() { /> ); } + +// ----------------------------------- +// Extending radius + +declare module '@mui/joy/styles' { + interface Radius { + xl2: string; + } +} + +function App6() { + // theme can be empty + return ( + + ); +} + +// ----------------------------------- +// Extending shadow + +declare module '@mui/joy/styles' { + interface Shadow { + xl2: string; + } +} + +function App7() { + // theme can be empty + return ( + + ); +} + +// ----------------------------------- +// Extending focus + +declare module '@mui/joy/styles' { + interface Focus { + bordered: CSSObject; + } +} + +function App8() { + // theme can be empty + return ( + + ); +} + +// ----------------------------------- +// Extending typography + +declare module '@mui/joy/styles' { + interface TypographySystemOverrides { + callout: true; // add new typography + h1: false; // default the default + } +} + +function App9() { + // theme can be empty + return ( + + + + + ); +} diff --git a/packages/mui-joy/src/styles/CssVarsProvider.tsx b/packages/mui-joy/src/styles/CssVarsProvider.tsx index 0e53177f5bb38b..d50141416050fb 100644 --- a/packages/mui-joy/src/styles/CssVarsProvider.tsx +++ b/packages/mui-joy/src/styles/CssVarsProvider.tsx @@ -41,7 +41,7 @@ type Partial3Level = { // Use Partial2Level instead of PartialDeep because nested value type is CSSObject which does not work with PartialDeep. interface JoyThemeInput extends Partial2Level { focus?: Partial; - typography?: TypographySystem; + typography?: Partial; variants?: Partial2Level; breakpoints?: BreakpointsOptions; spacing?: SpacingOptions; @@ -60,8 +60,8 @@ const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssV theme: { ...rest, colorSchemes: { - light: lightColorSystem as ColorSystem, - dark: darkColorSystem as ColorSystem, + light: lightColorSystem, + dark: darkColorSystem, }, }, defaultColorScheme: { diff --git a/packages/mui-joy/src/styles/defaultTheme.ts b/packages/mui-joy/src/styles/defaultTheme.ts index 4c02ba90972774..3c7b2227a455a4 100644 --- a/packages/mui-joy/src/styles/defaultTheme.ts +++ b/packages/mui-joy/src/styles/defaultTheme.ts @@ -334,7 +334,6 @@ const internalDefaultTheme = { }, }, variants: {}, - vars: baseDesignTokens, breakpoints: defaultSystemTheme.breakpoints, spacing: defaultSystemTheme.spacing, }; @@ -371,6 +370,6 @@ export interface JoyTheme extends ThemeScales, ColorSystem { export type SxProps = SystemSxProps; -const defaultTheme = internalDefaultTheme as JoyTheme; +const defaultTheme = internalDefaultTheme as unknown as JoyTheme; export default defaultTheme; diff --git a/packages/mui-joy/src/styles/types/typography.ts b/packages/mui-joy/src/styles/types/typography.ts index 1b4fe8d9f742c2..cbdeb405ea9c7d 100644 --- a/packages/mui-joy/src/styles/types/typography.ts +++ b/packages/mui-joy/src/styles/types/typography.ts @@ -1,4 +1,5 @@ import { CSSObject } from '@mui/system'; +import { OverridableStringUnion } from '@mui/types'; export interface FontSize { xs: string; @@ -40,14 +41,10 @@ export interface LetterSpacing { lg: string; } -export interface TypographySystem { - h1: CSSObject; - h2: CSSObject; - h3: CSSObject; - h4: CSSObject; - h5: CSSObject; - h6: CSSObject; - body1: CSSObject; - body2: CSSObject; - body3: CSSObject; -} +export interface TypographySystemOverrides {} +export type ExtendedTypographySystem = OverridableStringUnion< + 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'body1' | 'body2' | 'body3', + TypographySystemOverrides +>; + +export interface TypographySystem extends Record {} From 6e35910b74300fc4f5079b09c17fdd92eb4a1988 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 17 Feb 2022 16:27:40 +0700 Subject: [PATCH 11/50] revert the name to PaletteRange --- .../src/styles/CssVarsProvider.spec.tsx | 6 +++--- .../mui-joy/src/styles/types/colorSystem.ts | 20 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/mui-joy/src/styles/CssVarsProvider.spec.tsx b/packages/mui-joy/src/styles/CssVarsProvider.spec.tsx index 8eb65a6a9f752c..567f30b78b595a 100644 --- a/packages/mui-joy/src/styles/CssVarsProvider.spec.tsx +++ b/packages/mui-joy/src/styles/CssVarsProvider.spec.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { CSSObject } from '@mui/system'; -import { CssVarsProvider, PaletteScale, PaletteVariant } from '@mui/joy/styles'; +import { CssVarsProvider, PaletteRange, PaletteVariant } from '@mui/joy/styles'; // ----------------------------------- // Extending palete @@ -11,10 +11,10 @@ declare module '@mui/joy/styles' { } interface Palette { - secondary: PaletteScale & PaletteVariant; + secondary: PaletteRange; } - interface PaletteScaleOverrides { + interface PaletteRangeOverrides { '100': false; '120': true; } diff --git a/packages/mui-joy/src/styles/types/colorSystem.ts b/packages/mui-joy/src/styles/types/colorSystem.ts index c45ad166286b7e..3f877d4deefe50 100644 --- a/packages/mui-joy/src/styles/types/colorSystem.ts +++ b/packages/mui-joy/src/styles/types/colorSystem.ts @@ -63,13 +63,13 @@ export interface PaletteVariant { overrideTextTertiary: string; } -export interface PaletteScaleOverrides {} -export type ExtendedPaletteScale = OverridableStringUnion< +export interface PaletteRangeOverrides {} +export type ExtendedPaletteRange = OverridableStringUnion< '50' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900', - PaletteScaleOverrides + PaletteRangeOverrides >; -export interface PaletteScale extends Record {} +export interface PaletteRange extends Record, PaletteVariant {} export interface PaletteText { primary: string; @@ -101,12 +101,12 @@ export type ColorPaletteProp = OverridableStringUnion< // Split interfaces into multiple chunks so that they can be augmented independently -export interface PalettePrimary extends PaletteScale, PaletteVariant {} -export interface PaletteNeutral extends PaletteScale, PaletteVariant {} -export interface PaletteDanger extends PaletteScale, PaletteVariant {} -export interface PaletteInfo extends PaletteScale, PaletteVariant {} -export interface PaletteSuccess extends PaletteScale, PaletteVariant {} -export interface PaletteWarning extends PaletteScale, PaletteVariant {} +export interface PalettePrimary extends PaletteRange {} +export interface PaletteNeutral extends PaletteRange {} +export interface PaletteDanger extends PaletteRange {} +export interface PaletteInfo extends PaletteRange {} +export interface PaletteSuccess extends PaletteRange {} +export interface PaletteWarning extends PaletteRange {} export interface Palette { primary: PalettePrimary; From 95d75805ee417d6b84bf5de7cc48bc8c5700e7d4 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 17 Feb 2022 17:07:24 +0700 Subject: [PATCH 12/50] bring back vars for default them --- packages/mui-joy/src/styles/defaultTheme.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/mui-joy/src/styles/defaultTheme.ts b/packages/mui-joy/src/styles/defaultTheme.ts index 3c7b2227a455a4..2adff7ab5b488d 100644 --- a/packages/mui-joy/src/styles/defaultTheme.ts +++ b/packages/mui-joy/src/styles/defaultTheme.ts @@ -334,6 +334,7 @@ const internalDefaultTheme = { }, }, variants: {}, + vars: baseDesignTokens, breakpoints: defaultSystemTheme.breakpoints, spacing: defaultSystemTheme.spacing, }; From 3465d41e34dd579cf1202e1e42d04640dfe2f505 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 17 Feb 2022 17:26:49 +0700 Subject: [PATCH 13/50] add spec for createCssVarsProvider --- .../src/cssVars/createCssVarsProvider.d.ts | 5 +- .../cssVars/createCssVarsProvider.spec.tsx | 86 +++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts b/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts index 0488de6bfd0b31..7d447a86041e27 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts @@ -34,7 +34,10 @@ export interface CssVarsProviderConfig { prefix?: string; } -export default function createCssVarsProvider( +export default function createCssVarsProvider< + ColorScheme extends string, + ThemeInput extends { colorSchemes?: Partial> }, +>( options: CssVarsProviderConfig & { /** * Design system default theme diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx b/packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx new file mode 100644 index 00000000000000..16d622c9fc5d77 --- /dev/null +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.spec.tsx @@ -0,0 +1,86 @@ +import * as React from 'react'; +import { OverridableStringUnion } from '@mui/types'; +import { unstable_createCssVarsProvider as createCssVarsProvider } from '@mui/system'; + +interface JoyColorSchemeOverrides {} + +type JoyExtendedColorScheme = OverridableStringUnion; + +type JoyColorScheme = 'light' | 'dark' | JoyExtendedColorScheme; + +interface JoyThemeInput { + colorSchemes?: Partial< + Record< + JoyColorScheme, + { palette?: { primary?: { main?: string } }; fontSize?: { md?: string } } + > + >; +} + +// Simulate color scheme extending, same as module augmentation in real application +interface JoyColorSchemeOverrides { + comfort: true; + trueDark: true; +} + +const { CssVarsProvider, useColorScheme } = createCssVarsProvider({ + defaultColorScheme: 'light', + theme: { + fontSize: { + md: '1rem', + }, + colorSchemes: { + light: { + palette: { + primary: { + 500: '#007FFF', + }, + }, + }, + }, + }, +}); + +function Content() { + const { setColorScheme } = useColorScheme(); + React.useEffect(() => { + // @ts-expect-error 'yellow' is not typed in JoyExtendedColorScheme + setColorScheme('yellow'); + + setColorScheme('comfort'); + setColorScheme('light'); + }, [setColorScheme]); + return null; +} + +function App() { + return ( + + ); +} + +function App2() { + return ( + + ); +} From 918aa378f25aef6f5461ef941b9794f9acf6ca6f Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 17 Feb 2022 17:28:12 +0700 Subject: [PATCH 14/50] fix lint --- packages/mui-joy/src/styles/CssVarsProvider.spec.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/mui-joy/src/styles/CssVarsProvider.spec.tsx b/packages/mui-joy/src/styles/CssVarsProvider.spec.tsx index 567f30b78b595a..ac518d83251ae7 100644 --- a/packages/mui-joy/src/styles/CssVarsProvider.spec.tsx +++ b/packages/mui-joy/src/styles/CssVarsProvider.spec.tsx @@ -39,7 +39,7 @@ function App3() { trueDark: { palette: { primary: { - '500': '', + 500: '', }, }, }, @@ -73,8 +73,8 @@ function App5() { palette: { secondary: { // @ts-expect-error `100` is removed - '100': '', - '120': '#ff5252', + 100: '', + 120: '#ff5252', }, }, }, From 7614e32ec82c6fc732c0b16a1962d94101d46355 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 17 Feb 2022 17:29:30 +0700 Subject: [PATCH 15/50] revert type util change --- packages/mui-joy/src/styles/CssVarsProvider.tsx | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/mui-joy/src/styles/CssVarsProvider.tsx b/packages/mui-joy/src/styles/CssVarsProvider.tsx index d50141416050fb..b5145d634a3c2b 100644 --- a/packages/mui-joy/src/styles/CssVarsProvider.tsx +++ b/packages/mui-joy/src/styles/CssVarsProvider.tsx @@ -27,15 +27,13 @@ type Partial2Level = { }; type Partial3Level = { - [K in keyof T]?: T[K] extends Record - ? { - [J in keyof T[K]]?: T[K][J] extends Record - ? { - [P in keyof T[K][J]]?: T[K][J][P]; - } - : T[K][J]; - } - : T[K]; + [K in keyof T]?: { + [J in keyof T[K]]?: T[K][J] extends Record + ? { + [P in keyof T[K][J]]?: T[K][J][P]; + } + : T[K][J]; + }; }; // Use Partial2Level instead of PartialDeep because nested value type is CSSObject which does not work with PartialDeep. From 0d6279e3f0a9fb2cd1800871d9f1b368f3918249 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 17 Feb 2022 17:40:50 +0700 Subject: [PATCH 16/50] fix Typography types --- packages/mui-joy/src/Typography/Typography.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mui-joy/src/Typography/Typography.tsx b/packages/mui-joy/src/Typography/Typography.tsx index 1a3948b44a85d3..16a384ee528aba 100644 --- a/packages/mui-joy/src/Typography/Typography.tsx +++ b/packages/mui-joy/src/Typography/Typography.tsx @@ -36,7 +36,7 @@ export const TypographyRoot = styled('span', { }), })); -const defaultVariantMapping = { +const defaultVariantMapping: Record = { h1: 'h1', h2: 'h2', h3: 'h3', From 64eb5fe4191e5f6c9528b835531c5900d62caf9d Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Fri, 18 Feb 2022 12:11:59 +0100 Subject: [PATCH 17/50] wip --- docs/pages/experiments/mui/css-variables.tsx | 75 +++++++++++++++++++ packages/mui-material/src/Button/Button.js | 46 ++++++------ .../src/styles/CssVarsProvider.tsx | 47 ++++++++++++ packages/mui-material/src/styles/index.d.ts | 2 + packages/mui-material/src/styles/index.js | 2 + .../src/cssVars/createCssVarsProvider.js | 5 +- 6 files changed, 153 insertions(+), 24 deletions(-) create mode 100644 docs/pages/experiments/mui/css-variables.tsx create mode 100644 packages/mui-material/src/styles/CssVarsProvider.tsx diff --git a/docs/pages/experiments/mui/css-variables.tsx b/docs/pages/experiments/mui/css-variables.tsx new file mode 100644 index 00000000000000..656e3b6c6214be --- /dev/null +++ b/docs/pages/experiments/mui/css-variables.tsx @@ -0,0 +1,75 @@ +import * as React from 'react'; +import { CssVarsProvider, useColorScheme, createTheme } from '@mui/material/styles'; +import Moon from '@mui/icons-material/DarkMode'; +import Sun from '@mui/icons-material/LightMode'; +import Button from '@mui/material/Button'; +import Box from '@mui/material/Box'; + +const ColorSchemePicker = () => { + const { mode, setMode } = useColorScheme(); + const [mounted, setMounted] = React.useState(false); + React.useEffect(() => { + setMounted(true); + }, []); + if (!mounted) { + return null; + } + + return ( + + ); +}; + +export default function Page() { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} \ No newline at end of file diff --git a/packages/mui-material/src/Button/Button.js b/packages/mui-material/src/Button/Button.js index 9e03d3069f08cf..ceeb5104632bef 100644 --- a/packages/mui-material/src/Button/Button.js +++ b/packages/mui-material/src/Button/Button.js @@ -79,7 +79,7 @@ const ButtonRoot = styled(ButtonBase, { ...theme.typography.button, minWidth: 64, padding: '6px 16px', - borderRadius: theme.shape.borderRadius, + borderRadius: (theme.vars || theme).shape.borderRadius, transition: theme.transitions.create( ['background-color', 'box-shadow', 'border-color', 'color'], { @@ -106,7 +106,7 @@ const ButtonRoot = styled(ButtonBase, { }), ...(ownerState.variant === 'outlined' && ownerState.color !== 'inherit' && { - border: `1px solid ${theme.palette[ownerState.color].main}`, + border: `1px solid ${(theme.vars || theme).palette[ownerState.color].main}`, backgroundColor: alpha( theme.palette[ownerState.color].main, theme.palette.action.hoverOpacity, @@ -117,46 +117,46 @@ const ButtonRoot = styled(ButtonBase, { }, }), ...(ownerState.variant === 'contained' && { - backgroundColor: theme.palette.grey.A100, - boxShadow: theme.shadows[4], + backgroundColor: (theme.vars || theme).palette.grey.A100, + boxShadow: (theme.vars || theme).shadows[4], // Reset on touch devices, it doesn't add specificity '@media (hover: none)': { - boxShadow: theme.shadows[2], - backgroundColor: theme.palette.grey[300], + boxShadow: (theme.vars || theme).shadows[2], + backgroundColor: (theme.vars || theme).palette.grey[300], }, }), ...(ownerState.variant === 'contained' && ownerState.color !== 'inherit' && { - backgroundColor: theme.palette[ownerState.color].dark, + backgroundColor: (theme.vars || theme).palette[ownerState.color].dark, // Reset on touch devices, it doesn't add specificity '@media (hover: none)': { - backgroundColor: theme.palette[ownerState.color].main, + backgroundColor: (theme.vars || theme).palette[ownerState.color].main, }, }), }, '&:active': { ...(ownerState.variant === 'contained' && { - boxShadow: theme.shadows[8], + boxShadow: (theme.vars || theme).shadows[8], }), }, [`&.${buttonClasses.focusVisible}`]: { ...(ownerState.variant === 'contained' && { - boxShadow: theme.shadows[6], + boxShadow: (theme.vars || theme).shadows[6], }), }, [`&.${buttonClasses.disabled}`]: { - color: theme.palette.action.disabled, + color: (theme.vars || theme).palette.action.disabled, ...(ownerState.variant === 'outlined' && { - border: `1px solid ${theme.palette.action.disabledBackground}`, + border: `1px solid ${(theme.vars || theme).palette.action.disabledBackground}`, }), ...(ownerState.variant === 'outlined' && ownerState.color === 'secondary' && { - border: `1px solid ${theme.palette.action.disabled}`, + border: `1px solid ${(theme.vars || theme).palette.action.disabled}`, }), ...(ownerState.variant === 'contained' && { - color: theme.palette.action.disabled, - boxShadow: theme.shadows[0], - backgroundColor: theme.palette.action.disabledBackground, + color: (theme.vars || theme).palette.action.disabled, + boxShadow: (theme.vars || theme).shadows[0], + backgroundColor: (theme.vars || theme).palette.action.disabledBackground, }), }, ...(ownerState.variant === 'text' && { @@ -164,7 +164,7 @@ const ButtonRoot = styled(ButtonBase, { }), ...(ownerState.variant === 'text' && ownerState.color !== 'inherit' && { - color: theme.palette[ownerState.color].main, + color: (theme.vars || theme).palette[ownerState.color].main, }), ...(ownerState.variant === 'outlined' && { padding: '5px 15px', @@ -174,18 +174,18 @@ const ButtonRoot = styled(ButtonBase, { }), ...(ownerState.variant === 'outlined' && ownerState.color !== 'inherit' && { - color: theme.palette[ownerState.color].main, + color: (theme.vars || theme).palette[ownerState.color].main, border: `1px solid ${alpha(theme.palette[ownerState.color].main, 0.5)}`, }), ...(ownerState.variant === 'contained' && { - color: theme.palette.getContrastText(theme.palette.grey[300]), - backgroundColor: theme.palette.grey[300], - boxShadow: theme.shadows[2], + color: theme.palette.getContrastText?.(theme.palette.grey[300]), + backgroundColor: (theme.vars || theme).palette.grey[300], + boxShadow: (theme.vars || theme).shadows[2], }), ...(ownerState.variant === 'contained' && ownerState.color !== 'inherit' && { - color: theme.palette[ownerState.color].contrastText, - backgroundColor: theme.palette[ownerState.color].main, + color: (theme.vars || theme).palette[ownerState.color].contrastText, + backgroundColor: (theme.vars || theme).palette[ownerState.color].main, }), ...(ownerState.color === 'inherit' && { color: 'inherit', diff --git a/packages/mui-material/src/styles/CssVarsProvider.tsx b/packages/mui-material/src/styles/CssVarsProvider.tsx new file mode 100644 index 00000000000000..a973b30ffed03d --- /dev/null +++ b/packages/mui-material/src/styles/CssVarsProvider.tsx @@ -0,0 +1,47 @@ +import { unstable_createCssVarsProvider as createCssVarsProvider } from '@mui/system'; +import { deepmerge } from '@mui/utils'; +import createTheme, { ThemeOptions, Theme } from './createTheme'; +import { PaletteOptions } from './createPalette'; + +interface ThemeInput extends ThemeOptions { + colorSchemes?: Partial< + Record< + 'light' | 'dark', + Omit + > + >; +} + +interface ThemeWithColorSchemes extends Theme { + mode: 'light' | 'dark'; + colorSchemes: Record< + 'light' | 'dark', + Omit + >; +} + +const defaultTheme = createTheme(); +const darkTheme = createTheme({ palette: { mode: 'dark' } }); + +const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssVarsProvider<'light' | 'dark', ThemeInput>({ + theme: { + ...defaultTheme, + colorSchemes: { + // TODO: Shuold we remove the non color scheme values from here, like getContrastText, contrastThreshold etc. + light: { palette: defaultTheme.palette }, + dark: { palette: darkTheme.palette }, + }, + }, + defaultColorScheme: { + light: 'light', + dark: 'dark', + }, + resolveTheme: (mergedTheme) => { + console.log(mergedTheme); + return mergedTheme; + }, + shouldSkipGeneratingVar: (keys) => + keys[0] === 'typography' || keys[0] === 'mixins' || keys[0] === 'breakpoints', +}); + +export { useColorScheme, getInitColorSchemeScript, CssVarsProvider }; diff --git a/packages/mui-material/src/styles/index.d.ts b/packages/mui-material/src/styles/index.d.ts index af29ec8c92c272..bad1e5e2f42aa3 100644 --- a/packages/mui-material/src/styles/index.d.ts +++ b/packages/mui-material/src/styles/index.d.ts @@ -89,3 +89,5 @@ export interface StyledComponentProps { export { default as makeStyles } from './makeStyles'; export { default as withStyles } from './withStyles'; export { default as withTheme } from './withTheme'; + +export * from './CssVarsProvider'; diff --git a/packages/mui-material/src/styles/index.js b/packages/mui-material/src/styles/index.js index 5d19f3961bd5e1..f73c9bf0f7e2e9 100644 --- a/packages/mui-material/src/styles/index.js +++ b/packages/mui-material/src/styles/index.js @@ -32,3 +32,5 @@ export { StyledEngineProvider } from '@mui/system'; export { default as makeStyles } from './makeStyles'; export { default as withStyles } from './withStyles'; export { default as withTheme } from './withTheme'; + +export * from './CssVarsProvider'; diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.js b/packages/mui-system/src/cssVars/createCssVarsProvider.js index 5f49d6df37acad..7b811b773933ac 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.js +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.js @@ -64,7 +64,10 @@ export default function createCssVarsProvider(options) { }) { // make sure that baseTheme is always independent of each call. // JSON.parse(JSON.stringify(...)) is okay to be used as long as the baseTheme is a plain object. - const clonedBaseTheme = React.useMemo(() => JSON.parse(JSON.stringify(baseTheme)), []); + // const clonedBaseTheme = React.useMemo(() => JSON.parse(JSON.stringify(baseTheme)), []); + // TODO: this is not working for MD theme where there are functions, like + // transitions.create, palette.getContrastText etc. + const clonedBaseTheme = { ...baseTheme }; const { colorSchemes: baseColorSchemes = {}, ...restBaseTheme } = clonedBaseTheme; const { colorSchemes: colorSchemesProp = {}, ...restThemeProp } = themeProp; From ddcdd20df739dc343818362a952edcd57a19ca66 Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Fri, 18 Feb 2022 12:22:00 +0100 Subject: [PATCH 18/50] prettier & lint --- docs/pages/experiments/mui/css-variables.tsx | 46 +++++++++++++------ .../src/styles/CssVarsProvider.tsx | 18 ++------ .../src/cssVars/createCssVarsProvider.js | 2 +- 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/docs/pages/experiments/mui/css-variables.tsx b/docs/pages/experiments/mui/css-variables.tsx index 656e3b6c6214be..23d9cc5a5b3fd5 100644 --- a/docs/pages/experiments/mui/css-variables.tsx +++ b/docs/pages/experiments/mui/css-variables.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { CssVarsProvider, useColorScheme, createTheme } from '@mui/material/styles'; +import { CssVarsProvider, useColorScheme } from '@mui/material/styles'; import Moon from '@mui/icons-material/DarkMode'; import Sun from '@mui/icons-material/LightMode'; import Button from '@mui/material/Button'; @@ -45,31 +45,51 @@ export default function Page() { - - + + - - + + - - + + - - + + - - + + - ); -} \ No newline at end of file + ); +} diff --git a/packages/mui-material/src/styles/CssVarsProvider.tsx b/packages/mui-material/src/styles/CssVarsProvider.tsx index a973b30ffed03d..1cd3130aecd67d 100644 --- a/packages/mui-material/src/styles/CssVarsProvider.tsx +++ b/packages/mui-material/src/styles/CssVarsProvider.tsx @@ -1,5 +1,4 @@ import { unstable_createCssVarsProvider as createCssVarsProvider } from '@mui/system'; -import { deepmerge } from '@mui/utils'; import createTheme, { ThemeOptions, Theme } from './createTheme'; import { PaletteOptions } from './createPalette'; @@ -12,18 +11,13 @@ interface ThemeInput extends ThemeOptions { >; } -interface ThemeWithColorSchemes extends Theme { - mode: 'light' | 'dark'; - colorSchemes: Record< - 'light' | 'dark', - Omit - >; -} - const defaultTheme = createTheme(); const darkTheme = createTheme({ palette: { mode: 'dark' } }); -const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssVarsProvider<'light' | 'dark', ThemeInput>({ +const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssVarsProvider< + 'light' | 'dark', + ThemeInput +>({ theme: { ...defaultTheme, colorSchemes: { @@ -36,10 +30,6 @@ const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssV light: 'light', dark: 'dark', }, - resolveTheme: (mergedTheme) => { - console.log(mergedTheme); - return mergedTheme; - }, shouldSkipGeneratingVar: (keys) => keys[0] === 'typography' || keys[0] === 'mixins' || keys[0] === 'breakpoints', }); diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.js b/packages/mui-system/src/cssVars/createCssVarsProvider.js index 7b811b773933ac..ad7cdf51127a87 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.js +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.js @@ -67,7 +67,7 @@ export default function createCssVarsProvider(options) { // const clonedBaseTheme = React.useMemo(() => JSON.parse(JSON.stringify(baseTheme)), []); // TODO: this is not working for MD theme where there are functions, like // transitions.create, palette.getContrastText etc. - const clonedBaseTheme = { ...baseTheme }; + const clonedBaseTheme = React.useMemo(() => ({ ...baseTheme }), []); const { colorSchemes: baseColorSchemes = {}, ...restBaseTheme } = clonedBaseTheme; const { colorSchemes: colorSchemesProp = {}, ...restThemeProp } = themeProp; From 3c228cda63a535f40641b172fcf0802ecbbc3f15 Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Mon, 21 Feb 2022 12:36:49 +0100 Subject: [PATCH 19/50] Add custom design system page --- .../mui/css-variables-custom-theme.tsx | 193 ++++++++++++++++++ docs/pages/experiments/mui/css-variables.tsx | 1 - .../src/styles/CssVarsProvider.tsx | 17 +- 3 files changed, 207 insertions(+), 4 deletions(-) create mode 100644 docs/pages/experiments/mui/css-variables-custom-theme.tsx diff --git a/docs/pages/experiments/mui/css-variables-custom-theme.tsx b/docs/pages/experiments/mui/css-variables-custom-theme.tsx new file mode 100644 index 00000000000000..d5eb1754fa2987 --- /dev/null +++ b/docs/pages/experiments/mui/css-variables-custom-theme.tsx @@ -0,0 +1,193 @@ +import * as React from 'react'; +import { + CssVarsProvider, + useColorScheme, + createTheme, + ThemeInput, + alpha, + darken, +} from '@mui/material/styles'; +import Moon from '@mui/icons-material/DarkMode'; +import Sun from '@mui/icons-material/LightMode'; +import Button from '@mui/material/Button'; +import Box from '@mui/material/Box'; +import { teal, deepOrange, orange, cyan } from '@mui/material/colors'; + +const ColorSchemePicker = ({ modeChanged }: { modeChanged: (mode: 'light' | 'dark') => void }) => { + const { mode, setMode } = useColorScheme(); + const [mounted, setMounted] = React.useState(false); + React.useEffect(() => { + setMounted(true); + }, []); + if (!mounted) { + return null; + } + + return ( + + ); +}; + +const defaultTheme = createTheme({ + palette: { + primary: teal, + secondary: deepOrange, + }, +}); + +const darkTheme = createTheme({ + palette: { + primary: cyan, + secondary: orange, + }, +}); + +const themeWithColorSchemes = { + ...defaultTheme, + colorSchemes: { + light: { + palette: { + primary: defaultTheme.palette.primary, + secondary: defaultTheme.palette.secondary, + }, + }, + dark: { + palette: { + primary: defaultTheme.palette.primary, + secondary: defaultTheme.palette.secondary, + }, + }, + }, +}; + +const darkThemeWithColorSchemes = { + ...darkTheme, + colorSchemes: { + light: { + palette: { + primary: defaultTheme.palette.primary, + secondary: defaultTheme.palette.secondary, + }, + }, + dark: { + palette: { + primary: darkTheme.palette.primary, + secondary: darkTheme.palette.secondary, + }, + }, + }, +}; + +export default function Page() { + const [theme, setTheme] = React.useState(themeWithColorSchemes); + + const modeChanged = (newMode: 'light' | 'dark') => { + setTheme(newMode === 'dark' ? darkThemeWithColorSchemes : themeWithColorSchemes); + }; + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/docs/pages/experiments/mui/css-variables.tsx b/docs/pages/experiments/mui/css-variables.tsx index 23d9cc5a5b3fd5..8e46aaa14ded76 100644 --- a/docs/pages/experiments/mui/css-variables.tsx +++ b/docs/pages/experiments/mui/css-variables.tsx @@ -25,7 +25,6 @@ const ColorSchemePicker = () => { setMode('light'); } }} - sx={{ '--Button-gutter': '0.25rem', minWidth: 'var(--Button-minHeight)' }} > {mode === 'light' ? : } diff --git a/packages/mui-material/src/styles/CssVarsProvider.tsx b/packages/mui-material/src/styles/CssVarsProvider.tsx index 1cd3130aecd67d..d6adec356f5170 100644 --- a/packages/mui-material/src/styles/CssVarsProvider.tsx +++ b/packages/mui-material/src/styles/CssVarsProvider.tsx @@ -1,12 +1,22 @@ import { unstable_createCssVarsProvider as createCssVarsProvider } from '@mui/system'; import createTheme, { ThemeOptions, Theme } from './createTheme'; -import { PaletteOptions } from './createPalette'; +import { PaletteOptions, PaletteColorOptions } from './createPalette'; -interface ThemeInput extends ThemeOptions { +export interface ThemeInput extends ThemeOptions { colorSchemes?: Partial< Record< 'light' | 'dark', - Omit + { + palette: Partial< + Record< + keyof Omit< + PaletteOptions, + 'getContrastText' | 'contrastThreshold' | 'tonalOffset' | 'mode' + >, + PaletteColorOptions + > + >; + } > >; } @@ -30,6 +40,7 @@ const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssV light: 'light', dark: 'dark', }, + prefix: 'md', shouldSkipGeneratingVar: (keys) => keys[0] === 'typography' || keys[0] === 'mixins' || keys[0] === 'breakpoints', }); From 1f6b4395cb7a51cc714ba24b5d9b0810324d8580 Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Mon, 21 Feb 2022 13:12:38 +0100 Subject: [PATCH 20/50] Fix CI --- packages/mui-material/src/styles/CssVarsProvider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mui-material/src/styles/CssVarsProvider.tsx b/packages/mui-material/src/styles/CssVarsProvider.tsx index d6adec356f5170..aef09848b9a515 100644 --- a/packages/mui-material/src/styles/CssVarsProvider.tsx +++ b/packages/mui-material/src/styles/CssVarsProvider.tsx @@ -1,5 +1,5 @@ import { unstable_createCssVarsProvider as createCssVarsProvider } from '@mui/system'; -import createTheme, { ThemeOptions, Theme } from './createTheme'; +import createTheme, { ThemeOptions } from './createTheme'; import { PaletteOptions, PaletteColorOptions } from './createPalette'; export interface ThemeInput extends ThemeOptions { From be88d5ac2ab4bc4489a52fd2d9f9da742f648f33 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 3 Mar 2022 14:47:24 +0700 Subject: [PATCH 21/50] rename folder to material-ui --- .../{mui => material-ui}/css-variables-custom-theme.tsx | 0 docs/pages/experiments/{mui => material-ui}/css-variables.tsx | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename docs/pages/experiments/{mui => material-ui}/css-variables-custom-theme.tsx (100%) rename docs/pages/experiments/{mui => material-ui}/css-variables.tsx (100%) diff --git a/docs/pages/experiments/mui/css-variables-custom-theme.tsx b/docs/pages/experiments/material-ui/css-variables-custom-theme.tsx similarity index 100% rename from docs/pages/experiments/mui/css-variables-custom-theme.tsx rename to docs/pages/experiments/material-ui/css-variables-custom-theme.tsx diff --git a/docs/pages/experiments/mui/css-variables.tsx b/docs/pages/experiments/material-ui/css-variables.tsx similarity index 100% rename from docs/pages/experiments/mui/css-variables.tsx rename to docs/pages/experiments/material-ui/css-variables.tsx From 0ef6c17f1aa40bd96cffbe501e95ac5e51bbd2fb Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 3 Mar 2022 14:54:00 +0700 Subject: [PATCH 22/50] fix double generated vars --- packages/mui-material/src/styles/CssVarsProvider.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/mui-material/src/styles/CssVarsProvider.tsx b/packages/mui-material/src/styles/CssVarsProvider.tsx index aef09848b9a515..a31c01d220e113 100644 --- a/packages/mui-material/src/styles/CssVarsProvider.tsx +++ b/packages/mui-material/src/styles/CssVarsProvider.tsx @@ -21,8 +21,8 @@ export interface ThemeInput extends ThemeOptions { >; } -const defaultTheme = createTheme(); -const darkTheme = createTheme({ palette: { mode: 'dark' } }); +const { palette: lightPalette, ...defaultTheme } = createTheme(); +const { palette: darkPalette } = createTheme({ palette: { mode: 'dark' } }); const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssVarsProvider< 'light' | 'dark', @@ -32,8 +32,8 @@ const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssV ...defaultTheme, colorSchemes: { // TODO: Shuold we remove the non color scheme values from here, like getContrastText, contrastThreshold etc. - light: { palette: defaultTheme.palette }, - dark: { palette: darkTheme.palette }, + light: { palette: lightPalette }, + dark: { palette: darkPalette }, }, }, defaultColorScheme: { @@ -42,7 +42,7 @@ const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssV }, prefix: 'md', shouldSkipGeneratingVar: (keys) => - keys[0] === 'typography' || keys[0] === 'mixins' || keys[0] === 'breakpoints', + !!keys[0].match(/(typography|mixins|breakpoints|direction|transitions)/), }); export { useColorScheme, getInitColorSchemeScript, CssVarsProvider }; From b62d8d8b7e84c618e688f5b96c4ccf3f45155879 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 3 Mar 2022 15:22:52 +0700 Subject: [PATCH 23/50] use channel token for js color manipulation --- .../experiments/material-ui/css-variables.tsx | 58 ++++++++++++++++++- packages/mui-material/src/Button/Button.js | 42 ++++++++++---- 2 files changed, 88 insertions(+), 12 deletions(-) diff --git a/docs/pages/experiments/material-ui/css-variables.tsx b/docs/pages/experiments/material-ui/css-variables.tsx index 8e46aaa14ded76..ea6c4e9945f058 100644 --- a/docs/pages/experiments/material-ui/css-variables.tsx +++ b/docs/pages/experiments/material-ui/css-variables.tsx @@ -33,7 +33,63 @@ const ColorSchemePicker = () => { export default function Page() { return ( - + diff --git a/packages/mui-material/src/Button/Button.js b/packages/mui-material/src/Button/Button.js index ceeb5104632bef..89586902903871 100644 --- a/packages/mui-material/src/Button/Button.js +++ b/packages/mui-material/src/Button/Button.js @@ -88,17 +88,25 @@ const ButtonRoot = styled(ButtonBase, { ), '&:hover': { textDecoration: 'none', - backgroundColor: alpha(theme.palette.text.primary, theme.palette.action.hoverOpacity), + // backgroundColor: alpha(theme.palette.text.primary, theme.palette.action.hoverOpacity), + backgroundColor: theme.vars + ? `rgba(0,0,0,${theme.vars.opacity?.hover})` + : alpha(theme.palette.text.primary, theme.palette.action.hoverOpacity), // Reset on touch devices, it doesn't add specificity '@media (hover: none)': { backgroundColor: 'transparent', }, ...(ownerState.variant === 'text' && ownerState.color !== 'inherit' && { - backgroundColor: alpha( - theme.palette[ownerState.color].main, - theme.palette.action.hoverOpacity, - ), + // backgroundColor: alpha( + // theme.palette[ownerState.color].main, + // theme.palette.action.hoverOpacity, + // ), + backgroundColor: theme.vars + ? `rgba(${theme.vars.palette[ownerState.color].mainChannel} / ${ + theme.vars.opacity?.hover + })` + : alpha(theme.palette[ownerState.color].main, theme.palette.action.hoverOpacity), // Reset on touch devices, it doesn't add specificity '@media (hover: none)': { backgroundColor: 'transparent', @@ -107,10 +115,15 @@ const ButtonRoot = styled(ButtonBase, { ...(ownerState.variant === 'outlined' && ownerState.color !== 'inherit' && { border: `1px solid ${(theme.vars || theme).palette[ownerState.color].main}`, - backgroundColor: alpha( - theme.palette[ownerState.color].main, - theme.palette.action.hoverOpacity, - ), + // backgroundColor: alpha( + // theme.palette[ownerState.color].main, + // theme.palette.action.hoverOpacity, + // ), + backgroundColor: theme.vars + ? `rgba(${theme.vars.palette[ownerState.color].mainChannel} / ${ + theme.vars.opacity?.hover + })` + : alpha(theme.palette[ownerState.color].main, theme.palette.action.hoverOpacity), // Reset on touch devices, it doesn't add specificity '@media (hover: none)': { backgroundColor: 'transparent', @@ -175,10 +188,17 @@ const ButtonRoot = styled(ButtonBase, { ...(ownerState.variant === 'outlined' && ownerState.color !== 'inherit' && { color: (theme.vars || theme).palette[ownerState.color].main, - border: `1px solid ${alpha(theme.palette[ownerState.color].main, 0.5)}`, + // border: `1px solid ${alpha(theme.palette[ownerState.color].main, 0.5)}`, + border: theme.vars + ? `1px solid rgba(${theme.vars.palette[ownerState.color].mainChannel} / 0.5)` + : `1px solid ${alpha(theme.palette[ownerState.color].main, 0.5)}`, }), ...(ownerState.variant === 'contained' && { - color: theme.palette.getContrastText?.(theme.palette.grey[300]), + // color: theme.palette.getContrastText?.(theme.palette.grey[300]), + color: theme.vars + ? // this is safe because grey does not change between default light/dark mode + theme.vars.palette.text.primary + : theme.palette.getContrastText?.(theme.palette.grey[300]), backgroundColor: (theme.vars || theme).palette.grey[300], boxShadow: (theme.vars || theme).shadows[2], }), From 79a1b67a947857420eb6f711ce69c38d151e4940 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 3 Mar 2022 15:45:49 +0700 Subject: [PATCH 24/50] fix custom theme page --- .../css-variables-custom-theme.tsx | 189 +++++++++++++----- 1 file changed, 137 insertions(+), 52 deletions(-) diff --git a/docs/pages/experiments/material-ui/css-variables-custom-theme.tsx b/docs/pages/experiments/material-ui/css-variables-custom-theme.tsx index d5eb1754fa2987..4883beda7c61ec 100644 --- a/docs/pages/experiments/material-ui/css-variables-custom-theme.tsx +++ b/docs/pages/experiments/material-ui/css-variables-custom-theme.tsx @@ -7,6 +7,7 @@ import { alpha, darken, } from '@mui/material/styles'; +import { deepmerge } from '@mui/utils'; import Moon from '@mui/icons-material/DarkMode'; import Sun from '@mui/icons-material/LightMode'; import Button from '@mui/material/Button'; @@ -41,68 +42,152 @@ const ColorSchemePicker = ({ modeChanged }: { modeChanged: (mode: 'light' | 'dar ); }; -const defaultTheme = createTheme({ - palette: { - primary: teal, - secondary: deepOrange, - }, -}); +// const defaultTheme = createTheme({ +// palette: { +// primary: teal, +// secondary: deepOrange, +// }, +// }); -const darkTheme = createTheme({ - palette: { - primary: cyan, - secondary: orange, - }, -}); +// const darkTheme = createTheme({ +// palette: { +// primary: cyan, +// secondary: orange, +// }, +// }); -const themeWithColorSchemes = { - ...defaultTheme, - colorSchemes: { - light: { - palette: { - primary: defaultTheme.palette.primary, - secondary: defaultTheme.palette.secondary, - }, - }, - dark: { - palette: { - primary: defaultTheme.palette.primary, - secondary: defaultTheme.palette.secondary, - }, - }, - }, -}; +// const themeWithColorSchemes = { +// ...defaultTheme, +// colorSchemes: { +// light: { +// palette: { +// primary: defaultTheme.palette.primary, +// secondary: defaultTheme.palette.secondary, +// }, +// }, +// dark: { +// palette: { +// primary: defaultTheme.palette.primary, +// secondary: defaultTheme.palette.secondary, +// }, +// }, +// }, +// }; -const darkThemeWithColorSchemes = { - ...darkTheme, - colorSchemes: { - light: { - palette: { - primary: defaultTheme.palette.primary, - secondary: defaultTheme.palette.secondary, - }, - }, - dark: { - palette: { - primary: darkTheme.palette.primary, - secondary: darkTheme.palette.secondary, - }, - }, - }, -}; +// const darkThemeWithColorSchemes = { +// ...darkTheme, +// colorSchemes: { +// light: { +// palette: { +// primary: defaultTheme.palette.primary, +// secondary: defaultTheme.palette.secondary, +// }, +// }, +// dark: { +// palette: { +// primary: darkTheme.palette.primary, +// secondary: darkTheme.palette.secondary, +// }, +// }, +// }, +// }; export default function Page() { - const [theme, setTheme] = React.useState(themeWithColorSchemes); + // const [theme, setTheme] = React.useState(themeWithColorSchemes); - const modeChanged = (newMode: 'light' | 'dark') => { - setTheme(newMode === 'dark' ? darkThemeWithColorSchemes : themeWithColorSchemes); - }; + // const modeChanged = (newMode: 'light' | 'dark') => { + // setTheme(newMode === 'dark' ? darkThemeWithColorSchemes : themeWithColorSchemes); + // }; return ( - + - + From d8f73067a066bb3f7b110ac7cc2104f1e92502ba Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Tue, 8 Mar 2022 13:42:14 +0100 Subject: [PATCH 25/50] [material] Add an unstable createTheme for creating a theme using color schemes --- .../css-variables-custom-theme.tsx | 165 ++---------------- .../experiments/material-ui/css-variables.tsx | 62 +------ .../src/styles/CssVarsProvider.tsx | 18 +- .../src/styles/createPalette.d.ts | 26 +++ .../mui-material/src/styles/createPalette.js | 2 +- packages/mui-material/src/styles/index.d.ts | 3 + packages/mui-material/src/styles/index.js | 1 + .../src/styles/unstable_createTheme.d.ts | 63 +++++++ .../src/styles/unstable_createTheme.js | 165 ++++++++++++++++++ 9 files changed, 287 insertions(+), 218 deletions(-) create mode 100644 packages/mui-material/src/styles/unstable_createTheme.d.ts create mode 100644 packages/mui-material/src/styles/unstable_createTheme.js diff --git a/docs/pages/experiments/material-ui/css-variables-custom-theme.tsx b/docs/pages/experiments/material-ui/css-variables-custom-theme.tsx index 4883beda7c61ec..60d16912393ecf 100644 --- a/docs/pages/experiments/material-ui/css-variables-custom-theme.tsx +++ b/docs/pages/experiments/material-ui/css-variables-custom-theme.tsx @@ -2,19 +2,17 @@ import * as React from 'react'; import { CssVarsProvider, useColorScheme, - createTheme, - ThemeInput, + unstable_createTheme, alpha, darken, } from '@mui/material/styles'; -import { deepmerge } from '@mui/utils'; import Moon from '@mui/icons-material/DarkMode'; import Sun from '@mui/icons-material/LightMode'; import Button from '@mui/material/Button'; import Box from '@mui/material/Box'; import { teal, deepOrange, orange, cyan } from '@mui/material/colors'; -const ColorSchemePicker = ({ modeChanged }: { modeChanged: (mode: 'light' | 'dark') => void }) => { +const ColorSchemePicker = () => { const { mode, setMode } = useColorScheme(); const [mounted, setMounted] = React.useState(false); React.useEffect(() => { @@ -30,10 +28,8 @@ const ColorSchemePicker = ({ modeChanged }: { modeChanged: (mode: 'light' | 'dar onClick={() => { if (mode === 'light') { setMode('dark'); - modeChanged('dark'); } else { setMode('light'); - modeChanged('light'); } }} > @@ -42,149 +38,26 @@ const ColorSchemePicker = ({ modeChanged }: { modeChanged: (mode: 'light' | 'dar ); }; -// const defaultTheme = createTheme({ -// palette: { -// primary: teal, -// secondary: deepOrange, -// }, -// }); - -// const darkTheme = createTheme({ -// palette: { -// primary: cyan, -// secondary: orange, -// }, -// }); - -// const themeWithColorSchemes = { -// ...defaultTheme, -// colorSchemes: { -// light: { -// palette: { -// primary: defaultTheme.palette.primary, -// secondary: defaultTheme.palette.secondary, -// }, -// }, -// dark: { -// palette: { -// primary: defaultTheme.palette.primary, -// secondary: defaultTheme.palette.secondary, -// }, -// }, -// }, -// }; - -// const darkThemeWithColorSchemes = { -// ...darkTheme, -// colorSchemes: { -// light: { -// palette: { -// primary: defaultTheme.palette.primary, -// secondary: defaultTheme.palette.secondary, -// }, -// }, -// dark: { -// palette: { -// primary: darkTheme.palette.primary, -// secondary: darkTheme.palette.secondary, -// }, -// }, -// }, -// }; +const theme = unstable_createTheme({ + colorSchemes: { + light: { + palette: { + primary: teal, + secondary: deepOrange, + }, + }, + dark: { + palette: { + primary: cyan, + secondary: orange, + }, + }, + }, +}); export default function Page() { - // const [theme, setTheme] = React.useState(themeWithColorSchemes); - - // const modeChanged = (newMode: 'light' | 'dark') => { - // setTheme(newMode === 'dark' ? darkThemeWithColorSchemes : themeWithColorSchemes); - // }; - return ( - + diff --git a/docs/pages/experiments/material-ui/css-variables.tsx b/docs/pages/experiments/material-ui/css-variables.tsx index ea6c4e9945f058..a396a820468b92 100644 --- a/docs/pages/experiments/material-ui/css-variables.tsx +++ b/docs/pages/experiments/material-ui/css-variables.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { CssVarsProvider, useColorScheme } from '@mui/material/styles'; +import { CssVarsProvider, useColorScheme, unstable_createTheme } from '@mui/material/styles'; import Moon from '@mui/icons-material/DarkMode'; import Sun from '@mui/icons-material/LightMode'; import Button from '@mui/material/Button'; @@ -31,65 +31,11 @@ const ColorSchemePicker = () => { ); }; +const theme = unstable_createTheme(); + export default function Page() { return ( - + diff --git a/packages/mui-material/src/styles/CssVarsProvider.tsx b/packages/mui-material/src/styles/CssVarsProvider.tsx index a31c01d220e113..ae30f7111a2c70 100644 --- a/packages/mui-material/src/styles/CssVarsProvider.tsx +++ b/packages/mui-material/src/styles/CssVarsProvider.tsx @@ -1,21 +1,13 @@ import { unstable_createCssVarsProvider as createCssVarsProvider } from '@mui/system'; -import createTheme, { ThemeOptions } from './createTheme'; -import { PaletteOptions, PaletteColorOptions } from './createPalette'; +import createTheme, { Theme } from './createTheme'; +import { PaletteWithChannels } from './createPalette'; -export interface ThemeInput extends ThemeOptions { - colorSchemes?: Partial< +export interface ThemeInput extends Theme { + colorSchemes: Partial< Record< 'light' | 'dark', { - palette: Partial< - Record< - keyof Omit< - PaletteOptions, - 'getContrastText' | 'contrastThreshold' | 'tonalOffset' | 'mode' - >, - PaletteColorOptions - > - >; + palette: PaletteWithChannels; } > >; diff --git a/packages/mui-material/src/styles/createPalette.d.ts b/packages/mui-material/src/styles/createPalette.d.ts index f64ec3e088c31e..0ac7a26fcbd7b6 100644 --- a/packages/mui-material/src/styles/createPalette.d.ts +++ b/packages/mui-material/src/styles/createPalette.d.ts @@ -98,6 +98,32 @@ export interface Palette { augmentColor: (options: PaletteAugmentColorOptions) => PaletteColor; } +export interface Channels { + mainChannel: string; + lightChannel: string; + darkChannel: string; +} + +export interface PaletteWithChannels { + common: CommonColors; + mode: PaletteMode; + contrastThreshold: number; + tonalOffset: PaletteTonalOffset; + primary: PaletteColor & Channels; + secondary: PaletteColor & Channels; + error: PaletteColor & Channels; + warning: PaletteColor & Channels; + info: PaletteColor & Channels; + success: PaletteColor & Channels; + grey: Color; + text: TypeText; + divider: TypeDivider; + action: TypeAction; + background: TypeBackground; + getContrastText: (background: string) => string; + augmentColor: (options: PaletteAugmentColorOptions) => PaletteColor; +} + export type PartialTypeObject = { [P in keyof TypeObject]?: Partial }; export interface PaletteOptions { diff --git a/packages/mui-material/src/styles/createPalette.js b/packages/mui-material/src/styles/createPalette.js index a36f716d733aa0..d587b9a276c6a1 100644 --- a/packages/mui-material/src/styles/createPalette.js +++ b/packages/mui-material/src/styles/createPalette.js @@ -224,7 +224,7 @@ export default function createPalette(palette) { if (!color.hasOwnProperty('main')) { throw new MuiError( - 'MUI: The color%s provided to augmentColor(color) is invalid.\n' + + 'MUI: The color %s provided to augmentColor(color) is invalid.\n' + 'The color object needs to have a `main` property or a `%s` property.', name ? ` (${name})` : '', mainShade, diff --git a/packages/mui-material/src/styles/index.d.ts b/packages/mui-material/src/styles/index.d.ts index bad1e5e2f42aa3..86076cdd360a1f 100644 --- a/packages/mui-material/src/styles/index.d.ts +++ b/packages/mui-material/src/styles/index.d.ts @@ -91,3 +91,6 @@ export { default as withStyles } from './withStyles'; export { default as withTheme } from './withTheme'; export * from './CssVarsProvider'; + +export { default as unstable_createTheme } from './unstable_createTheme'; +export * from './unstable_createTheme'; diff --git a/packages/mui-material/src/styles/index.js b/packages/mui-material/src/styles/index.js index f73c9bf0f7e2e9..afe79e23e32295 100644 --- a/packages/mui-material/src/styles/index.js +++ b/packages/mui-material/src/styles/index.js @@ -34,3 +34,4 @@ export { default as withStyles } from './withStyles'; export { default as withTheme } from './withTheme'; export * from './CssVarsProvider'; +export { default as unstable_createTheme } from './unstable_createTheme'; diff --git a/packages/mui-material/src/styles/unstable_createTheme.d.ts b/packages/mui-material/src/styles/unstable_createTheme.d.ts new file mode 100644 index 00000000000000..aa7a96b9e5e08e --- /dev/null +++ b/packages/mui-material/src/styles/unstable_createTheme.d.ts @@ -0,0 +1,63 @@ +import { ThemeOptions as SystemThemeOptions, Theme as SystemTheme } 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; + colorSchemes?: Record; + shadows?: Shadows; + transitions?: TransitionsOptions; + typography?: TypographyOptions | ((palette: Palette) => TypographyOptions); + zIndex?: ZIndexOptions; + unstable_strictMode?: boolean; + opacity?: { + active?: number; + hover?: number; + selected?: number; + disabled?: number; + focus?: number; + }; +} + +interface BaseTheme extends SystemTheme { + mixins: Mixins; + palette: Palette; + shadows: Shadows; + transitions: Transitions; + typography: Typography; + zIndex: ZIndex; + unstable_strictMode?: boolean; + colorSchemes: Record; + opacity: { + active: number; + hover: number; + selected: number; + disabled: number; + focus: number; + }; +} + +// shut off automatic exporting for the `BaseTheme` above +export {}; + +/** + * Our [TypeScript guide on theme customization](https://mui.com/guides/typescript/#customization-of-theme) explains in detail how you would add custom properties. + */ +export interface Theme extends BaseTheme { + components?: Components; +} + +/** + * 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 unstable_createTheme(options?: ThemeOptions, ...args: object[]): Theme; diff --git a/packages/mui-material/src/styles/unstable_createTheme.js b/packages/mui-material/src/styles/unstable_createTheme.js new file mode 100644 index 00000000000000..1fecec3cdbc7a9 --- /dev/null +++ b/packages/mui-material/src/styles/unstable_createTheme.js @@ -0,0 +1,165 @@ +import { deepmerge } from '@mui/utils'; +import { generateUtilityClass } from '@mui/base'; +import { createTheme as systemCreateTheme, decomposeColor } from '@mui/system'; +import createThemeWithoutVars from './createTheme'; +import createMixins from './createMixins'; +import createPalette from './createPalette'; +import createTypography from './createTypography'; +import shadows from './shadows'; +import createTransitions from './createTransitions'; +import zIndex from './zIndex'; + +const { palette: lightPalette } = createThemeWithoutVars(); +const { palette: darkPalette } = createThemeWithoutVars({ palette: { mode: 'dark' } }); + +function createTheme(options = {}, ...args) { + const { + breakpoints: breakpointsInput, + mixins: mixinsInput = {}, + spacing: spacingInput, + // palette: paletteInput = {}, + colorSchemes: colorSchemesInput = {}, + transitions: transitionsInput = {}, + typography: typographyInput = {}, + shape: shapeInput, + opacity: opacityInput = {}, + ...other + } = options; + + const colorSchemesInitial = deepmerge( + { + light: { palette: lightPalette }, + dark: { palette: darkPalette }, + }, + colorSchemesInput, + ); + + const colorSchemes = {}; + + Object.keys(colorSchemesInitial).forEach((key) => { + const palette = createPalette(colorSchemesInitial[key].palette); + + Object.keys(palette).forEach((color) => { + const colors = palette[color]; + + if (colors.main) { + palette[color].mainChannel = decomposeColor(colors.main).values.join(' '); + } + if (colors.light) { + palette[color].lightChannel = decomposeColor(colors.light).values.join(' '); + } + if (colors.dark) { + palette[color].darkChannel = decomposeColor(colors.dark).values.join(' '); + } + }); + colorSchemes[key] = { palette }; + }); + const palette = createPalette({}); + const systemTheme = systemCreateTheme(options); + const opacity = { + active: 0.54, + hover: 0.04, + selected: 0.08, + disabled: 0.26, + focus: 0.12, + ...opacityInput, + }; + + let muiTheme = deepmerge(systemTheme, { + mixins: createMixins(systemTheme.breakpoints, systemTheme.spacing, 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 }, + colorSchemes, + opacity, + }); + + muiTheme = deepmerge(muiTheme, other); + muiTheme = args.reduce((acc, argument) => deepmerge(acc, argument), muiTheme); + + if (process.env.NODE_ENV !== 'production') { + 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, no-restricted-syntax + 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); + } + }); + } + + 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; From 37bda7face0a149254060653c71e655af0b10c65 Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Tue, 8 Mar 2022 16:48:12 +0100 Subject: [PATCH 26/50] Small fixes, create the typography in the CssVarsProvider --- .../css-variables-custom-theme.tsx | 28 +++++++++++++++++++ .../src/styles/CssVarsProvider.tsx | 10 ++++++- .../src/styles/unstable_createTheme.js | 25 +++++++++-------- 3 files changed, 50 insertions(+), 13 deletions(-) diff --git a/docs/pages/experiments/material-ui/css-variables-custom-theme.tsx b/docs/pages/experiments/material-ui/css-variables-custom-theme.tsx index 60d16912393ecf..c78d4b827f7878 100644 --- a/docs/pages/experiments/material-ui/css-variables-custom-theme.tsx +++ b/docs/pages/experiments/material-ui/css-variables-custom-theme.tsx @@ -9,6 +9,7 @@ import { import Moon from '@mui/icons-material/DarkMode'; import Sun from '@mui/icons-material/LightMode'; import Button from '@mui/material/Button'; +import Chip from '@mui/material/Chip'; import Box from '@mui/material/Box'; import { teal, deepOrange, orange, cyan } from '@mui/material/colors'; @@ -146,6 +147,33 @@ export default function Page() { + + + + + + + + + + + + + + + + + + + + + + + + + + + ); } diff --git a/packages/mui-material/src/styles/CssVarsProvider.tsx b/packages/mui-material/src/styles/CssVarsProvider.tsx index ae30f7111a2c70..6532abd276588a 100644 --- a/packages/mui-material/src/styles/CssVarsProvider.tsx +++ b/packages/mui-material/src/styles/CssVarsProvider.tsx @@ -1,6 +1,7 @@ import { unstable_createCssVarsProvider as createCssVarsProvider } from '@mui/system'; import createTheme, { Theme } from './createTheme'; import { PaletteWithChannels } from './createPalette'; +import createTypography from './createTypography'; export interface ThemeInput extends Theme { colorSchemes: Partial< @@ -23,7 +24,6 @@ const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssV theme: { ...defaultTheme, colorSchemes: { - // TODO: Shuold we remove the non color scheme values from here, like getContrastText, contrastThreshold etc. light: { palette: lightPalette }, dark: { palette: darkPalette }, }, @@ -33,6 +33,14 @@ const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssV dark: 'dark', }, prefix: 'md', + resolveTheme: (theme) => { + const newTheme = { + ...theme, + typography: createTypography(theme.palette, theme.typography), + }; + + return newTheme; + }, shouldSkipGeneratingVar: (keys) => !!keys[0].match(/(typography|mixins|breakpoints|direction|transitions)/), }); diff --git a/packages/mui-material/src/styles/unstable_createTheme.js b/packages/mui-material/src/styles/unstable_createTheme.js index 1fecec3cdbc7a9..5cd6133ee5227e 100644 --- a/packages/mui-material/src/styles/unstable_createTheme.js +++ b/packages/mui-material/src/styles/unstable_createTheme.js @@ -4,7 +4,6 @@ import { createTheme as systemCreateTheme, decomposeColor } from '@mui/system'; import createThemeWithoutVars from './createTheme'; import createMixins from './createMixins'; import createPalette from './createPalette'; -import createTypography from './createTypography'; import shadows from './shadows'; import createTransitions from './createTransitions'; import zIndex from './zIndex'; @@ -17,7 +16,6 @@ function createTheme(options = {}, ...args) { breakpoints: breakpointsInput, mixins: mixinsInput = {}, spacing: spacingInput, - // palette: paletteInput = {}, colorSchemes: colorSchemesInput = {}, transitions: transitionsInput = {}, typography: typographyInput = {}, @@ -26,13 +24,15 @@ function createTheme(options = {}, ...args) { ...other } = options; - const colorSchemesInitial = deepmerge( - { - light: { palette: lightPalette }, - dark: { palette: darkPalette }, - }, - colorSchemesInput, - ); + const colorSchemesInitial = colorSchemesInput; + + if (!colorSchemesInitial.light) { + colorSchemesInitial.light = { palette: lightPalette }; + } + + if (!colorSchemesInitial.dark) { + colorSchemesInitial.dark = { palette: darkPalette }; + } const colorSchemes = {}; @@ -54,7 +54,7 @@ function createTheme(options = {}, ...args) { }); colorSchemes[key] = { palette }; }); - const palette = createPalette({}); + const systemTheme = systemCreateTheme(options); const opacity = { active: 0.54, @@ -67,10 +67,11 @@ function createTheme(options = {}, ...args) { let muiTheme = deepmerge(systemTheme, { mixins: createMixins(systemTheme.breakpoints, systemTheme.spacing, 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), + // TODO: At this moment this is not processed, as we need to know the color scheme + // which is not part of the CssVarsProvider + typography: typographyInput, transitions: createTransitions(transitionsInput), zIndex: { ...zIndex }, colorSchemes, From b159c333b147e006ab3329f7d24fbcebb9cf935a Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Wed, 9 Mar 2022 11:09:30 +0100 Subject: [PATCH 27/50] Improve the createTheme func, fix some channels generation, fix some button colors --- .../css-variables-custom-theme.tsx | 249 +++++++++--------- packages/mui-material/src/Button/Button.js | 11 +- .../src/styles/unstable_createTheme.js | 158 +++-------- .../mui-system/src/cssVars/cssVarsParser.ts | 4 + 4 files changed, 167 insertions(+), 255 deletions(-) diff --git a/docs/pages/experiments/material-ui/css-variables-custom-theme.tsx b/docs/pages/experiments/material-ui/css-variables-custom-theme.tsx index c78d4b827f7878..57abc985485df1 100644 --- a/docs/pages/experiments/material-ui/css-variables-custom-theme.tsx +++ b/docs/pages/experiments/material-ui/css-variables-custom-theme.tsx @@ -1,11 +1,5 @@ import * as React from 'react'; -import { - CssVarsProvider, - useColorScheme, - unstable_createTheme, - alpha, - darken, -} from '@mui/material/styles'; +import { CssVarsProvider, useColorScheme, unstable_createTheme } from '@mui/material/styles'; import Moon from '@mui/icons-material/DarkMode'; import Sun from '@mui/icons-material/LightMode'; import Button from '@mui/material/Button'; @@ -59,119 +53,136 @@ const theme = unstable_createTheme({ export default function Page() { return ( - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/mui-material/src/Button/Button.js b/packages/mui-material/src/Button/Button.js index 89586902903871..8b19b258b60318 100644 --- a/packages/mui-material/src/Button/Button.js +++ b/packages/mui-material/src/Button/Button.js @@ -88,9 +88,8 @@ const ButtonRoot = styled(ButtonBase, { ), '&:hover': { textDecoration: 'none', - // backgroundColor: alpha(theme.palette.text.primary, theme.palette.action.hoverOpacity), backgroundColor: theme.vars - ? `rgba(0,0,0,${theme.vars.opacity?.hover})` + ? `rgba(${theme.vars.palette.text.primaryChannel} / ${theme.vars.opacity?.hover})` : alpha(theme.palette.text.primary, theme.palette.action.hoverOpacity), // Reset on touch devices, it doesn't add specificity '@media (hover: none)': { @@ -98,10 +97,6 @@ const ButtonRoot = styled(ButtonBase, { }, ...(ownerState.variant === 'text' && ownerState.color !== 'inherit' && { - // backgroundColor: alpha( - // theme.palette[ownerState.color].main, - // theme.palette.action.hoverOpacity, - // ), backgroundColor: theme.vars ? `rgba(${theme.vars.palette[ownerState.color].mainChannel} / ${ theme.vars.opacity?.hover @@ -115,10 +110,6 @@ const ButtonRoot = styled(ButtonBase, { ...(ownerState.variant === 'outlined' && ownerState.color !== 'inherit' && { border: `1px solid ${(theme.vars || theme).palette[ownerState.color].main}`, - // backgroundColor: alpha( - // theme.palette[ownerState.color].main, - // theme.palette.action.hoverOpacity, - // ), backgroundColor: theme.vars ? `rgba(${theme.vars.palette[ownerState.color].mainChannel} / ${ theme.vars.opacity?.hover diff --git a/packages/mui-material/src/styles/unstable_createTheme.js b/packages/mui-material/src/styles/unstable_createTheme.js index 5cd6133ee5227e..57524454b6ec01 100644 --- a/packages/mui-material/src/styles/unstable_createTheme.js +++ b/packages/mui-material/src/styles/unstable_createTheme.js @@ -1,61 +1,57 @@ import { deepmerge } from '@mui/utils'; -import { generateUtilityClass } from '@mui/base'; -import { createTheme as systemCreateTheme, decomposeColor } from '@mui/system'; +import { decomposeColor } from '@mui/system'; import createThemeWithoutVars from './createTheme'; -import createMixins from './createMixins'; import createPalette from './createPalette'; -import shadows from './shadows'; -import createTransitions from './createTransitions'; -import zIndex from './zIndex'; - -const { palette: lightPalette } = createThemeWithoutVars(); -const { palette: darkPalette } = createThemeWithoutVars({ palette: { mode: 'dark' } }); function createTheme(options = {}, ...args) { - const { - breakpoints: breakpointsInput, - mixins: mixinsInput = {}, - spacing: spacingInput, - colorSchemes: colorSchemesInput = {}, - transitions: transitionsInput = {}, - typography: typographyInput = {}, - shape: shapeInput, - opacity: opacityInput = {}, - ...other - } = options; - - const colorSchemesInitial = colorSchemesInput; + const { colorSchemes: colorSchemesInput = {}, opacity: opacityInput = {}, ...input } = options; - if (!colorSchemesInitial.light) { - colorSchemesInitial.light = { palette: lightPalette }; - } + let { palette: lightPalette, ...muiTheme } = createThemeWithoutVars({ + ...input, + ...(colorSchemesInput.light && { palette: colorSchemesInput.light.palette }), + }); + const { palette: darkPalette } = createThemeWithoutVars({ + palette: { mode: 'dark', ...colorSchemesInput.dark?.palette }, + }); - if (!colorSchemesInitial.dark) { - colorSchemesInitial.dark = { palette: darkPalette }; - } + colorSchemesInput.light = { palette: lightPalette }; + colorSchemesInput.dark = { palette: darkPalette }; const colorSchemes = {}; - Object.keys(colorSchemesInitial).forEach((key) => { - const palette = createPalette(colorSchemesInitial[key].palette); + Object.keys(colorSchemesInput).forEach((key) => { + const palette = createPalette(colorSchemesInput[key].palette); Object.keys(palette).forEach((color) => { const colors = palette[color]; if (colors.main) { - palette[color].mainChannel = decomposeColor(colors.main).values.join(' '); + palette[color].mainChannel = decomposeColor(colors.main).values.slice(0, 3).join(' '); } if (colors.light) { - palette[color].lightChannel = decomposeColor(colors.light).values.join(' '); + palette[color].lightChannel = decomposeColor(colors.light).values.slice(0, 3).join(' '); } if (colors.dark) { - palette[color].darkChannel = decomposeColor(colors.dark).values.join(' '); + palette[color].darkChannel = decomposeColor(colors.dark).values.slice(0, 3).join(' '); + } + if (colors.primary) { + palette[color].primaryChannel = decomposeColor(colors.primary).values.slice(0, 3).join(' '); + } + if (colors.secondary) { + palette[color].secondaryChannel = decomposeColor(colors.secondary) + .values.slice(0, 3) + .join(' '); + } + if (colors.disabled) { + palette[color].disabledChannel = decomposeColor(colors.disabled) + .values.slice(0, 3) + .join(' '); } }); + colorSchemes[key] = { palette }; }); - const systemTheme = systemCreateTheme(options); const opacity = { active: 0.54, hover: 0.04, @@ -65,102 +61,12 @@ function createTheme(options = {}, ...args) { ...opacityInput, }; - let muiTheme = deepmerge(systemTheme, { - mixins: createMixins(systemTheme.breakpoints, systemTheme.spacing, mixinsInput), - // Don't use [...shadows] until you've verified its transpiled code is not invoking the iterator protocol. - shadows: shadows.slice(), - // TODO: At this moment this is not processed, as we need to know the color scheme - // which is not part of the CssVarsProvider - typography: typographyInput, - transitions: createTransitions(transitionsInput), - zIndex: { ...zIndex }, - colorSchemes, - opacity, - }); + muiTheme.colorSchemes = colorSchemes; + muiTheme.opacity = opacity; - muiTheme = deepmerge(muiTheme, other); muiTheme = args.reduce((acc, argument) => deepmerge(acc, argument), muiTheme); - if (process.env.NODE_ENV !== 'production') { - 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, no-restricted-syntax - 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); - } - }); - } - 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-system/src/cssVars/cssVarsParser.ts b/packages/mui-system/src/cssVars/cssVarsParser.ts index 5ee34b5a95319d..9e55ca6af362a4 100644 --- a/packages/mui-system/src/cssVars/cssVarsParser.ts +++ b/packages/mui-system/src/cssVars/cssVarsParser.ts @@ -77,6 +77,10 @@ const getCssValue = (keys: string[], value: string | number) => { // CSS property that are unitless return value; } + if (keys[keys.length - 1].indexOf('Channel') !== -1) { + // the channels are unitless too + return value; + } return `${value}px`; } return value; From 3ea304ebb86cc5e2a2325e3f03937f3424ce1020 Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Wed, 9 Mar 2022 13:59:46 +0100 Subject: [PATCH 28/50] Some fixes --- .../material-ui/css-variables-custom-theme.tsx | 8 ++++---- packages/mui-material/src/styles/createPalette.js | 2 +- .../mui-material/src/styles/unstable_createTheme.d.ts | 1 + packages/mui-material/src/styles/unstable_createTheme.js | 1 + 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/pages/experiments/material-ui/css-variables-custom-theme.tsx b/docs/pages/experiments/material-ui/css-variables-custom-theme.tsx index 57abc985485df1..b4a86b2926c8b0 100644 --- a/docs/pages/experiments/material-ui/css-variables-custom-theme.tsx +++ b/docs/pages/experiments/material-ui/css-variables-custom-theme.tsx @@ -129,19 +129,19 @@ export default function Page() { Text diff --git a/packages/mui-material/src/styles/createPalette.js b/packages/mui-material/src/styles/createPalette.js index d587b9a276c6a1..a36f716d733aa0 100644 --- a/packages/mui-material/src/styles/createPalette.js +++ b/packages/mui-material/src/styles/createPalette.js @@ -224,7 +224,7 @@ export default function createPalette(palette) { if (!color.hasOwnProperty('main')) { throw new MuiError( - 'MUI: The color %s provided to augmentColor(color) is invalid.\n' + + 'MUI: The color%s provided to augmentColor(color) is invalid.\n' + 'The color object needs to have a `main` property or a `%s` property.', name ? ` (${name})` : '', mainShade, diff --git a/packages/mui-material/src/styles/unstable_createTheme.d.ts b/packages/mui-material/src/styles/unstable_createTheme.d.ts index aa7a96b9e5e08e..2d507c1fd4f884 100644 --- a/packages/mui-material/src/styles/unstable_createTheme.d.ts +++ b/packages/mui-material/src/styles/unstable_createTheme.d.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/naming-convention */ import { ThemeOptions as SystemThemeOptions, Theme as SystemTheme } from '@mui/system'; import { Mixins, MixinsOptions } from './createMixins'; import { Palette, PaletteOptions } from './createPalette'; diff --git a/packages/mui-material/src/styles/unstable_createTheme.js b/packages/mui-material/src/styles/unstable_createTheme.js index 57524454b6ec01..0d9309614d88be 100644 --- a/packages/mui-material/src/styles/unstable_createTheme.js +++ b/packages/mui-material/src/styles/unstable_createTheme.js @@ -6,6 +6,7 @@ import createPalette from './createPalette'; function createTheme(options = {}, ...args) { const { colorSchemes: colorSchemesInput = {}, opacity: opacityInput = {}, ...input } = options; + // eslint-disable-next-line prefer-const let { palette: lightPalette, ...muiTheme } = createThemeWithoutVars({ ...input, ...(colorSchemesInput.light && { palette: colorSchemesInput.light.palette }), From 86d9665cabfc9f54888b9fd1235e826926116080 Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Wed, 9 Mar 2022 14:08:06 +0100 Subject: [PATCH 29/50] Fix TS issue --- packages/mui-material/src/styles/CssVarsProvider.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/mui-material/src/styles/CssVarsProvider.tsx b/packages/mui-material/src/styles/CssVarsProvider.tsx index 6532abd276588a..25daef37a0ed4d 100644 --- a/packages/mui-material/src/styles/CssVarsProvider.tsx +++ b/packages/mui-material/src/styles/CssVarsProvider.tsx @@ -1,9 +1,9 @@ import { unstable_createCssVarsProvider as createCssVarsProvider } from '@mui/system'; -import createTheme, { Theme } from './createTheme'; +import createTheme, { ThemeOptions } from './createTheme'; import { PaletteWithChannels } from './createPalette'; import createTypography from './createTypography'; -export interface ThemeInput extends Theme { +export interface ThemeInput extends ThemeOptions { colorSchemes: Partial< Record< 'light' | 'dark', From 3e104159ed06df45e974cd7afeb03c5e777cd1d6 Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Wed, 9 Mar 2022 16:09:48 +0100 Subject: [PATCH 30/50] Fix the types --- packages/mui-material/src/styles/CssVarsProvider.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/mui-material/src/styles/CssVarsProvider.tsx b/packages/mui-material/src/styles/CssVarsProvider.tsx index 25daef37a0ed4d..340d1cc9c9d547 100644 --- a/packages/mui-material/src/styles/CssVarsProvider.tsx +++ b/packages/mui-material/src/styles/CssVarsProvider.tsx @@ -1,5 +1,6 @@ import { unstable_createCssVarsProvider as createCssVarsProvider } from '@mui/system'; -import createTheme, { ThemeOptions } from './createTheme'; +import createTheme from './createTheme'; +import { ThemeOptions } from './unstable_createTheme'; import { PaletteWithChannels } from './createPalette'; import createTypography from './createTypography'; From cff193ffed7856a9dff3bf7d3048c94abaee67b0 Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Tue, 15 Mar 2022 14:14:23 +0100 Subject: [PATCH 31/50] Some TS fixes --- .../src/styles/CssVarsProvider.tsx | 7 +++-- .../src/styles/unstable_createTheme.d.ts | 28 ++++++++++++++++++- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/packages/mui-material/src/styles/CssVarsProvider.tsx b/packages/mui-material/src/styles/CssVarsProvider.tsx index 340d1cc9c9d547..7947f1da35ce6a 100644 --- a/packages/mui-material/src/styles/CssVarsProvider.tsx +++ b/packages/mui-material/src/styles/CssVarsProvider.tsx @@ -1,13 +1,13 @@ import { unstable_createCssVarsProvider as createCssVarsProvider } from '@mui/system'; import createTheme from './createTheme'; -import { ThemeOptions } from './unstable_createTheme'; +import { ThemeOptions, SupportedColorScheme } from './unstable_createTheme'; import { PaletteWithChannels } from './createPalette'; import createTypography from './createTypography'; -export interface ThemeInput extends ThemeOptions { +export interface ThemeInput extends Omit { colorSchemes: Partial< Record< - 'light' | 'dark', + SupportedColorScheme, { palette: PaletteWithChannels; } @@ -16,6 +16,7 @@ export interface ThemeInput extends ThemeOptions { } const { palette: lightPalette, ...defaultTheme } = createTheme(); +// @ts-ignore conflicts with textFieldCustomProps.tsconfig.json const { palette: darkPalette } = createTheme({ palette: { mode: 'dark' } }); const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssVarsProvider< diff --git a/packages/mui-material/src/styles/unstable_createTheme.d.ts b/packages/mui-material/src/styles/unstable_createTheme.d.ts index 2d507c1fd4f884..9162a51157ea85 100644 --- a/packages/mui-material/src/styles/unstable_createTheme.d.ts +++ b/packages/mui-material/src/styles/unstable_createTheme.d.ts @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { ThemeOptions as SystemThemeOptions, Theme as SystemTheme } from '@mui/system'; +import { OverridableStringUnion } from '@mui/types'; import { Mixins, MixinsOptions } from './createMixins'; import { Palette, PaletteOptions } from './createPalette'; import { Typography, TypographyOptions } from './createTypography'; @@ -8,11 +9,36 @@ import { Transitions, TransitionsOptions } from './createTransitions'; import { ZIndex, ZIndexOptions } 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 ThemeOptions extends Omit { mixins?: MixinsOptions; components?: Components; // palette?: PaletteOptions; - colorSchemes?: Record; + colorSchemes?: Record; shadows?: Shadows; transitions?: TransitionsOptions; typography?: TypographyOptions | ((palette: Palette) => TypographyOptions); From 91d9995a990894ffa5919c0f979cc0cc1bab3e6c Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Tue, 15 Mar 2022 15:27:04 +0100 Subject: [PATCH 32/50] Types improvements --- .../src/styles/CssVarsProvider.d.ts | 22 ++++++++++ ...CssVarsProvider.tsx => CssVarsProvider.js} | 19 +------- .../src/cssVars/createCssVarsProvider.d.ts | 44 ++++++++++--------- packages/mui-system/src/cssVars/index.ts | 1 + packages/mui-system/src/index.d.ts | 2 +- 5 files changed, 48 insertions(+), 40 deletions(-) create mode 100644 packages/mui-material/src/styles/CssVarsProvider.d.ts rename packages/mui-material/src/styles/{CssVarsProvider.tsx => CssVarsProvider.js} (67%) diff --git a/packages/mui-material/src/styles/CssVarsProvider.d.ts b/packages/mui-material/src/styles/CssVarsProvider.d.ts new file mode 100644 index 00000000000000..cf787adfeccb05 --- /dev/null +++ b/packages/mui-material/src/styles/CssVarsProvider.d.ts @@ -0,0 +1,22 @@ +import { CreateCssVarsProviderResult } from '@mui/system'; +import { ThemeOptions, SupportedColorScheme } from './unstable_createTheme'; +import { PaletteWithChannels } from './createPalette'; + +export interface ThemeInput extends Omit { + colorSchemes: Partial< + Record< + SupportedColorScheme, + { + palette: PaletteWithChannels; + } + > + >; +} + +type MDCreateCssVarsProviderResult = CreateCssVarsProviderResult; + +type useColorScheme = MDCreateCssVarsProviderResult['useColorScheme']; +type getInitColorSchemeScript = MDCreateCssVarsProviderResult['getInitColorSchemeScript']; +type CssVarsProvider = MDCreateCssVarsProviderResult['CssVarsProvider']; + +export { useColorScheme, getInitColorSchemeScript, CssVarsProvider }; diff --git a/packages/mui-material/src/styles/CssVarsProvider.tsx b/packages/mui-material/src/styles/CssVarsProvider.js similarity index 67% rename from packages/mui-material/src/styles/CssVarsProvider.tsx rename to packages/mui-material/src/styles/CssVarsProvider.js index 7947f1da35ce6a..fa12ce48eed747 100644 --- a/packages/mui-material/src/styles/CssVarsProvider.tsx +++ b/packages/mui-material/src/styles/CssVarsProvider.js @@ -1,28 +1,11 @@ import { unstable_createCssVarsProvider as createCssVarsProvider } from '@mui/system'; import createTheme from './createTheme'; -import { ThemeOptions, SupportedColorScheme } from './unstable_createTheme'; -import { PaletteWithChannels } from './createPalette'; import createTypography from './createTypography'; -export interface ThemeInput extends Omit { - colorSchemes: Partial< - Record< - SupportedColorScheme, - { - palette: PaletteWithChannels; - } - > - >; -} - const { palette: lightPalette, ...defaultTheme } = createTheme(); -// @ts-ignore conflicts with textFieldCustomProps.tsconfig.json const { palette: darkPalette } = createTheme({ palette: { mode: 'dark' } }); -const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssVarsProvider< - 'light' | 'dark', - ThemeInput ->({ +const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssVarsProvider({ theme: { ...defaultTheme, colorSchemes: { diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts b/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts index 9cf05540ea01c3..20bcb3a3749659 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.d.ts @@ -36,6 +36,28 @@ export interface CssVarsProviderConfig { prefix?: string; } +export interface CreateCssVarsProviderResult { + CssVarsProvider: ( + props: React.PropsWithChildren< + Partial> & { + theme?: ThemeInput; + /** + * localStorage key used to store application `mode` + * @default 'mui-mode' + */ + modeStorageKey?: string; + /** + * DOM attribute for applying color scheme + * @default 'data-mui-color-scheme' + */ + attribute?: string; + } + >, + ) => React.ReactElement; + useColorScheme: () => ColorSchemeContextValue; + getInitColorSchemeScript: typeof getInitColorSchemeScript; +} + export default function createCssVarsProvider< ColorScheme extends string, ThemeInput extends { colorSchemes?: Partial> }, @@ -83,27 +105,7 @@ export default function createCssVarsProvider< */ resolveTheme?: (theme: any) => any; // the type is any because it depends on the design system. }, -): { - CssVarsProvider: ( - props: React.PropsWithChildren< - Partial> & { - theme?: ThemeInput; - /** - * localStorage key used to store application `mode` - * @default 'mui-mode' - */ - modeStorageKey?: string; - /** - * DOM attribute for applying color scheme - * @default 'data-mui-color-scheme' - */ - attribute?: string; - } - >, - ) => React.ReactElement; - useColorScheme: () => ColorSchemeContextValue; - getInitColorSchemeScript: typeof getInitColorSchemeScript; -}; +): CreateCssVarsProviderResult; // disable automatic export export {}; diff --git a/packages/mui-system/src/cssVars/index.ts b/packages/mui-system/src/cssVars/index.ts index 8e24f2897db82d..87925a74d621eb 100644 --- a/packages/mui-system/src/cssVars/index.ts +++ b/packages/mui-system/src/cssVars/index.ts @@ -1 +1,2 @@ export { default } from './createCssVarsProvider'; +export type { CreateCssVarsProviderResult } from './createCssVarsProvider'; diff --git a/packages/mui-system/src/index.d.ts b/packages/mui-system/src/index.d.ts index 36dea68c8ae745..582cc491a43779 100644 --- a/packages/mui-system/src/index.d.ts +++ b/packages/mui-system/src/index.d.ts @@ -162,6 +162,6 @@ export * from './colorManipulator'; export { default as ThemeProvider } from './ThemeProvider'; export * from './ThemeProvider'; -export { default as unstable_createCssVarsProvider } from './cssVars'; +export { default as unstable_createCssVarsProvider, CreateCssVarsProviderResult } from './cssVars'; export { default as unstable_createGetCssVar } from './cssVars/createGetCssVar'; export * from './cssVars'; From f5021023ee0a47ccea2c00d91346bc47389dab11 Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Tue, 15 Mar 2022 15:41:01 +0100 Subject: [PATCH 33/50] Fix build API script --- docs/scripts/buildApi.ts | 3 ++- packages/mui-material/src/styles/CssVarsProvider.d.ts | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/scripts/buildApi.ts b/docs/scripts/buildApi.ts index 68e19209643186..e7dc5610d0ecdf 100644 --- a/docs/scripts/buildApi.ts +++ b/docs/scripts/buildApi.ts @@ -190,7 +190,8 @@ async function run(argv: CommandOptions) { return directories.concat(findComponents(componentDirectory)); }, [] as ReadonlyArray<{ filename: string }>) .filter((component) => { - if (component.filename.includes('ThemeProvider')) { + console.log(component.filename) + if (component.filename.includes('ThemeProvider') || (component.filename.includes('mui-material') && component.filename.includes('CssVarsProvider'))) { return false; } if (grep === null) { diff --git a/packages/mui-material/src/styles/CssVarsProvider.d.ts b/packages/mui-material/src/styles/CssVarsProvider.d.ts index cf787adfeccb05..d68993c54ef43c 100644 --- a/packages/mui-material/src/styles/CssVarsProvider.d.ts +++ b/packages/mui-material/src/styles/CssVarsProvider.d.ts @@ -17,6 +17,11 @@ type MDCreateCssVarsProviderResult = CreateCssVarsProviderResult Date: Tue, 15 Mar 2022 16:15:42 +0100 Subject: [PATCH 34/50] More fixes --- docs/scripts/buildApi.ts | 7 +++++-- packages/mui-material/src/styles/CssVarsProvider.d.ts | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/scripts/buildApi.ts b/docs/scripts/buildApi.ts index e7dc5610d0ecdf..0df4bda370a9d6 100644 --- a/docs/scripts/buildApi.ts +++ b/docs/scripts/buildApi.ts @@ -190,8 +190,11 @@ async function run(argv: CommandOptions) { return directories.concat(findComponents(componentDirectory)); }, [] as ReadonlyArray<{ filename: string }>) .filter((component) => { - console.log(component.filename) - if (component.filename.includes('ThemeProvider') || (component.filename.includes('mui-material') && component.filename.includes('CssVarsProvider'))) { + if ( + component.filename.includes('ThemeProvider') || + (component.filename.includes('mui-material') && + component.filename.includes('CssVarsProvider')) + ) { return false; } if (grep === null) { diff --git a/packages/mui-material/src/styles/CssVarsProvider.d.ts b/packages/mui-material/src/styles/CssVarsProvider.d.ts index d68993c54ef43c..2e7947d7902a28 100644 --- a/packages/mui-material/src/styles/CssVarsProvider.d.ts +++ b/packages/mui-material/src/styles/CssVarsProvider.d.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/naming-convention */ import { CreateCssVarsProviderResult } from '@mui/system'; import { ThemeOptions, SupportedColorScheme } from './unstable_createTheme'; import { PaletteWithChannels } from './createPalette'; @@ -24,4 +25,4 @@ type getInitColorSchemeScript = MDCreateCssVarsProviderResult['getInitColorSchem */ type CssVarsProvider = MDCreateCssVarsProviderResult['CssVarsProvider']; -export { useColorScheme, getInitColorSchemeScript }; +export { useColorScheme, getInitColorSchemeScript, CssVarsProvider }; From 718108819a0dcb43ea7cca66924bfd88cb3811ad Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Tue, 15 Mar 2022 16:58:31 +0100 Subject: [PATCH 35/50] Fix CI --- packages/mui-material/src/styles/CssVarsProvider.d.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/mui-material/src/styles/CssVarsProvider.d.ts b/packages/mui-material/src/styles/CssVarsProvider.d.ts index 2e7947d7902a28..7b947cb3686c26 100644 --- a/packages/mui-material/src/styles/CssVarsProvider.d.ts +++ b/packages/mui-material/src/styles/CssVarsProvider.d.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import { CreateCssVarsProviderResult } from '@mui/system'; import { ThemeOptions, SupportedColorScheme } from './unstable_createTheme'; import { PaletteWithChannels } from './createPalette'; @@ -16,13 +15,13 @@ export interface ThemeInput extends Omit { type MDCreateCssVarsProviderResult = CreateCssVarsProviderResult; -type useColorScheme = MDCreateCssVarsProviderResult['useColorScheme']; -type getInitColorSchemeScript = MDCreateCssVarsProviderResult['getInitColorSchemeScript']; +declare const useColorScheme: MDCreateCssVarsProviderResult['useColorScheme']; +declare const getInitColorSchemeScript: MDCreateCssVarsProviderResult['getInitColorSchemeScript']; /** * This component is an experimental Theme Provider that generates CSS variabels out of the theme tokens. * It should preferably be used at **the root of your component tree**. */ -type CssVarsProvider = MDCreateCssVarsProviderResult['CssVarsProvider']; +declare const CssVarsProvider: MDCreateCssVarsProviderResult['CssVarsProvider']; export { useColorScheme, getInitColorSchemeScript, CssVarsProvider }; From 8733e6cbe03ea8848cb88666f5d919c725a10aee Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Tue, 15 Mar 2022 17:37:31 +0100 Subject: [PATCH 36/50] Try demos using CSS Variables (to be reverted) --- docs/src/modules/components/DemoSandboxed.js | 73 ++++++++++++++++---- 1 file changed, 61 insertions(+), 12 deletions(-) diff --git a/docs/src/modules/components/DemoSandboxed.js b/docs/src/modules/components/DemoSandboxed.js index 5eb3abb65ea44f..2a5970c247ec40 100644 --- a/docs/src/modules/components/DemoSandboxed.js +++ b/docs/src/modules/components/DemoSandboxed.js @@ -9,7 +9,15 @@ import createCache from '@emotion/cache'; import { CacheProvider } from '@emotion/react'; import { StyleSheetManager } from 'styled-components'; import { jssPreset, StylesProvider } from '@mui/styles'; -import { useTheme, styled, createTheme, ThemeProvider } from '@mui/material/styles'; +import { + useTheme, + styled, + createTheme, + ThemeProvider, + useColorScheme, + unstable_createTheme, + CssVarsProvider, +} from '@mui/material/styles'; import rtl from 'jss-rtl'; import DemoErrorBoundary from 'docs/src/modules/components/DemoErrorBoundary'; import { useTranslate } from 'docs/src/modules/utils/i18n'; @@ -126,21 +134,47 @@ const getTheme = (outerTheme) => { const isCustomized = outerTheme.palette.primary?.main && outerTheme.palette.primary.main !== brandingDesignTokens.palette.primary.main; - const resultTheme = createTheme( + // const resultTheme = createTheme( + // { + // palette: { + // mode: outerTheme.palette.mode || 'light', + // ...(isCustomized && { + // // Apply color from the color playground + // primary: { main: outerTheme.palette.primary.main }, + // secondary: { main: outerTheme.palette.secondary.main }, + // }), + // }, + // }, + // // To make DensityTool playground works + // // check from MuiFormControl because brandingTheme does not customize this component + // outerTheme.components?.MuiFormControl?.defaultProps?.margin === 'dense' ? highDensity : {}, + // ); + + const resultTheme = unstable_createTheme( { - palette: { - mode: outerTheme.palette.mode || 'light', - ...(isCustomized && { - // Apply color from the color playground - primary: { main: outerTheme.palette.primary.main }, - secondary: { main: outerTheme.palette.secondary.main }, - }), - }, + ...(isCustomized && { + colorSchemes: { + light: { + palette: { + primary: { main: outerTheme.palette.primary.main }, + secondary: { main: outerTheme.palette.secondary.main }, + }, + }, + dark: { + palette: { + // Apply color from the color playground + primary: { main: outerTheme.palette.primary.main }, + secondary: { main: outerTheme.palette.secondary.main }, + }, + }, + }, + }), }, // To make DensityTool playground works // check from MuiFormControl because brandingTheme does not customize this component outerTheme.components?.MuiFormControl?.defaultProps?.margin === 'dense' ? highDensity : {}, ); + if (outerTheme.direction) { resultTheme.direction = outerTheme.direction; } @@ -157,6 +191,15 @@ const jss = create({ typeof window !== 'undefined' ? document.querySelector('#insertion-point-jss') : null, }); +const ColorSchemeSetter = ({ mode: inputMode }) => { + const { mode, setMode } = useColorScheme(); + + React.useEffect(() => { + setMode(inputMode); + }, [inputMode]); + return null; +}; + /** * Isolates the demo component as best as possible. Additional props are spread * to an `iframe` if `iframe={true}`. @@ -168,15 +211,21 @@ function DemoSandboxed(props) { const t = useTranslate(); + const outerTheme = useTheme(); + const outerThemeMode = outerTheme.palette.mode === 'dark' ? 'dark' : 'light'; + + const theme = getTheme(outerTheme); + return ( - getTheme(outerTheme)}> + + {/* WARNING: `` needs to be a child of `Sandbox` since certain implementations rely on `cloneElement` */} - + ); From 11fe02061106b20c506f79736c32a9962ea8d191 Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Tue, 15 Mar 2022 17:58:58 +0100 Subject: [PATCH 37/50] Fix netlify build --- docs/data/material/customization/palette/palette.md | 6 ++++-- docs/src/modules/components/DemoSandboxed.js | 7 +++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/data/material/customization/palette/palette.md b/docs/data/material/customization/palette/palette.md index 27159fc04de326..0b67b5f481d076 100644 --- a/docs/data/material/customization/palette/palette.md +++ b/docs/data/material/customization/palette/palette.md @@ -126,7 +126,8 @@ Note that "contrastThreshold" follows a non-linear curve. ### Example -{{"demo": "Palette.js", "defaultCodeOpen": true}} + + ### Adding new colors @@ -185,7 +186,8 @@ declare module '@mui/material/styles' { } ``` -{{"demo": "CustomColor.js"}} + + ## Picking colors diff --git a/docs/src/modules/components/DemoSandboxed.js b/docs/src/modules/components/DemoSandboxed.js index 2a5970c247ec40..9d0bc62b9db11a 100644 --- a/docs/src/modules/components/DemoSandboxed.js +++ b/docs/src/modules/components/DemoSandboxed.js @@ -12,8 +12,6 @@ import { jssPreset, StylesProvider } from '@mui/styles'; import { useTheme, styled, - createTheme, - ThemeProvider, useColorScheme, unstable_createTheme, CssVarsProvider, @@ -192,11 +190,12 @@ const jss = create({ }); const ColorSchemeSetter = ({ mode: inputMode }) => { - const { mode, setMode } = useColorScheme(); + const { setMode } = useColorScheme(); React.useEffect(() => { setMode(inputMode); - }, [inputMode]); + }, [inputMode, setMode]); + return null; }; From 9d8e060cf3b3d002c5f37680c93b06db684c2736 Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Wed, 16 Mar 2022 10:54:55 +0100 Subject: [PATCH 38/50] Some comments addressed --- .../src/styles/unstable_createTheme.js | 21 ++++++++++--------- .../mui-system/src/cssVars/cssVarsParser.ts | 4 ---- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/packages/mui-material/src/styles/unstable_createTheme.js b/packages/mui-material/src/styles/unstable_createTheme.js index 0d9309614d88be..487c7a4ff43baf 100644 --- a/packages/mui-material/src/styles/unstable_createTheme.js +++ b/packages/mui-material/src/styles/unstable_createTheme.js @@ -3,6 +3,11 @@ import { decomposeColor } from '@mui/system'; import createThemeWithoutVars from './createTheme'; import createPalette from './createPalette'; +export const createChannel = (color) => { + const decomposedColor = decomposeColor(color); + return decomposedColor.values.slice(0, 3).map((val, idx) => decomposedColor.type === 'hsl' && idx !== 0 ? `${val}%` : val).join(' '); +} + function createTheme(options = {}, ...args) { const { colorSchemes: colorSchemesInput = {}, opacity: opacityInput = {}, ...input } = options; @@ -27,26 +32,22 @@ function createTheme(options = {}, ...args) { const colors = palette[color]; if (colors.main) { - palette[color].mainChannel = decomposeColor(colors.main).values.slice(0, 3).join(' '); + palette[color].mainChannel = createChannel(colors.main); } if (colors.light) { - palette[color].lightChannel = decomposeColor(colors.light).values.slice(0, 3).join(' '); + palette[color].lightChannel = createChannel(colors.light); } if (colors.dark) { - palette[color].darkChannel = decomposeColor(colors.dark).values.slice(0, 3).join(' '); + palette[color].darkChannel = createChannel(colors.dark); } if (colors.primary) { - palette[color].primaryChannel = decomposeColor(colors.primary).values.slice(0, 3).join(' '); + palette[color].primaryChannel = createChannel(colors.primary); } if (colors.secondary) { - palette[color].secondaryChannel = decomposeColor(colors.secondary) - .values.slice(0, 3) - .join(' '); + palette[color].secondaryChannel = createChannel(colors.secondary); } if (colors.disabled) { - palette[color].disabledChannel = decomposeColor(colors.disabled) - .values.slice(0, 3) - .join(' '); + palette[color].disabledChannel = createChannel(colors.disabled); } }); diff --git a/packages/mui-system/src/cssVars/cssVarsParser.ts b/packages/mui-system/src/cssVars/cssVarsParser.ts index 9e55ca6af362a4..5ee34b5a95319d 100644 --- a/packages/mui-system/src/cssVars/cssVarsParser.ts +++ b/packages/mui-system/src/cssVars/cssVarsParser.ts @@ -77,10 +77,6 @@ const getCssValue = (keys: string[], value: string | number) => { // CSS property that are unitless return value; } - if (keys[keys.length - 1].indexOf('Channel') !== -1) { - // the channels are unitless too - return value; - } return `${value}px`; } return value; From 990c453247b1f30e24be21bd4bf0a80def9993a8 Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Wed, 16 Mar 2022 11:28:20 +0100 Subject: [PATCH 39/50] Move colorChannel to colorManipulator --- .../src/styles/unstable_createTheme.js | 19 +++++++------------ packages/mui-system/src/colorManipulator.d.ts | 1 + packages/mui-system/src/colorManipulator.js | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/packages/mui-material/src/styles/unstable_createTheme.js b/packages/mui-material/src/styles/unstable_createTheme.js index 487c7a4ff43baf..ed2ad09f7325ea 100644 --- a/packages/mui-material/src/styles/unstable_createTheme.js +++ b/packages/mui-material/src/styles/unstable_createTheme.js @@ -1,13 +1,8 @@ import { deepmerge } from '@mui/utils'; -import { decomposeColor } from '@mui/system'; +import { colorChannel } from '@mui/system'; import createThemeWithoutVars from './createTheme'; import createPalette from './createPalette'; -export const createChannel = (color) => { - const decomposedColor = decomposeColor(color); - return decomposedColor.values.slice(0, 3).map((val, idx) => decomposedColor.type === 'hsl' && idx !== 0 ? `${val}%` : val).join(' '); -} - function createTheme(options = {}, ...args) { const { colorSchemes: colorSchemesInput = {}, opacity: opacityInput = {}, ...input } = options; @@ -32,22 +27,22 @@ function createTheme(options = {}, ...args) { const colors = palette[color]; if (colors.main) { - palette[color].mainChannel = createChannel(colors.main); + palette[color].mainChannel = colorChannel(colors.main); } if (colors.light) { - palette[color].lightChannel = createChannel(colors.light); + palette[color].lightChannel = colorChannel(colors.light); } if (colors.dark) { - palette[color].darkChannel = createChannel(colors.dark); + palette[color].darkChannel = colorChannel(colors.dark); } if (colors.primary) { - palette[color].primaryChannel = createChannel(colors.primary); + palette[color].primaryChannel = colorChannel(colors.primary); } if (colors.secondary) { - palette[color].secondaryChannel = createChannel(colors.secondary); + palette[color].secondaryChannel = colorChannel(colors.secondary); } if (colors.disabled) { - palette[color].disabledChannel = createChannel(colors.disabled); + palette[color].disabledChannel = colorChannel(colors.disabled); } }); diff --git a/packages/mui-system/src/colorManipulator.d.ts b/packages/mui-system/src/colorManipulator.d.ts index 5f1dc06d9ef4b9..3fa5d630fe6bac 100644 --- a/packages/mui-system/src/colorManipulator.d.ts +++ b/packages/mui-system/src/colorManipulator.d.ts @@ -9,6 +9,7 @@ export function hexToRgb(hex: string): string; export function rgbToHex(color: string): string; export function hslToRgb(color: string): string; export function decomposeColor(color: string): ColorObject; +export function colorChannel(color: string): string; export function recomposeColor(color: ColorObject): string; export function getContrastRatio(foreground: string, background: string): number; export function getLuminance(color: string): number; diff --git a/packages/mui-system/src/colorManipulator.js b/packages/mui-system/src/colorManipulator.js index f8f292d59137f9..8db6f431b9866f 100644 --- a/packages/mui-system/src/colorManipulator.js +++ b/packages/mui-system/src/colorManipulator.js @@ -98,6 +98,20 @@ export function decomposeColor(color) { return { type, values, colorSpace }; } +/** + * Returns a channel created from the input color. + * + * @param {string} color - CSS color, i.e. one of: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla() + * @returns {string} - The channel for the color, that can be used in rgba or hsla colors + */ +export const colorChannel = (color) => { + const decomposedColor = decomposeColor(color); + return decomposedColor.values + .slice(0, 3) + .map((val, idx) => (decomposedColor.type === 'hsl' && idx !== 0 ? `${val}%` : val)) + .join(' '); +}; + /** * Converts a color object with type and values to a string. * @param {object} color - Decomposed color From d25444fe5ccb226bf658452c88d5bcd4235fb469 Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Wed, 16 Mar 2022 13:00:37 +0100 Subject: [PATCH 40/50] [tests] Added tests and fixed some bugs --- .../src/styles/CssVarsProvider.js | 2 + .../src/styles/CssVarsProvider.test.js | 300 ++++++++++++++++ .../src/styles/unstable_createTheme.js | 14 +- .../src/styles/unstable_createTheme.test.js | 320 ++++++++++++++++++ packages/mui-system/src/colorManipulator.js | 2 +- .../mui-system/src/colorManipulator.test.js | 33 +- .../src/cssVars/cssVarsParser.test.ts | 15 + 7 files changed, 679 insertions(+), 7 deletions(-) create mode 100644 packages/mui-material/src/styles/CssVarsProvider.test.js create mode 100644 packages/mui-material/src/styles/unstable_createTheme.test.js diff --git a/packages/mui-material/src/styles/CssVarsProvider.js b/packages/mui-material/src/styles/CssVarsProvider.js index fa12ce48eed747..3d48a81e57aee0 100644 --- a/packages/mui-material/src/styles/CssVarsProvider.js +++ b/packages/mui-material/src/styles/CssVarsProvider.js @@ -1,4 +1,5 @@ import { unstable_createCssVarsProvider as createCssVarsProvider } from '@mui/system'; +import { defaultOpacity } from './unstable_createTheme'; import createTheme from './createTheme'; import createTypography from './createTypography'; @@ -12,6 +13,7 @@ const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssV light: { palette: lightPalette }, dark: { palette: darkPalette }, }, + opacity: defaultOpacity, }, defaultColorScheme: { light: 'light', diff --git a/packages/mui-material/src/styles/CssVarsProvider.test.js b/packages/mui-material/src/styles/CssVarsProvider.test.js new file mode 100644 index 00000000000000..d5ba9016ab1a34 --- /dev/null +++ b/packages/mui-material/src/styles/CssVarsProvider.test.js @@ -0,0 +1,300 @@ +import * as React from 'react'; +import { expect } from 'chai'; +import { createRenderer, screen } from 'test/utils'; +import { + CssVarsProvider, + useTheme, +} from '@mui/material/styles'; + +describe('[Material UI] CssVarsProvider', () => { + let originalMatchmedia; + const { render } = createRenderer(); + const storage = {}; + beforeEach(() => { + originalMatchmedia = window.matchMedia; + // Create mocks of localStorage getItem and setItem functions + Object.defineProperty(global, 'localStorage', { + value: { + getItem: (key) => storage[key], + setItem: (key, value) => { + storage[key] = value; + }, + }, + configurable: true, + }); + window.matchMedia = () => ({ + addListener: () => {}, + removeListener: () => {}, + }); + }); + afterEach(() => { + window.matchMedia = originalMatchmedia; + }); + + describe('All CSS vars', () => { + it('palette', () => { + const Vars = () => { + const theme = useTheme(); + return ( +
+
{JSON.stringify(theme.vars.palette.primary)}
+
+ {JSON.stringify(theme.vars.palette.secondary)} +
+
{JSON.stringify(theme.vars.palette.error)}
+
{JSON.stringify(theme.vars.palette.info)}
+
{JSON.stringify(theme.vars.palette.success)}
+
{JSON.stringify(theme.vars.palette.warning)}
+
{JSON.stringify(theme.vars.palette.text)}
+
+ {JSON.stringify(theme.vars.palette.background)} +
+
{JSON.stringify(theme.vars.palette.divider)}
+
{JSON.stringify(theme.vars.palette.action)}
+
+ ); + }; + + render( + + + , + ); + + expect(screen.getByTestId('palette-primary').textContent).to.equal( + JSON.stringify({ + main: 'var(--md-palette-primary-main)', + light: 'var(--md-palette-primary-light)', + dark: 'var(--md-palette-primary-dark)', + contrastText: 'var(--md-palette-primary-contrastText)', + }), + ); + expect(screen.getByTestId('palette-secondary').textContent).to.equal( + JSON.stringify({ + main: 'var(--md-palette-secondary-main)', + light: 'var(--md-palette-secondary-light)', + dark: 'var(--md-palette-secondary-dark)', + contrastText: 'var(--md-palette-secondary-contrastText)', + }), + ); + expect(screen.getByTestId('palette-error').textContent).to.equal( + JSON.stringify({ + main: 'var(--md-palette-error-main)', + light: 'var(--md-palette-error-light)', + dark: 'var(--md-palette-error-dark)', + contrastText: 'var(--md-palette-error-contrastText)', + }), + ); + expect(screen.getByTestId('palette-warning').textContent).to.equal( + JSON.stringify({ + main: 'var(--md-palette-warning-main)', + light: 'var(--md-palette-warning-light)', + dark: 'var(--md-palette-warning-dark)', + contrastText: 'var(--md-palette-warning-contrastText)', + }), + ); + expect(screen.getByTestId('palette-info').textContent).to.equal( + JSON.stringify({ + main: 'var(--md-palette-info-main)', + light: 'var(--md-palette-info-light)', + dark: 'var(--md-palette-info-dark)', + contrastText: 'var(--md-palette-info-contrastText)', + }), + ); + expect(screen.getByTestId('palette-success').textContent).to.equal( + JSON.stringify({ + main: 'var(--md-palette-success-main)', + light: 'var(--md-palette-success-light)', + dark: 'var(--md-palette-success-dark)', + contrastText: 'var(--md-palette-success-contrastText)', + }), + ); + + expect(screen.getByTestId('palette-text').textContent).to.equal( + JSON.stringify({ + primary: 'var(--md-palette-text-primary)', + secondary: 'var(--md-palette-text-secondary)', + disabled: 'var(--md-palette-text-disabled)', + icon: 'var(--md-palette-text-icon)', + }), + ); + expect(screen.getByTestId('palette-divider').textContent).to.equal( + '"var(--md-palette-divider)"', + ); + expect(screen.getByTestId('palette-background').textContent).to.equal( + JSON.stringify({ + paper: 'var(--md-palette-background-paper)', + default: 'var(--md-palette-background-default)', + }), + ); + expect(screen.getByTestId('palette-action').textContent).to.equal( + JSON.stringify({ + active: 'var(--md-palette-action-active)', + hover: 'var(--md-palette-action-hover)', + hoverOpacity: 'var(--md-palette-action-hoverOpacity)', + selected: 'var(--md-palette-action-selected)', + selectedOpacity: 'var(--md-palette-action-selectedOpacity)', + disabled: 'var(--md-palette-action-disabled)', + disabledBackground: 'var(--md-palette-action-disabledBackground)', + disabledOpacity: 'var(--md-palette-action-disabledOpacity)', + focus: 'var(--md-palette-action-focus)', + focusOpacity: 'var(--md-palette-action-focusOpacity)', + activatedOpacity: 'var(--md-palette-action-activatedOpacity)', + }), + ); + }); + + it('opacity', () => { + const Vars = () => { + const theme = useTheme(); + return ( +
+
{JSON.stringify(theme.vars.opacity)}
+
+ ); + }; + + render( + + + , + ); + + expect(screen.getByTestId('opacity').textContent).to.equal( + JSON.stringify({ + active: 'var(--md-opacity-active)', + hover: 'var(--md-opacity-hover)', + selected: 'var(--md-opacity-selected)', + disabled: 'var(--md-opacity-disabled)', + focus: 'var(--md-opacity-focus)', + }), + ); + }); + + it('shape', () => { + const Vars = () => { + const theme = useTheme(); + return ( +
+
{JSON.stringify(theme.vars.shape)}
+
+ ); + }; + + render( + + + , + ); + + expect(screen.getByTestId('shape').textContent).to.equal( + JSON.stringify({ + borderRadius: 'var(--md-shape-borderRadius)', + }), + ); + }); + }); + + describe('Typography', () => { + it('contain expected typography', function test() { + const Text = () => { + const theme = useTheme(); + return
{Object.keys(theme.typography).join(',')}
; + }; + + const { container } = render( + + + , + ); + + expect(container.firstChild?.textContent).to.equal( + 'htmlFontSize,pxToRem,fontFamily,fontSize,fontWeightLight,fontWeightRegular,fontWeightMedium,fontWeightBold,h1,h2,h3,h4,h5,h6,subtitle1,subtitle2,body1,body2,button,caption,overline', + ); + }); + }); + + describe('Spacing', () => { + it('provides spacing utility', function test() { + const Text = () => { + const theme = useTheme(); + return
{theme.spacing(2)}
; + }; + + const { container } = render( + + + , + ); + + expect(container.firstChild?.textContent).to.equal('16px'); + }); + }); + + describe('Breakpoints', () => { + it('provides breakpoint utilities', function test() { + const Text = () => { + const theme = useTheme(); + return
{theme.breakpoints.up('sm')}
; + }; + + const { container } = render( + + + , + ); + + expect(container.firstChild?.textContent).to.equal('@media (min-width:600px)'); + }); + }); + + describe('Skipped vars', () => { + it('should not contain `variants` in theme.vars', () => { + const Consumer = () => { + const theme = useTheme(); + // @ts-expect-error + return
{theme.vars.variants ? 'variants' : ''}
; + }; + + const { container } = render( + + + , + ); + + expect(container.firstChild?.textContent).not.to.equal('variants'); + }); + + it('should not contain `typography` in theme.vars', () => { + const Consumer = () => { + const theme = useTheme(); + // @ts-expect-error + return
{theme.vars.typography ? 'typography' : ''}
; + }; + + const { container } = render( + + + , + ); + + expect(container.firstChild?.textContent).not.to.equal('typography'); + }); + + it('should not contain `focus` in theme.vars', () => { + const Consumer = () => { + const theme = useTheme(); + // @ts-expect-error + return
{theme.vars.focus ? 'focus' : ''}
; + }; + + const { container } = render( + + + , + ); + + expect(container.firstChild?.textContent).not.to.equal('focus'); + }); + }); +}); diff --git a/packages/mui-material/src/styles/unstable_createTheme.js b/packages/mui-material/src/styles/unstable_createTheme.js index ed2ad09f7325ea..e3cee921258653 100644 --- a/packages/mui-material/src/styles/unstable_createTheme.js +++ b/packages/mui-material/src/styles/unstable_createTheme.js @@ -3,6 +3,14 @@ import { colorChannel } from '@mui/system'; import createThemeWithoutVars from './createTheme'; import createPalette from './createPalette'; +export const defaultOpacity = { + active: 0.54, + hover: 0.04, + selected: 0.08, + disabled: 0.26, + focus: 0.12, +}; + function createTheme(options = {}, ...args) { const { colorSchemes: colorSchemesInput = {}, opacity: opacityInput = {}, ...input } = options; @@ -50,11 +58,7 @@ function createTheme(options = {}, ...args) { }); const opacity = { - active: 0.54, - hover: 0.04, - selected: 0.08, - disabled: 0.26, - focus: 0.12, + ...defaultOpacity, ...opacityInput, }; diff --git a/packages/mui-material/src/styles/unstable_createTheme.test.js b/packages/mui-material/src/styles/unstable_createTheme.test.js new file mode 100644 index 00000000000000..17dfe37f25d847 --- /dev/null +++ b/packages/mui-material/src/styles/unstable_createTheme.test.js @@ -0,0 +1,320 @@ +import * as React from 'react'; +import { expect } from 'chai'; +import { createRenderer } from 'test/utils'; +import Button from '@mui/material/Button'; +import { CssVarsProvider, unstable_createTheme as createTheme } from '@mui/material/styles'; +import { deepOrange, green } from '@mui/material/colors'; + +describe('unstable_createTheme', () => { + let originalMatchmedia; + const { render } = createRenderer(); + const storage = {}; + beforeEach(() => { + originalMatchmedia = window.matchMedia; + // Create mocks of localStorage getItem and setItem functions + Object.defineProperty(global, 'localStorage', { + value: { + getItem: (key) => storage[key], + setItem: (key, value) => { + storage[key] = value; + }, + }, + configurable: true, + }); + window.matchMedia = () => ({ + addListener: () => {}, + removeListener: () => {}, + }); + }); + afterEach(() => { + window.matchMedia = originalMatchmedia; + }); + + it('should have a colorSchemes', () => { + const theme = createTheme(); + expect(typeof createTheme).to.equal('function'); + expect(typeof theme.colorSchemes).to.equal('object'); + }); + + it('should have the custom color schemes', () => { + const theme = createTheme({ + colorSchemes: { + light: { + palette: { primary: { main: deepOrange[500] }, secondary: { main: green.A400 } }, + }, + }, + }); + expect(theme.colorSchemes.light.palette.primary.main).to.equal(deepOrange[500]); + expect(theme.colorSchemes.light.palette.secondary.main).to.equal(green.A400); + }); + + it('should generate color channels', () => { + const theme = createTheme(); + expect(theme.colorSchemes.dark.palette.primary.mainChannel).to.equal('144 202 249'); + expect(theme.colorSchemes.dark.palette.primary.darkChannel).to.equal('66 165 245'); + expect(theme.colorSchemes.dark.palette.primary.lightChannel).to.equal('227 242 253'); + + expect(theme.colorSchemes.light.palette.primary.mainChannel).to.equal('25 118 210'); + expect(theme.colorSchemes.light.palette.primary.darkChannel).to.equal('21 101 192'); + expect(theme.colorSchemes.light.palette.primary.lightChannel).to.equal('66 165 245'); + + expect(theme.colorSchemes.dark.palette.secondary.mainChannel).to.equal('206 147 216'); + expect(theme.colorSchemes.dark.palette.secondary.darkChannel).to.equal('171 71 188'); + expect(theme.colorSchemes.dark.palette.secondary.lightChannel).to.equal('243 229 245'); + + expect(theme.colorSchemes.light.palette.secondary.mainChannel).to.equal('156 39 176'); + expect(theme.colorSchemes.light.palette.secondary.darkChannel).to.equal('123 31 162'); + expect(theme.colorSchemes.light.palette.secondary.lightChannel).to.equal('186 104 200'); + + expect(theme.colorSchemes.dark.palette.text.primaryChannel).to.equal('255 255 255'); + expect(theme.colorSchemes.dark.palette.text.secondaryChannel).to.equal('255 255 255'); + expect(theme.colorSchemes.dark.palette.text.disabledChannel).to.equal('255 255 255'); + expect(theme.colorSchemes.dark.palette.action.disabledChannel).to.equal('255 255 255'); + + expect(theme.colorSchemes.light.palette.text.primaryChannel).to.equal('0 0 0'); + expect(theme.colorSchemes.light.palette.text.secondaryChannel).to.equal('0 0 0'); + expect(theme.colorSchemes.light.palette.text.disabledChannel).to.equal('0 0 0'); + expect(theme.colorSchemes.light.palette.action.disabledChannel).to.equal('0 0 0'); + }); + + it('should generate color channels for custom colors', () => { + const theme = createTheme({ + colorSchemes: { + light: { + palette: { primary: { main: deepOrange[500] }, secondary: { main: green.A400 } }, + }, + }, + }); + expect(theme.colorSchemes.light.palette.primary.mainChannel).to.equal('255 87 34'); + expect(theme.colorSchemes.light.palette.secondary.mainChannel).to.equal('0 230 118'); + }); + + describe('transitions', () => { + it('[`easing`]: should provide the default values', () => { + const theme = createTheme(); + expect(theme.transitions.easing.easeInOut).to.equal('cubic-bezier(0.4, 0, 0.2, 1)'); + expect(theme.transitions.easing.easeOut).to.equal('cubic-bezier(0.0, 0, 0.2, 1)'); + expect(theme.transitions.easing.easeIn).to.equal('cubic-bezier(0.4, 0, 1, 1)'); + expect(theme.transitions.easing.sharp).to.equal('cubic-bezier(0.4, 0, 0.6, 1)'); + }); + + it('[`duration`]: should provide the default values', () => { + const theme = createTheme(); + expect(theme.transitions.duration.shortest).to.equal(150); + expect(theme.transitions.duration.shorter).to.equal(200); + expect(theme.transitions.duration.short).to.equal(250); + expect(theme.transitions.duration.standard).to.equal(300); + expect(theme.transitions.duration.complex).to.equal(375); + expect(theme.transitions.duration.enteringScreen).to.equal(225); + expect(theme.transitions.duration.leavingScreen).to.equal(195); + }); + + it('[`easing`]: should provide the custom values', () => { + const theme = createTheme({ + transitions: { + easing: { + easeInOut: 'cubic-bezier(1, 1, 1, 1)', + easeOut: 'cubic-bezier(1, 1, 1, 1)', + easeIn: 'cubic-bezier(1, 1, 1, 1)', + sharp: 'cubic-bezier(1, 1, 1, 1)', + }, + }, + }); + expect(theme.transitions.easing.easeInOut).to.equal('cubic-bezier(1, 1, 1, 1)'); + expect(theme.transitions.easing.easeOut).to.equal('cubic-bezier(1, 1, 1, 1)'); + expect(theme.transitions.easing.easeIn).to.equal('cubic-bezier(1, 1, 1, 1)'); + expect(theme.transitions.easing.sharp).to.equal('cubic-bezier(1, 1, 1, 1)'); + }); + + it('[`duration`]: should provide the custom values', () => { + const theme = createTheme({ + transitions: { + duration: { + shortest: 1, + shorter: 1, + short: 1, + standard: 1, + complex: 1, + enteringScreen: 1, + leavingScreen: 1, + }, + }, + }); + expect(theme.transitions.duration.shortest).to.equal(1); + expect(theme.transitions.duration.shorter).to.equal(1); + expect(theme.transitions.duration.short).to.equal(1); + expect(theme.transitions.duration.standard).to.equal(1); + expect(theme.transitions.duration.complex).to.equal(1); + expect(theme.transitions.duration.enteringScreen).to.equal(1); + expect(theme.transitions.duration.leavingScreen).to.equal(1); + }); + + it('should allow providing a partial structure', () => { + const theme = createTheme({ transitions: { duration: { shortest: 150 } } }); + expect(theme.transitions.duration.shorter).not.to.equal(undefined); + }); + }); + + describe('opacity', () => { + it('should provide the default opacities', () => { + const theme = createTheme(); + expect(theme.opacity).to.deep.equal({ + active: 0.54, + hover: 0.04, + selected: 0.08, + disabled: 0.26, + focus: 0.12, + }); + }); + + it('should allow overriding of the default opacities', () => { + const theme = createTheme({ + opacity: { + active: 0.4, + }, + }); + expect(theme.opacity).to.deep.equal({ + active: 0.4, + hover: 0.04, + selected: 0.08, + disabled: 0.26, + focus: 0.12, + }); + }); + }); + + describe('shadows', () => { + it('should provide the default array', () => { + const theme = createTheme(); + expect(theme.shadows[2]).to.equal( + '0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)', + ); + }); + + it('should override the array as expected', () => { + const shadows = [ + 'none', + 1, + 1, + 1, + 2, + 3, + 3, + 4, + 5, + 5, + 6, + 6, + 7, + 7, + 7, + 8, + 8, + 8, + 9, + 9, + 10, + 10, + 10, + 11, + 11, + ]; + const theme = createTheme({ shadows }); + expect(theme.shadows).to.equal(shadows); + }); + }); + + describe('components', () => { + it('should have the components as expected', () => { + const components = { + MuiDialog: { + defaultProps: { + fullScreen: true, + fullWidth: false, + }, + }, + MuiButtonBase: { + defaultProps: { + disableRipple: true, + }, + }, + MuiPopover: { + defaultProps: { + container: document.createElement('div'), + }, + }, + }; + const theme = createTheme({ components }); + expect(theme.components).to.deep.equal(components); + }); + }); + + describe('styleOverrides', () => { + it('should warn when trying to override an internal state the wrong way', () => { + let theme; + + expect(() => { + theme = createTheme({ + components: { Button: { styleOverrides: { disabled: { color: 'blue' } } } }, + }); + }).not.toErrorDev(); + expect(Object.keys(theme.components.Button.styleOverrides.disabled).length).to.equal(1); + + expect(() => { + theme = createTheme({ + components: { MuiButton: { styleOverrides: { root: { color: 'blue' } } } }, + }); + }).not.toErrorDev(); + + expect(() => { + theme = createTheme({ + components: { MuiButton: { styleOverrides: { disabled: { color: 'blue' } } } }, + }); + }).toErrorDev( + 'MUI: The `MuiButton` component increases the CSS specificity of the `disabled` internal state.', + ); + expect(Object.keys(theme.components.MuiButton.styleOverrides.disabled).length).to.equal(0); + }); + }); + + it('shallow merges multiple arguments', () => { + const theme = createTheme({ foo: 'I am foo' }, { bar: 'I am bar' }); + expect(theme.foo).to.equal('I am foo'); + expect(theme.bar).to.equal('I am bar'); + }); + + it('deep merges multiple arguments', () => { + const theme = createTheme({ custom: { foo: 'I am foo' } }, { custom: { bar: 'I am bar' } }); + expect(theme.custom.foo).to.equal('I am foo'); + expect(theme.custom.bar).to.equal('I am bar'); + }); + + it('allows callbacks using theme in variants', () => { + const theme = createTheme({ + typography: { + fontFamily: 'cursive', + }, + components: { + MuiButton: { + variants: [ + { + props: {}, // match any props combination + style: ({ theme: t }) => { + return { + fontFamily: t.typography.fontFamily, + }; + }, + }, + ], + }, + }, + }); + + const { container } = render( + +