Skip to content

Commit

Permalink
[TypeScript] getCssVar autocomplete for Material UI (#33464)
Browse files Browse the repository at this point in the history
  • Loading branch information
siriwatknp authored Jul 11, 2022
1 parent 4e9f6cb commit f427ef9
Show file tree
Hide file tree
Showing 12 changed files with 223 additions and 75 deletions.
4 changes: 2 additions & 2 deletions packages/mui-joy/src/styles/extendTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { ColorSystem, ColorPaletteProp, PaletteRange } from './types/colorSystem
import { Focus } from './types/focus';
import { TypographySystem, FontSize } from './types/typography';
import { Variants } from './types/variants';
import { Theme, ThemeCSSVar, ThemeScales } from './types';
import { Theme, ThemeCssVar, ThemeScales } from './types';
import { Components } from './components';
import { generateUtilityClass } from '../className';
import { createVariant, createTextOverrides, createContainedOverrides } from './variantUtils';
Expand Down Expand Up @@ -61,7 +61,7 @@ export interface CssVarsThemeOptions extends Partial2Level<ThemeScales> {
}

export const createGetCssVar = (cssVarPrefix = 'joy') =>
systemCreateGetCssVar<ThemeCSSVar>(cssVarPrefix);
systemCreateGetCssVar<ThemeCssVar>(cssVarPrefix);

export default function extendTheme(themeOptions?: CssVarsThemeOptions): Theme {
const {
Expand Down
8 changes: 7 additions & 1 deletion packages/mui-joy/src/styles/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,13 @@ export type {
Variants,
VariantProp,
} from './types/variants';
export type { Theme, ThemeVars, ThemeScales, ThemeCSSVar } from './types/theme';
export type {
Theme,
ThemeVars,
ThemeScales,
ThemeCssVar,
ThemeCssVarOverrides,
} from './types/theme';
export {
CssVarsProvider,
useColorScheme,
Expand Down
15 changes: 10 additions & 5 deletions packages/mui-joy/src/styles/types/theme.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { OverridableStringUnion } from '@mui/types';
import {
Breakpoints,
Spacing,
Expand Down Expand Up @@ -33,6 +34,11 @@ type ConcatDeep<T> = T extends Record<string | number, infer V>
: never
: never;

/**
* Does not work for these cases:
* - { borderRadius: string | number } // the value can't be a union
* - { shadows: [string, string, ..., string] } // the value can't be an array
*/
type NormalizeVars<T> = ConcatDeep<Split<T>>;

export interface RuntimeColorSystem extends Omit<ColorSystem, 'palette'> {
Expand All @@ -54,7 +60,9 @@ export interface ThemeScales {

export interface ThemeVars extends ThemeScales, ColorSystem {}

export type ThemeCSSVar = NormalizeVars<ThemeVars>;
export interface ThemeCssVarOverrides {}

export type ThemeCssVar = OverridableStringUnion<NormalizeVars<ThemeVars>, ThemeCssVarOverrides>;

export interface Theme extends ThemeScales, RuntimeColorSystem {
colorSchemes: Record<DefaultColorScheme | ExtendedColorScheme, ColorSystem>;
Expand All @@ -65,10 +73,7 @@ export interface Theme extends ThemeScales, RuntimeColorSystem {
breakpoints: Breakpoints;
cssVarPrefix: string;
vars: ThemeVars;
getCssVar: <CustomVar extends string = never>(
field: ThemeCSSVar | CustomVar,
...vars: (ThemeCSSVar | CustomVar)[]
) => string;
getCssVar: (field: ThemeCssVar, ...vars: ThemeCssVar[]) => string;
getColorSchemeSelector: (colorScheme: DefaultColorScheme | ExtendedColorScheme) => string;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ declare module '@mui/joy/styles' {
// extends Palette
declare module '@mui/joy/styles' {
interface Palette {
neutral: PaletteRange;
secondary: PaletteRange;
}
}

Expand Down Expand Up @@ -75,73 +75,76 @@ declare module '@mui/joy/styles' {
}
}

<CssVarsProvider
theme={extendTheme({
colorSchemes: {
light: {
palette: {
primary: {
1000: '',
},
neutral: {
500: '',
},
const extendedTheme = extendTheme({
colorSchemes: {
light: {
palette: {
primary: {
1000: '',
},
neutral: {
500: '',
},
bgcolor: '',
},
bgcolor: '',
},
borderRadius: {
xxxs: '',
},
fontSize: {
xxxs: '',
},
fontFamily: {
secondary: '',
},
fontWeight: {
xxxs: '',
},
lineHeight: {
xxxs: '',
},
borderRadius: {
xxxs: '',
},
fontSize: {
xxxs: '',
},
fontFamily: {
secondary: '',
},
fontWeight: {
xxxs: '',
},
lineHeight: {
xxxs: '',
},
typography: {
ads: {
fontFamily: 'var(--joy-fontFamily-secondary)',
fontSize: '1rem',
lineHeight: 1,
},
typography: {
ads: {
fontFamily: 'var(--joy-fontFamily-secondary)',
fontSize: '1rem',
lineHeight: 1,
},
},
components: {
JoyButton: {
styleOverrides: {
root: ({ ownerState, theme }) => {
const { color, variant } = ownerState;
const styles = [];
if (color === 'primary') {
styles.push({
width: 120,
height: 48,
});
}
if (variant === 'contained') {
styles.push(theme.typography.body1);
}
return styles;
},
},
components: {
JoyButton: {
styleOverrides: {
root: ({ ownerState, theme }) => {
const { color, variant } = ownerState;
const styles = [];
if (color === 'primary') {
styles.push({
width: 120,
height: 48,
});
}
if (variant === 'contained') {
styles.push(theme.typography.body1);
}
return styles;
},
},
JoySwitch: {
styleOverrides: {
thumb: ({ ownerState, theme }) => [
ownerState.color === 'primary' && {
'&:hover': {
backgroundColor: theme.vars.palette.primary.containedHoverBg,
},
},
JoySwitch: {
styleOverrides: {
thumb: ({ ownerState, theme }) => [
ownerState.color === 'primary' && {
'&:hover': {
backgroundColor: theme.vars.palette.primary.containedHoverBg,
},
],
},
},
],
},
},
})}
/>;
},
});

extendedTheme.getCssVar('fontSize-xxxs');
extendedTheme.getCssVar('palette-secondary-solidBg');

<CssVarsProvider theme={extendedTheme} />;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { extendTheme } from '@mui/joy/styles';

declare module '@mui/joy/styles' {
interface ThemeCssVarOverrides {
'custom-color': true;
}
}

const theme = extendTheme();

theme.getCssVar('custom-color');
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "../../../../../tsconfig",
"files": ["themeGetCssVar.spec.tsx"]
}
89 changes: 84 additions & 5 deletions packages/mui-material/src/styles/experimental_extendTheme.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,21 +288,100 @@ export interface ThemeVars {
opacity: Opacity;
overlays: Overlays;
shadows: Shadows;
zIndex: ZIndex;
shape: Theme['shape'];
zIndex: ZIndex;
}

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
? V extends string | number
? keyof T
: keyof V extends string | number
? `${keyof T}-${ConcatDeep<Split<V>>}`
: never
: never
: never;

/**
* Does not work for these cases:
* - { borderRadius: string | number } // the value can't be a union
* - { shadows: [string, string, ..., string] } // the value can't be an array
*/
type NormalizeVars<T> = ConcatDeep<Split<T>>;

// shut off automatic exporting for the Generics above
export {};

export interface ThemeCssVarOverrides {}

export type ThemeCssVar = OverridableStringUnion<
| NormalizeVars<Omit<ThemeVars, 'overlays' | 'shadows' | 'shape'>>
| 'shape-borderRadius'
| 'shadows-0'
| 'shadows-1'
| 'shadows-2'
| 'shadows-3'
| 'shadows-4'
| 'shadows-5'
| 'shadows-6'
| 'shadows-7'
| 'shadows-8'
| 'shadows-9'
| 'shadows-10'
| 'shadows-11'
| 'shadows-12'
| 'shadows-13'
| 'shadows-14'
| 'shadows-15'
| 'shadows-16'
| 'shadows-17'
| 'shadows-18'
| 'shadows-19'
| 'shadows-20'
| 'shadows-21'
| 'shadows-22'
| 'shadows-23'
| 'shadows-24'
| 'overlays-0'
| 'overlays-1'
| 'overlays-2'
| 'overlays-3'
| 'overlays-4'
| 'overlays-5'
| 'overlays-6'
| 'overlays-7'
| 'overlays-8'
| 'overlays-9'
| 'overlays-10'
| 'overlays-11'
| 'overlays-12'
| 'overlays-13'
| 'overlays-14'
| 'overlays-15'
| 'overlays-16'
| 'overlays-17'
| 'overlays-18'
| 'overlays-19'
| 'overlays-20'
| 'overlays-21'
| 'overlays-22'
| 'overlays-23'
| 'overlays-24',
ThemeCssVarOverrides
>;

/**
* Theme properties generated by extendTheme and CssVarsProvider
*/
export interface CssVarsTheme extends ColorSystem {
colorSchemes: Record<SupportedColorScheme, ColorSystem>;
cssVarPrefix: string;
vars: ThemeVars;
getCssVar: <CustomVar extends string = never>(
field: string | CustomVar,
...vars: Array<string | CustomVar>
) => string;
getCssVar: (field: ThemeCssVar, ...vars: ThemeCssVar[]) => string;
getColorSchemeSelector: (colorScheme: SupportedColorScheme) => string;
}

Expand Down
20 changes: 20 additions & 0 deletions packages/mui-material/src/styles/experimental_extendTheme.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { experimental_extendTheme as extendTheme } from '@mui/material/styles';

const theme = extendTheme();

theme.getCssVar('palette-primary-main');
theme.getCssVar('palette-Alert-errorColor');
theme.getCssVar('opacity-inputPlaceholder');
theme.getCssVar('zIndex-appBar');
theme.getCssVar('shape-borderRadius');
theme.getCssVar('shadows-0');
theme.getCssVar('overlays-0');

// @ts-expect-error
theme.getCssVar();
// @ts-expect-error
theme.getCssVar('');
// @ts-expect-error
theme.getCssVar('custom-color');
// @ts-expect-error
theme.getCssVar('palette-primary-main', '');
2 changes: 2 additions & 0 deletions packages/mui-material/src/styles/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,6 @@ export type {
CssVarsThemeOptions,
CssVarsTheme,
ThemeVars,
ThemeCssVar,
ThemeCssVarOverrides,
} from './experimental_extendTheme';
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,5 @@ const theme = extendTheme({
},
},
});

theme.getCssVar('palette-gradient-default');
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { experimental_extendTheme as extendTheme } from '@mui/material/styles';
import type {} from '@mui/material/themeCssVarsAugmentation';

declare module '@mui/material/styles' {
interface ThemeCssVarOverrides {
'custom-color': true;
}
}

const theme = extendTheme();

theme.getCssVar('custom-color');
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "../../../../../tsconfig",
"files": ["themeGetCssVar.spec.tsx"]
}

0 comments on commit f427ef9

Please sign in to comment.