Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Joy] Improve variant customization experience #30878

Merged
merged 31 commits into from
Feb 12, 2022
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
71337a0
create variants after user input
siriwatknp Jan 26, 2022
da4fd85
fix variant type to be augmentable
siriwatknp Jan 28, 2022
f70996d
minor cleanup types
siriwatknp Jan 25, 2022
b27c23d
add comment
siriwatknp Feb 2, 2022
069b03f
fix types
siriwatknp Feb 2, 2022
ac39c9a
remove unnecessary contained context
siriwatknp Feb 2, 2022
cc33f74
fix types
siriwatknp Feb 2, 2022
abd043c
add variant experiment page
siriwatknp Feb 2, 2022
2ee1c0c
auto create variant style for any palette
siriwatknp Feb 2, 2022
c7f3f44
remove recursive type
siriwatknp Feb 2, 2022
a5a1a77
fix undefined resolveTheme
siriwatknp Feb 2, 2022
6741ec0
add prefix to theme
siriwatknp Feb 2, 2022
22d7c5e
fix contained overrides
siriwatknp Feb 2, 2022
7f8875e
prevent crash if undefined
siriwatknp Feb 3, 2022
8d5885e
fix CSS value case
siriwatknp Feb 3, 2022
321c90a
add focusVisible to context overrides
siriwatknp Feb 3, 2022
23f5d4a
remove colorScheme toggle
siriwatknp Feb 3, 2022
87fc23e
add tests
siriwatknp Feb 3, 2022
df69def
Merge branch 'master' of https://github.com/mui-org/material-ui into …
siriwatknp Feb 3, 2022
e5654f7
fix variant outlined borderWidth
siriwatknp Feb 3, 2022
4bcd7e7
rename for consistency
siriwatknp Feb 3, 2022
c28d963
revert changes
siriwatknp Feb 4, 2022
6e0d45c
fix types naming
siriwatknp Feb 4, 2022
96a4888
fix CSS variables prefix replacement
siriwatknp Feb 4, 2022
b6ad6f6
add comments
siriwatknp Feb 4, 2022
364a57f
Merge branch 'master' into joy/variant-implementation
siriwatknp Feb 11, 2022
c19d937
fix wrong merge conflict
siriwatknp Feb 11, 2022
4cb6800
add other variants overrides
siriwatknp Feb 11, 2022
a8a9a41
fix test
siriwatknp Feb 11, 2022
721046b
add override text palette
siriwatknp Feb 12, 2022
f90bacf
fix test
siriwatknp Feb 12, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
831 changes: 831 additions & 0 deletions docs/pages/experiments/joy/variant.tsx

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/mui-joy/src/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const ButtonRoot = styled('button', {
padding: '0.25rem var(--Button-gutter)', // the padding-top, bottom act as a minimum spacing between content and root element
...(ownerState.variant === 'outlined' && {
padding:
'calc(0.25rem - var(--variant-outlined-borderWidth)) calc(var(--Button-gutter) - var(--variant-outlined-borderWidth))', // account for the border width
'calc(0.25rem - var(--variant-outlinedBorderWidth)) calc(var(--Button-gutter) - var(--variant-outlinedBorderWidth))', // account for the border width
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename to match the variant variables.

}),
minHeight: 'var(--Button-minHeight)',
borderRadius: theme.vars.radius.sm,
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-joy/src/IconButton/IconButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const IconButtonRoot = styled('button', {
}),
padding: 'var(--IconButton-padding)',
...(ownerState.variant === 'outlined' && {
padding: 'calc(var(--IconButton-padding) - var(--variant-outlined-borderWidth))', // account for the border width
padding: 'calc(var(--IconButton-padding) - var(--variant-outlinedBorderWidth))', // account for the border width
}),
minWidth: 'var(--IconButton-size)', // use min-width instead of height to make the button resilient to its content
minHeight: 'var(--IconButton-size)', // use min-height instead of height to make the button resilient to its content
Expand Down
50 changes: 43 additions & 7 deletions packages/mui-joy/src/styles/CssVarsProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { deepmerge } from '@mui/utils';
import {
unstable_createCssVarsProvider as createCssVarsProvider,
BreakpointsOptions,
Expand All @@ -15,14 +16,23 @@ import { Variants } from './types/variants';
import { ColorSystem } from './types/colorSystem';
import { TypographySystem } from './types/typography';
import { Components } from './components';
import { createVariant, createContainedOverrides } from './variantUtils';

type PartialDeep<T> = {
[K in keyof T]?: PartialDeep<T[K]>;
type PartialNested<T> = {
[K in keyof T]?: T[K] extends Record<any, any>
? {
[J in keyof T[K]]?: T[K][J];
}
: T[K];
};

type PartialNested<T> = {
type PartialNestedNested<T> = {
[K in keyof T]?: {
[J in keyof T[K]]?: T[K][J];
[J in keyof T[K]]?: T[K][J] extends Record<any, any>
? {
[P in keyof T[K][J]]?: T[K][J][P];
}
: T[K][J];
};
};

Expand All @@ -31,7 +41,7 @@ type ThemeInput = PartialNested<
ThemeScales & {
focus: Focus;
typography: TypographySystem;
variants: Variants;
variants: PartialNested<Variants>;
}
> & {
breakpoints?: BreakpointsOptions;
Expand All @@ -40,11 +50,11 @@ type ThemeInput = PartialNested<
};

type JoyThemeInput = ThemeInput & {
colorSchemes: Record<DefaultColorScheme, PartialDeep<ColorSystem>>;
colorSchemes: Record<DefaultColorScheme, PartialNestedNested<ColorSystem>>;
};

type ApplicationThemeInput = ThemeInput & {
colorSchemes: Record<ExtendedColorScheme, PartialDeep<ColorSystem>>;
colorSchemes: Record<ExtendedColorScheme, PartialNestedNested<ColorSystem>>;
};

const { palette, ...rest } = defaultTheme;
Expand All @@ -67,6 +77,32 @@ const { CssVarsProvider, useColorScheme, getInitColorSchemeScript } = createCssV
dark: 'dark',
},
prefix: 'joy',
resolveTheme: (mergedTheme: JoyTheme) => {
mergedTheme.variants = deepmerge(
{
text: createVariant('text', mergedTheme),
textHover: createVariant('textHover', mergedTheme),
textActive: createVariant('textActive', mergedTheme),
textDisabled: createVariant('textDisabled', mergedTheme),
outlined: createVariant('outlined', mergedTheme),
outlinedHover: createVariant('outlinedHover', mergedTheme),
outlinedActive: createVariant('outlinedActive', mergedTheme),
outlinedDisabled: createVariant('outlinedDisabled', mergedTheme),
light: createVariant('light', mergedTheme),
lightHover: createVariant('lightHover', mergedTheme),
lightActive: createVariant('lightActive', mergedTheme),
lightDisabled: createVariant('lightDisabled', mergedTheme),
contained: createVariant('contained', mergedTheme),
containedHover: createVariant('containedHover', mergedTheme),
containedActive: createVariant('containedActive', mergedTheme),
containedDisabled: createVariant('containedDisabled', mergedTheme),
containedOverrides: createContainedOverrides(mergedTheme),
} as typeof mergedTheme.variants,
mergedTheme.variants,
{ clone: false },
);
return mergedTheme;
},
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the main change of this PR.

shouldSkipGeneratingVar: (keys) =>
keys[0] === 'typography' ||
keys[0] === 'variants' ||
Expand Down
5 changes: 2 additions & 3 deletions packages/mui-joy/src/styles/ThemeProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { deepmerge } from '@mui/utils';
import { ThemeProvider as SystemThemeProvider, useTheme as useSystemTheme } from '@mui/system';
import defaultTheme, { JoyTheme } from './defaultTheme';
import { Components } from './components';
import { ExtendedColorScheme } from './types/colorScheme';

type PartialDeep<T> = {
[K in keyof T]?: PartialDeep<T[K]>;
Expand All @@ -17,7 +16,7 @@ export default function ThemeProvider({
children,
theme,
}: React.PropsWithChildren<{
theme?: PartialDeep<Omit<JoyTheme<ExtendedColorScheme>, 'vars'>> & {
theme?: PartialDeep<Omit<JoyTheme, 'vars'>> & {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JoyTheme should not be a generic.

components?: Components;
};
}>) {
Expand All @@ -27,6 +26,6 @@ export default function ThemeProvider({
...mergedTheme,
vars: mergedTheme,
components,
} as JoyTheme<ExtendedColorScheme> & { components: Components };
} as JoyTheme & { components: Components };
return <SystemThemeProvider theme={mergedTheme}>{children}</SystemThemeProvider>;
}
149 changes: 76 additions & 73 deletions packages/mui-joy/src/styles/defaultTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,14 @@ import {
} from '@mui/system';
import colors from '../colors';
import {
ColorPaletteProp,
ColorSystem,
ColorPaletteProp,
Palette,
PaletteText,
PaletteRange,
PaletteBackground,
} from './types/colorSystem';
import { Variants, DefaultVariantKey, DefaultContextualOverrides } from './types/variants';
import {
createLightModeVariantVariables,
createDarkModeVariantVariables,
createVariant,
} from './variantUtils';
import { Variants } from './types/variants';
import { DefaultColorScheme, ExtendedColorScheme } from './types/colorScheme';
import { Shadow } from './types/shadow';
import { Radius } from './types/radius';
Expand All @@ -36,7 +31,9 @@ import {

type CSSProperties = CSS.Properties<number | string>;

type Split<T, K extends keyof T = keyof T> = K extends string | number ? { [k in K]: T[K] } : never;
type Split<T, K extends keyof T = keyof T> = K extends string | number
? { [k in K]: Exclude<T[K], undefined> }
: never;

type ConcatDeep<T> = T extends Record<string | number, infer V>
? keyof T extends string | number
Expand All @@ -59,47 +56,17 @@ export interface Focus {
* Internal type for definfing default Joy theme.
* ==============================================
*/
type BasePaletteRange =
| 50
| 100
| 200
| 300
| 400
| 500
| 600
| 700
| 800
| 900
| 'textColor'
| 'textHoverBg'
| 'textActiveBg'
| 'textDisabledColor'
| 'outlinedColor'
| 'outlinedBorder'
| 'outlinedHoverBg'
| 'outlinedHoverBorder'
| 'outlinedActiveBg'
| 'outlinedDisabledColor'
| 'outlinedDisabledBorder'
| 'lightColor'
| 'lightBg'
| 'lightHoverBg'
| 'lightActiveBg'
| 'lightDisabledColor'
| 'lightDisabledBg'
| 'containedColor'
| 'containedBg'
| 'containedHoverBg'
| 'containedActiveBg'
| 'containedDisabledBg';
type BasePaletteRange = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;
type PartialRest<T, U extends keyof T> = Pick<T, U> & Partial<Exclude<T, U>>;
type BaseDesignTokens = {
palette: {
primary: Pick<PaletteRange, BasePaletteRange>;
neutral: Pick<PaletteRange, BasePaletteRange>;
danger: Pick<PaletteRange, BasePaletteRange>;
info: Pick<PaletteRange, BasePaletteRange>;
success: Pick<PaletteRange, BasePaletteRange>;
warning: Pick<PaletteRange, BasePaletteRange>;
// variant tokens are optional because the style will be generated after CSS variables has been prepared.
primary: PartialRest<PaletteRange, BasePaletteRange>;
neutral: PartialRest<PaletteRange, BasePaletteRange>;
danger: PartialRest<PaletteRange, BasePaletteRange>;
info: PartialRest<PaletteRange, BasePaletteRange>;
success: PartialRest<PaletteRange, BasePaletteRange>;
warning: PartialRest<PaletteRange, BasePaletteRange>;
text: Pick<PaletteText, 'primary' | 'secondary' | 'tertiary'>;
background: Pick<PaletteBackground, 'body' | 'level1' | 'level2' | 'level3'>;
focusVisible: Palette['focusVisible'];
Expand All @@ -120,6 +87,62 @@ type BaseDesignTokens = {

type BaseColorSystem = Pick<BaseDesignTokens, 'palette' | 'shadowRing' | 'shadowChannel'>;

const createLightModeVariantVariables = (color: ColorPaletteProp) => ({
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no change on these functions, just moved there to prevent dependency cycle.

textColor: `var(--joy-palette-${color}-600)`,
textHoverBg: `var(--joy-palette-${color}-100)`,
textActiveBg: `var(--joy-palette-${color}-200)`,
textDisabledColor: `var(--joy-palette-${color}-200)`,

outlinedColor: `var(--joy-palette-${color}-600)`,
outlinedBorder: `var(--joy-palette-${color}-200)`,
outlinedHoverBg: `var(--joy-palette-${color}-100)`,
outlinedHoverBorder: `var(--joy-palette-${color}-300)`,
outlinedActiveBg: `var(--joy-palette-${color}-200)`,
outlinedDisabledColor: `var(--joy-palette-${color}-200)`,
outlinedDisabledBorder: `var(--joy-palette-${color}-100)`,

lightColor: `var(--joy-palette-${color}-700)`,
lightBg: `var(--joy-palette-${color}-100)`,
lightHoverBg: `var(--joy-palette-${color}-200)`,
lightActiveBg: `var(--joy-palette-${color}-300)`,
lightDisabledColor: `var(--joy-palette-${color}-300)`,
lightDisabledBg: `var(--joy-palette-${color}-50)`,

containedColor: '#fff',
containedBg: `var(--joy-palette-${color}-600)`,
containedHoverBg: `var(--joy-palette-${color}-700)`,
containedActiveBg: `var(--joy-palette-${color}-800)`,
containedDisabledBg: `var(--joy-palette-${color}-200)`,
});

const createDarkModeVariantVariables = (color: ColorPaletteProp) => ({
textColor: `var(--joy-palette-${color}-300)`,
textHoverBg: `var(--joy-palette-${color}-800)`,
textActiveBg: `var(--joy-palette-${color}-700)`,
textDisabledColor: `var(--joy-palette-${color}-800)`,

outlinedColor: `var(--joy-palette-${color}-200)`,
outlinedBorder: `var(--joy-palette-${color}-700)`,
outlinedHoverBg: `var(--joy-palette-${color}-900)`,
outlinedHoverBorder: `var(--joy-palette-${color}-600)`,
outlinedActiveBg: `var(--joy-palette-${color}-900)`,
outlinedDisabledColor: `var(--joy-palette-${color}-800)`,
outlinedDisabledBorder: `var(--joy-palette-${color}-800)`,

lightColor: `var(--joy-palette-${color}-200)`,
lightBg: `var(--joy-palette-${color}-900)`,
lightHoverBg: `var(--joy-palette-${color}-800)`,
lightActiveBg: `var(--joy-palette-${color}-700)`,
lightDisabledColor: `var(--joy-palette-${color}-800)`,
lightDisabledBg: `var(--joy-palette-${color}-900)`,

containedColor: `#fff`,
containedBg: `var(--joy-palette-${color}-600)`,
containedHoverBg: `var(--joy-palette-${color}-700)`,
containedActiveBg: `var(--joy-palette-${color}-800)`,
containedDisabledBg: `var(--joy-palette-${color}-300)`,
});

export const lightColorSystem: BaseColorSystem = {
palette: {
primary: {
Expand Down Expand Up @@ -275,8 +298,7 @@ const internalDefaultTheme: BaseDesignTokens & {
TypographySystem,
'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'body1' | 'body2' | 'body3'
>;
variants: Pick<Variants, DefaultVariantKey> &
Record<DefaultContextualOverrides, Record<Exclude<ColorPaletteProp, 'context'>, CSSObject>>;
variants: {};
vars: BaseDesignTokens & BaseColorSystem;
spacing: Spacing;
breakpoints: Breakpoints;
Expand All @@ -289,7 +311,7 @@ const internalDefaultTheme: BaseDesignTokens & {
focus: {
default: {
outline: '4px solid',
outlineColor: 'var(--joy-palette-focusVisible)',
outlineColor: 'var(--variant-focusVisible, var(--joy-palette-focusVisible))',
},
},
typography: {
Expand Down Expand Up @@ -359,25 +381,7 @@ const internalDefaultTheme: BaseDesignTokens & {
color: 'var(--joy-palette-text-tertiary)',
},
},
variants: {
text: createVariant('text'),
textHover: createVariant('textHover'),
textActive: createVariant('textActive'),
textDisabled: createVariant('textDisabled'),
outlined: createVariant('outlined'),
outlinedHover: createVariant('outlinedHover'),
outlinedActive: createVariant('outlinedActive'),
outlinedDisabled: createVariant('outlinedDisabled'),
light: createVariant('light'),
lightHover: createVariant('lightHover'),
lightActive: createVariant('lightActive'),
lightDisabled: createVariant('lightDisabled'),
contained: createVariant('contained'),
containedHover: createVariant('containedHover'),
containedActive: createVariant('containedActive'),
containedDisabled: createVariant('containedDisabled'),
containedOverrides: createVariant('containedOverrides'),
},
variants: {},
vars: baseDesignTokens,
breakpoints: defaultSystemTheme.breakpoints,
spacing: defaultSystemTheme.spacing,
Expand All @@ -401,15 +405,14 @@ export type ThemeVar = NormalizeVars<Vars>;

export const createGetCssVar = (prefix = 'joy') => systemCreateGetCssVar<ThemeVar>(prefix);

export interface JoyTheme<ApplicationColorScheme extends string = ExtendedColorScheme>
extends ThemeScales,
ColorSystem {
colorSchemes: Record<DefaultColorScheme | ApplicationColorScheme, ColorSystem>;
export interface JoyTheme extends ThemeScales, ColorSystem {
colorSchemes: Record<DefaultColorScheme | ExtendedColorScheme, ColorSystem>;
focus: Focus;
typography: TypographySystem;
variants: Variants;
spacing: Spacing;
breakpoints: Breakpoints;
prefix: string;
vars: Vars;
getCssVar: ReturnType<typeof createGetCssVar>;
}
Expand Down