Skip to content

Commit ac1de07

Browse files
authored
feat(styles): allow extending theme tokens (#4813)
1 parent 7438b01 commit ac1de07

File tree

10 files changed

+119
-73
lines changed

10 files changed

+119
-73
lines changed

packages/styles/src/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@ export * from "./types";
77
export * from "./theme";
88
export * from "./makeTheme";
99
export * from "./utils";
10-
export * from "./tokens";
10+
export * from "./tokens/breakpoints";
11+
export * from "./tokens/colors";
12+
export * from "./tokens/radii";
13+
export * from "./tokens/space";
14+
export * from "./tokens/sizes";
15+
export * from "./tokens/typography";
16+
export * from "./tokens/zIndices";
1117
export * from "./CssBaseline";
1218

1319
// Export each theme individually and a bundle of themes

packages/styles/src/makeTheme.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { HvTheme, theme } from "./theme";
2-
import * as tokens from "./tokens";
3-
import { colors, type ColorTokens } from "./tokens";
4-
import type { HvCustomTheme, HvThemeColors, HvThemeStructure } from "./types";
2+
import { baseTheme } from "./tokens";
3+
import { colors, HvThemeColors, type ColorTokens } from "./tokens/colors";
4+
import type { HvCustomTheme, HvThemeStructure } from "./types";
55
import { mergeTheme } from "./utils";
66

77
/**
@@ -15,7 +15,7 @@ export const makeTheme = <Mode extends string = string>(
1515
options: HvCustomTheme<Mode> | ((theme: HvTheme) => HvCustomTheme<Mode>),
1616
): HvThemeStructure<Mode> => {
1717
const customTheme = typeof options === "function" ? options(theme) : options;
18-
const newTheme = mergeTheme(tokens, customTheme);
18+
const newTheme = mergeTheme(baseTheme, customTheme);
1919

2020
return newTheme;
2121
};

packages/styles/src/theme.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { palette } from "./palette";
2-
import * as tokens from "./tokens";
3-
import type { HvColor, HvColorAny } from "./tokens";
2+
import { baseTheme as tokens } from "./tokens";
3+
import type { HvColor, HvColorAny } from "./tokens/colors";
44
import {
55
DeepString,
66
HvThemeComponents,

packages/styles/src/themes/pentahoPlus.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import {
1313
slate,
1414
yellow,
1515
} from "../palette";
16-
import { radii } from "../tokens";
1716

1817
const pentahoPlus = makeTheme((theme) => ({
1918
name: "pentahoPlus",
@@ -256,7 +255,6 @@ const pentahoPlus = makeTheme((theme) => ({
256255
xl: "64px",
257256
},
258257
radii: {
259-
...radii,
260258
base: "4px",
261259
round: "8px",
262260
large: "16px",
Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
export type HvBreakpoints = "xs" | "sm" | "md" | "lg" | "xl";
2+
3+
/** @experimental extendable theme breakpoints */
4+
export interface HvThemeBreakpoints {
5+
unit: string;
6+
step: number;
7+
values: Record<HvBreakpoints, number>;
8+
}
9+
110
export const breakpoints = {
211
unit: "px",
312
step: 5,
@@ -8,6 +17,4 @@ export const breakpoints = {
817
lg: 1270,
918
xl: 1920,
1019
},
11-
};
12-
13-
export type HvBreakpoints = keyof typeof breakpoints.values;
20+
} satisfies HvThemeBreakpoints;

packages/styles/src/tokens/colors.ts

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,18 @@ const categorical = {
203203
cat28: "#D8265D",
204204
};
205205

206+
const support = {
207+
supp1: "#0F8B8D",
208+
supp2: "#734B6D",
209+
supp3: "#4E7599",
210+
supp4: "#C19C31",
211+
supp5: "#546B6B",
212+
};
213+
206214
const common = {
207215
...base,
208216
...categorical,
217+
...support,
209218
};
210219

211220
// #region Light palette
@@ -255,14 +264,6 @@ const semanticLight = {
255264
warning_20: "#FBF2D8",
256265
};
257266

258-
const supportLight = {
259-
supp1: "#0F8B8D",
260-
supp2: "#734B6D",
261-
supp3: "#4E7599",
262-
supp4: "#C19C31",
263-
supp5: "#546B6B",
264-
};
265-
266267
const shadowLight = {
267268
shad1: "rgba(65, 65, 65, 0.12)",
268269
shadow: "0 2px 12px rgba(65,65,65,0.12)",
@@ -382,14 +383,6 @@ const semanticDark = {
382383
warning_20: "#FBF2D8",
383384
};
384385

385-
const supportDark = {
386-
supp2: "#734B6D",
387-
supp3: "#4E7599",
388-
supp4: "#C19C31",
389-
supp5: "#546B6B",
390-
supp1: "#0F8B8D",
391-
};
392-
393386
const shadowDark = {
394387
shad1: "rgba(0,0,0,.16)",
395388
shadow: "0 3px 5px rgba(0,0,0,.16)",
@@ -466,7 +459,6 @@ export const colors = {
466459
...accentLight,
467460
...atmosphereLight,
468461
...semanticLight,
469-
...supportLight,
470462
...shadowLight,
471463
...utilsLight,
472464
...newLight,
@@ -475,23 +467,28 @@ export const colors = {
475467
...accentDark,
476468
...atmosphereDark,
477469
...semanticDark,
478-
...supportDark,
479470
...shadowDark,
480471
...utilsDark,
481472
...newDark,
482473
},
483474
};
484475

485-
// TODO: remove in favour of `HvColor`/`HvColorAny`?
476+
/** @deprecated replace with standard UI Kit ColorTokens in v6 */
477+
type AllColors = typeof colors.common & typeof colors.light;
478+
479+
/** @experimental extendable theme colors */
480+
export interface HvThemeColors extends ColorTokens, AllColors {}
481+
482+
// TODO: remove in favour of `HvColor`/`HvColorAny`
486483
export type HvAccentColor = keyof typeof accentLight;
487484
export type HvAtmosphereColor = keyof typeof atmosphereLight;
488485
export type HvBaseColor = keyof typeof base;
489486
export type HvSemanticColor = keyof typeof semanticLight;
490-
export type HvSupportColor = keyof typeof supportLight;
487+
export type HvSupportColor = keyof typeof support;
491488
export type HvCategoricalColor = keyof typeof categorical;
492489

493490
/** A type with all the accepted colors from the color palette */
494-
export type HvColor = keyof typeof colors.common | keyof typeof colors.light;
491+
export type HvColor = keyof HvThemeColors;
495492

496493
/**
497494
* A type representing an `HvColor` from the palette or any other color string

packages/styles/src/tokens/index.ts

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,24 @@
1-
export * from "./breakpoints";
2-
export * from "./colors";
3-
export * from "./radii";
4-
export * from "./space";
5-
export * from "./sizes";
6-
export * from "./typography";
7-
export * from "./zIndices";
1+
import { breakpoints } from "./breakpoints";
2+
import { colors } from "./colors";
3+
import { radii } from "./radii";
4+
import { sizes } from "./sizes";
5+
import { space } from "./space";
6+
import { fontFamily, fontSizes, fontWeights, lineHeights } from "./typography";
7+
import { zIndices } from "./zIndices";
8+
9+
/**
10+
* Base theme tokens to use when merging with theme, used to merge with the makeTheme utility.
11+
* Mostly just the uses the `tokens` directly, but also adds other properties like `typography` or component vars.
12+
*/
13+
export const baseTheme = {
14+
breakpoints,
15+
colors,
16+
radii,
17+
space,
18+
sizes,
19+
zIndices,
20+
fontFamily,
21+
fontSizes,
22+
fontWeights,
23+
lineHeights,
24+
};

packages/styles/src/tokens/radii.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
export const radii = {
1+
export type HvRadius = "none" | "base" | "round" | "large" | "circle" | "full";
2+
3+
/** @experimental */
4+
export interface HvThemeRadii extends Record<HvRadius, string> {}
5+
6+
export const radii: HvThemeRadii = {
27
none: "0px",
38
base: "2px",
49
round: "6px",
@@ -7,5 +12,3 @@ export const radii = {
712
circle: "50%",
813
full: "9999px",
914
};
10-
11-
export type HvRadius = keyof typeof radii;

packages/styles/src/tokens/space.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
export const space = {
1+
type HvSpace = "xxs" | "xs" | "sm" | "md" | "lg" | "xl";
2+
3+
/** @experimental extendable theme spacing units */
4+
export interface HvThemeSpace extends Record<HvSpace, string> {
5+
base: number;
6+
}
7+
8+
export const space: HvThemeSpace = {
29
base: 8,
310
xxs: "4px",
411
xs: "8px",

packages/styles/src/types.ts

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,40 @@
11
import type { StandardProperties } from "csstype";
22

3-
import * as tokens from "./tokens";
4-
import { colors } from "./tokens/colors";
5-
6-
// Theme tokens
7-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
8-
const flattenTokens = {
9-
...tokens,
10-
colors: {
11-
type: "light",
12-
...tokens.colors.common,
13-
...tokens.colors.light,
14-
},
15-
};
3+
import type { HvThemeBreakpoints } from "./tokens/breakpoints";
4+
import type { HvThemeColors } from "./tokens/colors";
5+
import type { HvThemeRadii } from "./tokens/radii";
6+
import { sizes } from "./tokens/sizes";
7+
import { HvThemeSpace, space } from "./tokens/space";
8+
import {
9+
fontFamily,
10+
fontSizes,
11+
fontWeights,
12+
lineHeights,
13+
} from "./tokens/typography";
14+
import { zIndices } from "./tokens/zIndices";
1615

1716
interface CSSProperties extends StandardProperties<string | number> {}
1817

19-
export type HvThemeTokens = typeof flattenTokens;
18+
/** @experimental extendable theme spacing units */
19+
export interface HvThemeZIndices
20+
extends Record<keyof typeof zIndices, number> {}
21+
22+
/** UI Kit static theme tokens */
23+
export interface HvThemeTokens {
24+
breakpoints: HvThemeBreakpoints;
25+
colors: { type: HvThemeColorModeType } & HvThemeColors;
26+
radii: HvThemeRadii;
27+
space: HvThemeSpace;
28+
/** @deprecated use `theme.space` or the direct value instead */
29+
sizes: typeof sizes;
30+
// #region typography
31+
fontFamily: typeof fontFamily;
32+
fontSizes: typeof fontSizes;
33+
fontWeights: typeof fontWeights;
34+
lineHeights: typeof lineHeights;
35+
// #endregion
36+
zIndices: HvThemeZIndices;
37+
}
2038

2139
/** Theme components props */
2240
export interface HvThemeComponentsProps {
@@ -68,7 +86,7 @@ export interface HvThemeComponents {
6886
}
6987

7088
// Theme typography
71-
// TODO: allow arbitrary `CSSProperties` overrides
89+
// TODO: remove in favor of `CSSProperties` when supported
7290
export interface HvThemeTypographyProps
7391
extends Pick<
7492
CSSProperties,
@@ -98,13 +116,10 @@ export interface HvThemeTypography {
98116
}
99117

100118
// Breakpoints
101-
export type HvThemeBreakpoint = Exclude<keyof typeof tokens.space, "base">;
119+
export type HvThemeBreakpoint = Exclude<keyof typeof space, "base">;
102120

103121
export type SpacingValue = number | HvThemeBreakpoint | (string & {});
104122

105-
// Theme colors
106-
export type HvThemeColors = typeof colors.common & typeof colors.light;
107-
108123
// Base themes: DS3 and DS5
109124
export type HvBaseTheme = "ds3" | "ds5" | "pentahoPlus";
110125

@@ -121,7 +136,7 @@ export interface HvThemeColorModeStructure
121136
type: HvThemeColorModeType;
122137
}
123138

124-
// Theme structure
139+
/** Complete theme structure and values */
125140
export interface HvThemeStructure<Mode extends string = string>
126141
extends HvThemeComponents,
127142
HvThemeComponentsProps,
@@ -136,21 +151,17 @@ export interface HvThemeStructure<Mode extends string = string>
136151

137152
// Custom theme
138153
export interface HvCustomTheme<Mode extends string = string>
139-
extends HvThemeComponents,
140-
HvThemeComponentsProps,
141-
HvThemeTypography,
142-
Partial<Omit<HvThemeTokens, "colors">> {
143-
name: string;
144-
colors: {
145-
modes: Record<Mode, Partial<HvThemeColorModeStructure>>;
146-
};
147-
}
154+
extends DeepPartial<Omit<HvThemeStructure<Mode>, "base">> {}
148155

149156
// Deep string: set all props to strings
150157
export type DeepString<T> = {
151158
[P in keyof T]: T[P] extends object ? DeepString<T[P]> : string;
152159
};
153160

161+
type DeepPartial<T> = T extends {}
162+
? Partial<{ [P in keyof T]: DeepPartial<T[P]> }>
163+
: T;
164+
154165
// Theme CSS vars
155166
export interface HvThemeVars
156167
extends DeepString<HvThemeTokens>,

0 commit comments

Comments
 (0)