@kalink-ui/seedly 0.34.3 → 0.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +34 -0
  3. package/docs/component-theming.md +295 -0
  4. package/docs/theming-strategy.md +69 -0
  5. package/docs/tone-system.md +139 -0
  6. package/docs/value-and-scope.md +65 -0
  7. package/package.json +4 -3
  8. package/src/components/alert-dialog/alert-dialog-action.tsx +0 -2
  9. package/src/components/alert-dialog/alert-dialog-cancel.tsx +0 -1
  10. package/src/components/alert-dialog/alert-dialog-content.css.ts +1 -1
  11. package/src/components/alert-dialog/alert-dialog-content.tsx +13 -6
  12. package/src/components/alert-dialog/alert-dialog-footer.css.ts +3 -3
  13. package/src/components/alert-dialog/alert-dialog-footer.tsx +2 -2
  14. package/src/components/alert-dialog/alert-dialog-header.tsx +4 -4
  15. package/src/components/alert-dialog/index.ts +9 -0
  16. package/src/components/box/box.css.ts +137 -39
  17. package/src/components/box/box.responsive.ts +2 -2
  18. package/src/components/box/box.tsx +2 -3
  19. package/src/components/box/index.ts +1 -1
  20. package/src/components/button/button.css.ts +142 -149
  21. package/src/components/button/button.responsive.ts +2 -2
  22. package/src/components/button/button.tsx +44 -31
  23. package/src/components/button/index.ts +2 -2
  24. package/src/components/button-icon/button-icon.css.ts +26 -62
  25. package/src/components/button-icon/button-icon.responsive.ts +2 -2
  26. package/src/components/button-icon/button-icon.tsx +5 -7
  27. package/src/components/card/card.css.ts +1 -5
  28. package/src/components/card/card.tsx +11 -11
  29. package/src/components/center/center.css.ts +61 -21
  30. package/src/components/center/center.responsive.ts +2 -2
  31. package/src/components/center/center.tsx +4 -6
  32. package/src/components/center/index.ts +1 -1
  33. package/src/components/cluster/cluster.css.ts +37 -99
  34. package/src/components/cluster/cluster.responsive.ts +13 -2
  35. package/src/components/cluster/cluster.tsx +6 -5
  36. package/src/components/cluster/index.ts +5 -1
  37. package/src/components/command/command-empty.tsx +36 -4
  38. package/src/components/command/command-group.css.ts +23 -7
  39. package/src/components/command/command-group.tsx +30 -6
  40. package/src/components/command/command-input.css.ts +2 -2
  41. package/src/components/command/command-item.tsx +26 -2
  42. package/src/components/command/command-list.css.ts +2 -2
  43. package/src/components/command/command-list.responsive.ts +2 -2
  44. package/src/components/command/command-list.tsx +1 -2
  45. package/src/components/command/command-separator.tsx +7 -5
  46. package/src/components/cover/cover.css.ts +29 -8
  47. package/src/components/cover/cover.tsx +13 -13
  48. package/src/components/cover/index.ts +2 -2
  49. package/src/components/divider/divider.css.ts +9 -4
  50. package/src/components/form-field/form-field-context.ts +3 -0
  51. package/src/components/form-field/form-field-item.tsx +3 -3
  52. package/src/components/form-field/form-field-message.tsx +34 -3
  53. package/src/components/form-field/form-field.css.ts +78 -16
  54. package/src/components/form-field/form-field.tsx +5 -0
  55. package/src/components/form-field/index.ts +1 -1
  56. package/src/components/frame/frame.css.ts +96 -59
  57. package/src/components/frame/frame.responsive.ts +9 -0
  58. package/src/components/frame/frame.tsx +11 -5
  59. package/src/components/frame/index.ts +1 -1
  60. package/src/components/grid/grid-child.tsx +14 -10
  61. package/src/components/grid/grid.css.ts +56 -148
  62. package/src/components/grid/grid.tsx +40 -18
  63. package/src/components/grid/index.ts +4 -3
  64. package/src/components/heading/heading.css.ts +4 -4
  65. package/src/components/heading/heading.responsive.ts +6 -6
  66. package/src/components/heading/heading.tsx +3 -4
  67. package/src/components/heading/index.ts +1 -1
  68. package/src/components/input/index.ts +4 -1
  69. package/src/components/input/input-wrapper.tsx +20 -8
  70. package/src/components/input/input.css.ts +121 -93
  71. package/src/components/input/input.responsive.ts +9 -0
  72. package/src/components/input/input.tsx +7 -1
  73. package/src/components/label/label.css.ts +2 -2
  74. package/src/components/label/label.tsx +23 -3
  75. package/src/components/layout-maps.ts +120 -0
  76. package/src/components/loader/index.ts +2 -1
  77. package/src/components/loader/loader.css.ts +91 -54
  78. package/src/components/loader/moon-loader.responsive.ts +2 -2
  79. package/src/components/loader/moon-loader.tsx +4 -5
  80. package/src/components/loader-overlay/loader-overlay.css.ts +3 -3
  81. package/src/components/loader-overlay/loader-overlay.tsx +5 -2
  82. package/src/components/menu/index.ts +2 -2
  83. package/src/components/menu/menu-item.css.ts +102 -46
  84. package/src/components/menu/menu-separator.css.ts +27 -15
  85. package/src/components/menu/menu-separator.responsive.ts +2 -2
  86. package/src/components/overlay/overlay.css.ts +1 -1
  87. package/src/components/popover/index.ts +1 -1
  88. package/src/components/popover/popover-content.css.ts +69 -52
  89. package/src/components/popover/popover-content.tsx +22 -6
  90. package/src/components/scroll-area/scroll-area.css.ts +3 -3
  91. package/src/components/scroll-area/scroll-bar.tsx +2 -2
  92. package/src/components/select/index.ts +4 -5
  93. package/src/components/select/select-content.css.ts +1 -1
  94. package/src/components/select/select-content.tsx +2 -2
  95. package/src/components/select/select-item.tsx +11 -3
  96. package/src/components/select/select-trigger.css.ts +14 -18
  97. package/src/components/select/select-trigger.tsx +18 -8
  98. package/src/components/select/select.tsx +10 -6
  99. package/src/components/sheet/index.ts +12 -0
  100. package/src/components/sheet/sheet-content.css.ts +2 -2
  101. package/src/components/sheet/sheet-content.tsx +25 -7
  102. package/src/components/sheet/sheet-description.tsx +5 -7
  103. package/src/components/sheet/sheet-footer.tsx +3 -1
  104. package/src/components/sheet/sheet-header.css.ts +1 -1
  105. package/src/components/sheet/sheet-header.tsx +3 -3
  106. package/src/components/sheet/sheet-overlay.tsx +3 -4
  107. package/src/components/sheet/sheet-title.tsx +1 -1
  108. package/src/components/sidebar/index.ts +5 -1
  109. package/src/components/sidebar/sidebar.css.ts +35 -9
  110. package/src/components/sidebar/sidebar.tsx +7 -10
  111. package/src/components/skeleton/skeleton.css.ts +23 -14
  112. package/src/components/skeleton/skeleton.tsx +26 -7
  113. package/src/components/stack/index.ts +1 -1
  114. package/src/components/stack/stack.css.ts +18 -46
  115. package/src/components/stack/stack.tsx +1 -2
  116. package/src/components/switcher/index.ts +5 -1
  117. package/src/components/switcher/switcher.css.ts +105 -72
  118. package/src/components/switcher/switcher.responsive.ts +2 -2
  119. package/src/components/switcher/switcher.tsx +5 -5
  120. package/src/components/text/text.css.ts +93 -105
  121. package/src/components/text/text.responsive.ts +3 -63
  122. package/src/components/text/text.tsx +16 -28
  123. package/src/components/text-field/index.ts +1 -2
  124. package/src/components/text-field/text-field.tsx +5 -7
  125. package/src/components/textarea/textarea-input.tsx +30 -3
  126. package/src/components/textarea/textarea.css.ts +12 -7
  127. package/src/components/textarea/textarea.tsx +9 -3
  128. package/src/components/visually-hidden/visually-hidden.css.ts +16 -10
  129. package/src/styles/define-responsive-properties.ts +5 -1
  130. package/src/styles/index.ts +12 -0
  131. package/src/styles/responsive.ts +72 -43
  132. package/src/styles/system-contract.css.ts +22 -3
  133. package/src/styles/theme/sprout-ref.css.ts +107 -0
  134. package/src/styles/theme/sprout.css.ts +259 -0
  135. package/src/styles/tone.ts +69 -0
  136. package/src/styles/typography.responsive.css.ts +35 -0
  137. package/src/styles/typography.responsive.ts +104 -0
  138. package/src/utils/arg-types/index.ts +1 -0
  139. package/src/utils/arg-types/responsive-arg.ts +28 -0
  140. package/src/utils/index.ts +1 -0
  141. package/src/components/command/command-item.css.ts +0 -32
  142. package/src/components/select/select.css.ts +0 -3
  143. package/src/components/sheet/sheet-body.css.ts +0 -68
  144. package/src/components/text-field/text-field.css.ts +0 -3
@@ -8,12 +8,34 @@ export type BreakpointWithBase = 'xs' | BreakpointKey;
8
8
  export type ResponsiveObject<T, B extends string> = Partial<
9
9
  Record<Exclude<B, 'xs'>, T>
10
10
  > & { xs?: T };
11
+
11
12
  export type ResponsiveArray<T> = (T | null | undefined)[];
13
+
12
14
  export type Responsive<T, B extends string = BreakpointWithBase> =
13
15
  | T
14
16
  | ResponsiveObject<T, B>
15
17
  | ResponsiveArray<T>;
16
18
 
19
+ function entriesOf<K extends string | number, V>(
20
+ record: Partial<Record<K, V>>,
21
+ ): [K, V][] {
22
+ return Object.entries(record) as [K, V][];
23
+ }
24
+
25
+ function recordFromEntries<K extends string | number, V>(
26
+ entries: [K, V][],
27
+ ): Record<K, V> {
28
+ return Object.fromEntries(entries) as Record<K, V>;
29
+ }
30
+
31
+ function styleVariantsWithArrays<
32
+ Variants extends Record<string | number, StyleRule | StyleRule[]>,
33
+ >(variants: Variants): { [K in keyof Variants]: string } {
34
+ return styleVariants(variants as Record<string, StyleRule>) as {
35
+ [K in keyof Variants]: string;
36
+ };
37
+ }
38
+
17
39
  export function resolveResponsive<T, B extends string = BreakpointWithBase>(
18
40
  value: Responsive<T, B> | undefined,
19
41
  order: readonly B[],
@@ -26,10 +48,10 @@ export function resolveResponsive<T, B extends string = BreakpointWithBase>(
26
48
  const out: Partial<Record<B, T>> = {};
27
49
 
28
50
  value.forEach((val, i) => {
29
- const breakpoint = order[i] as B | undefined;
51
+ const breakpoint = order[i];
30
52
 
31
- if (val != null && breakpoint) {
32
- out[breakpoint] = val as T;
53
+ if (val != null && breakpoint != null) {
54
+ out[breakpoint] = val;
33
55
  }
34
56
  });
35
57
 
@@ -40,7 +62,16 @@ export function resolveResponsive<T, B extends string = BreakpointWithBase>(
40
62
  return value as Partial<Record<B, T>>;
41
63
  }
42
64
 
43
- return { xs: value as T } as Partial<Record<B, T>>;
65
+ return { xs: value } as Partial<Record<B, T>>;
66
+ }
67
+
68
+ export function getResponsiveBase<T>(
69
+ value: Responsive<T> | undefined,
70
+ order: readonly BreakpointWithBase[] = defaultOrder,
71
+ ): T | undefined {
72
+ const map = resolveResponsive(value, order);
73
+
74
+ return map.xs;
44
75
  }
45
76
 
46
77
  export interface CreateResponsiveVariantsArgs<
@@ -57,23 +88,17 @@ export function createResponsiveVariants<
57
88
  >(args: CreateResponsiveVariantsArgs<VariantValues, Bps>) {
58
89
  const { styles, media } = args;
59
90
 
60
- const at = Object.fromEntries(
61
- Object.entries(media).map(([bp, query]) => {
62
- const styleEntries = Object.entries(styles) as [
63
- VariantValues,
64
- StyleRule | StyleRule[],
65
- ][];
66
-
67
- const styleMap = Object.fromEntries(
68
- styleEntries.map(([val, rule]) => [
69
- val,
70
- applyMedia(query as string, rule),
71
- ]),
72
- ) as Record<VariantValues, StyleRule | StyleRule[]>;
73
-
74
- return [bp, styleVariants(styleMap)];
91
+ const at = recordFromEntries(
92
+ entriesOf(media).map(([bp, query]) => {
93
+ const styleMap = recordFromEntries(
94
+ entriesOf<VariantValues, StyleRule | StyleRule[]>(styles).map(
95
+ ([val, rule]) => [val, applyMedia(query, rule)],
96
+ ),
97
+ );
98
+
99
+ return [bp, styleVariantsWithArrays(styleMap)];
75
100
  }),
76
- ) as Record<Exclude<Bps, 'xs'>, Record<VariantValues, string>>;
101
+ );
77
102
 
78
103
  return at;
79
104
  }
@@ -83,10 +108,10 @@ function applyMedia(
83
108
  rule: StyleRule | StyleRule[],
84
109
  ): StyleRule | StyleRule[] {
85
110
  if (Array.isArray(rule)) {
86
- return rule.map((r) => ({ '@media': { [query]: r } })) as StyleRule[];
111
+ return rule.map((r) => ({ '@media': { [query]: r } }));
87
112
  }
88
113
 
89
- return { '@media': { [query]: rule } } as StyleRule;
114
+ return { '@media': { [query]: rule } };
90
115
  }
91
116
 
92
117
  type MakeResponsive<V, B extends string> = {
@@ -95,9 +120,7 @@ type MakeResponsive<V, B extends string> = {
95
120
 
96
121
  export interface ResponsiveRecipeArgs<V, Bps extends string> {
97
122
  recipe: (props: V) => string;
98
- at: Partial<
99
- Record<keyof V, Record<Exclude<Bps, 'xs'>, Record<string, string>>>
100
- >;
123
+ at: Partial<Record<keyof V, Partial<Record<Bps, Record<string, string>>>>>;
101
124
  order: readonly Bps[];
102
125
  }
103
126
 
@@ -106,31 +129,37 @@ export function responsiveRecipe<
106
129
  const Bps extends string,
107
130
  >(args: ResponsiveRecipeArgs<V, Bps>) {
108
131
  const { recipe, at, order } = args;
132
+ type ClassValue = Parameters<typeof clsx>[number];
109
133
 
110
- return (props: MakeResponsive<V, Bps> & { className?: string }) => {
111
- const { className, ...rest } = props as Record<string, unknown> & {
112
- className?: string;
113
- };
134
+ return (props: MakeResponsive<V, Bps>, ...classNames: ClassValue[]) => {
135
+ const responsiveRest = props as MakeResponsive<V, Bps>;
136
+ const keys = Object.keys(responsiveRest) as (keyof V)[];
114
137
 
115
138
  const baseProps: Partial<V> = {};
116
139
 
117
- for (const key in rest) {
118
- const value = (rest as Record<string, unknown>)[key];
119
- const map = resolveResponsive(value, order);
140
+ for (const key of keys) {
141
+ const value = responsiveRest[key];
142
+ const map = resolveResponsive<unknown, Bps>(
143
+ value as Responsive<unknown, Bps> | undefined,
144
+ order,
145
+ );
146
+
147
+ const baseValue =
148
+ (map as Partial<Record<BreakpointWithBase, unknown>>).xs ?? value;
120
149
 
121
- (baseProps as Record<string, unknown>)[key] =
122
- (map as Record<string, unknown>)['xs'] ?? value;
150
+ baseProps[key] = baseValue as V[typeof key];
123
151
  }
124
152
 
125
153
  const base = recipe(baseProps as V);
126
154
  const overrides: string[] = [];
127
155
 
128
- for (const key in rest) {
129
- const value = (rest as Record<string, unknown>)[key];
130
- const map = resolveResponsive(value, order);
131
- const variantAt = (at as Record<string, unknown>)[key] as
132
- | Record<string, Record<string, string>>
133
- | undefined;
156
+ for (const key of keys) {
157
+ const value = responsiveRest[key];
158
+ const variantAt = at[key];
159
+ const map = resolveResponsive<unknown, Bps>(
160
+ value as Responsive<unknown, Bps> | undefined,
161
+ order,
162
+ );
134
163
 
135
164
  if (!variantAt) {
136
165
  continue;
@@ -141,13 +170,13 @@ export function responsiveRecipe<
141
170
  continue;
142
171
  }
143
172
 
144
- const val = (map as Partial<Record<Bps, unknown>>)[bp];
173
+ const val = map[bp];
145
174
 
146
175
  if (val == null) {
147
176
  continue;
148
177
  }
149
178
 
150
- const cls = variantAt[bp as string]?.[String(val)];
179
+ const cls = variantAt[bp]?.[String(val)];
151
180
 
152
181
  if (cls) {
153
182
  overrides.push(cls);
@@ -155,7 +184,7 @@ export function responsiveRecipe<
155
184
  }
156
185
  }
157
186
 
158
- return clsx(base, ...overrides, className);
187
+ return clsx(base, ...overrides, ...classNames);
159
188
  };
160
189
  }
161
190
 
@@ -19,17 +19,31 @@ const typographyVariants = [
19
19
 
20
20
  const typographySizes = ['large', 'medium', 'small'] as const;
21
21
 
22
+ const toneNames = ['neutral', 'primary', 'destructive', 'success'] as const;
23
+
24
+ export type Tone = ArrayValues<typeof toneNames>;
25
+ type ToneOnName = `on${Capitalize<Tone>}`;
26
+
22
27
  export const sys = createThemeContract({
23
28
  layout: {
24
29
  direction: null,
25
30
  measure: null,
26
31
  },
27
32
 
28
- color: {
33
+ surface: {
29
34
  background: null,
30
35
  foreground: null,
31
36
  },
32
37
 
38
+ tone: toneNames.reduce(
39
+ (acc, tone) => ({
40
+ ...acc,
41
+ [tone]: null,
42
+ [`on${tone[0]?.toUpperCase()}${tone.slice(1)}`]: null,
43
+ }),
44
+ {} as Record<Tone | ToneOnName, null>,
45
+ ),
46
+
33
47
  state: {
34
48
  hovered: {
35
49
  opacity: null,
@@ -41,8 +55,13 @@ export const sys = createThemeContract({
41
55
  opacity: null,
42
56
  },
43
57
  muted: {
44
- light: null,
45
- dark: null,
58
+ text: null,
59
+ surface: null,
60
+ },
61
+ disabled: {
62
+ text: null,
63
+ border: null,
64
+ background: null,
46
65
  },
47
66
  },
48
67
 
@@ -0,0 +1,107 @@
1
+ import { createGlobalTheme } from '@vanilla-extract/css';
2
+
3
+ import { base } from '../layers.css';
4
+ import { toFluidClampFor } from '../scale';
5
+
6
+ const spacingClamp = (value: number) =>
7
+ toFluidClampFor(value, {
8
+ lowMin: 4,
9
+ lowMax: 72,
10
+ highMin: 6,
11
+ highMax: 176,
12
+ exponent: 2,
13
+ rounding: 'none',
14
+ });
15
+
16
+ const typeScaleClamp = (value: number) =>
17
+ toFluidClampFor(value, {
18
+ lowMin: 12,
19
+ lowMax: 40,
20
+ highMin: 14,
21
+ highMax: 85,
22
+ exponent: 2,
23
+ rounding: 'none',
24
+ });
25
+
26
+ export const refs = createGlobalTheme(':root', {
27
+ '@layer': base,
28
+
29
+ colors: {
30
+ neutral: {
31
+ 0: '#000000',
32
+ 10: '#161c1d',
33
+ 20: '#2c383a',
34
+ 30: '#435456',
35
+ 40: '#597173',
36
+ 50: '#6f8d90',
37
+ 60: '#8ca4a6',
38
+ 70: '#a9bbbc',
39
+ 80: '#c5d1d3',
40
+ 90: '#e2e8e9',
41
+ 100: '#ffffff',
42
+ },
43
+ primary: {
44
+ 0: '#000000',
45
+ 10: '#1a1110',
46
+ 20: '#401d10',
47
+ 30: '#7f3a1a',
48
+ 40: '#bf5b21',
49
+ 50: '#f27f1b',
50
+ 60: '#f2a950',
51
+ 70: '#e6bd8a',
52
+ 80: '#e4cebc',
53
+ 90: '#ece8e2',
54
+ 100: '#ffffff',
55
+ },
56
+ },
57
+
58
+ typeface: {
59
+ brand: 'serif',
60
+ plain: 'sans-serif',
61
+ },
62
+
63
+ lineHeight: {
64
+ md: '1',
65
+ lg: '1.2',
66
+ xl: '1.4',
67
+ },
68
+
69
+ spacing: {
70
+ 1: spacingClamp(4),
71
+ 2: spacingClamp(8),
72
+ 3: spacingClamp(12),
73
+ 4: spacingClamp(16),
74
+ 5: spacingClamp(20),
75
+ 6: spacingClamp(24),
76
+ 7: spacingClamp(28),
77
+ 8: spacingClamp(32),
78
+ 9: spacingClamp(36),
79
+ 10: spacingClamp(40),
80
+ 11: spacingClamp(44),
81
+ 12: spacingClamp(48),
82
+ 13: spacingClamp(52),
83
+ 14: spacingClamp(56),
84
+ 15: spacingClamp(60),
85
+ 16: spacingClamp(64),
86
+ 17: spacingClamp(68),
87
+ 18: spacingClamp(72),
88
+ },
89
+
90
+ typeScale: {
91
+ displayLarge: typeScaleClamp(40),
92
+ displayMedium: typeScaleClamp(34),
93
+ displaySmall: typeScaleClamp(28),
94
+ headlineLarge: typeScaleClamp(32),
95
+ headlineMedium: typeScaleClamp(28),
96
+ headlineSmall: typeScaleClamp(24),
97
+ titleLarge: typeScaleClamp(24),
98
+ titleMedium: typeScaleClamp(18),
99
+ titleSmall: typeScaleClamp(17),
100
+ bodyLarge: typeScaleClamp(19),
101
+ bodyMedium: typeScaleClamp(14),
102
+ bodySmall: typeScaleClamp(12),
103
+ labelLarge: typeScaleClamp(16),
104
+ labelMedium: typeScaleClamp(14),
105
+ labelSmall: typeScaleClamp(12),
106
+ },
107
+ });
@@ -0,0 +1,259 @@
1
+ import { createTheme } from '@vanilla-extract/css';
2
+
3
+ import { sys } from '../system-contract.css';
4
+
5
+ import { refs } from './sprout-ref.css';
6
+
7
+ export const sprout = createTheme(sys, {
8
+ layout: {
9
+ measure: '75ch',
10
+ direction: '1',
11
+ },
12
+
13
+ surface: {
14
+ background: refs.colors.neutral[100],
15
+ foreground: refs.colors.neutral[10],
16
+ },
17
+
18
+ tone: {
19
+ neutral: refs.colors.neutral[10],
20
+ onNeutral: refs.colors.neutral[90],
21
+ primary: refs.colors.primary[50],
22
+ onPrimary: refs.colors.primary[10],
23
+ destructive: '#d80000',
24
+ onDestructive: refs.colors.neutral[100],
25
+ success: '#2e7d32',
26
+ onSuccess: refs.colors.neutral[100],
27
+ },
28
+
29
+ state: {
30
+ hovered: {
31
+ opacity: '0.1',
32
+ },
33
+ focused: {
34
+ opacity: '0.12',
35
+ },
36
+ pressed: {
37
+ opacity: '0.2',
38
+ },
39
+ muted: {
40
+ text: '0.6',
41
+ surface: '0.12',
42
+ },
43
+ disabled: {
44
+ text: '0.5',
45
+ border: '0.12',
46
+ background: '0.08',
47
+ },
48
+ },
49
+
50
+ shape: {
51
+ corner: {
52
+ none: '0',
53
+ sharp: '0.125rem',
54
+ small: '0.25rem',
55
+ medium: '0.5rem',
56
+ rounded: '0.75rem',
57
+ circle: '50%',
58
+ },
59
+ },
60
+
61
+ elevation: {
62
+ none: 'none',
63
+ minimal:
64
+ '0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)',
65
+ low: '0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)',
66
+ moderate:
67
+ '0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)',
68
+ high: '0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)',
69
+ peak: '0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)',
70
+ },
71
+
72
+ motion: {
73
+ duration: {
74
+ short: {
75
+ 1: '50ms',
76
+ 2: '100ms',
77
+ 3: '150ms',
78
+ 4: '200ms',
79
+ },
80
+ medium: {
81
+ 1: '250ms',
82
+ 2: '300ms',
83
+ 3: '350ms',
84
+ 4: '400ms',
85
+ },
86
+ long: {
87
+ 1: '450ms',
88
+ 2: '500ms',
89
+ 3: '550ms',
90
+ 4: '600ms',
91
+ },
92
+ },
93
+ easing: {
94
+ standard: 'cubic-bezier(0.2, 0, 0, 1)',
95
+ decelerate: {
96
+ standard: 'cubic-bezier(0.4, 0, 1, 1)',
97
+ emphasized: 'cubic-bezier(0.05, 0.7, 0.1, 1)',
98
+ },
99
+ accelerate: {
100
+ standard: 'cubic-bezier(0.4, 0, 1, 1)',
101
+ emphasized: 'cubic-bezier(0.3, 0, 0.8, 0.15)',
102
+ },
103
+ },
104
+ },
105
+
106
+ typography: {
107
+ display: {
108
+ large: {
109
+ font: refs.typeface.brand,
110
+ weight: '700',
111
+ lineHeight: refs.lineHeight.md,
112
+ tracking: '0.1',
113
+ size: refs.typeScale.displayLarge,
114
+ },
115
+
116
+ medium: {
117
+ font: refs.typeface.brand,
118
+ weight: '700',
119
+ lineHeight: refs.lineHeight.md,
120
+ tracking: '0.1',
121
+ size: refs.typeScale.displayMedium,
122
+ },
123
+
124
+ small: {
125
+ font: refs.typeface.brand,
126
+ weight: '700',
127
+ lineHeight: refs.lineHeight.md,
128
+ tracking: '0.1',
129
+ size: refs.typeScale.displaySmall,
130
+ },
131
+ },
132
+
133
+ headline: {
134
+ large: {
135
+ font: refs.typeface.brand,
136
+ weight: '700',
137
+ lineHeight: refs.lineHeight.md,
138
+ tracking: '0.1',
139
+ size: refs.typeScale.headlineLarge,
140
+ },
141
+
142
+ medium: {
143
+ font: refs.typeface.brand,
144
+ weight: '700',
145
+ lineHeight: refs.lineHeight.md,
146
+ tracking: '0.1',
147
+ size: refs.typeScale.headlineMedium,
148
+ },
149
+
150
+ small: {
151
+ font: refs.typeface.brand,
152
+ weight: '700',
153
+ lineHeight: refs.lineHeight.md,
154
+ tracking: '0.1',
155
+ size: refs.typeScale.headlineSmall,
156
+ },
157
+ },
158
+
159
+ title: {
160
+ large: {
161
+ font: refs.typeface.brand,
162
+ weight: '700',
163
+ lineHeight: refs.lineHeight.md,
164
+ tracking: '0.1',
165
+ size: refs.typeScale.titleLarge,
166
+ },
167
+
168
+ medium: {
169
+ font: refs.typeface.brand,
170
+ weight: '700',
171
+ lineHeight: refs.lineHeight.md,
172
+ tracking: '0.1',
173
+ size: refs.typeScale.titleMedium,
174
+ },
175
+
176
+ small: {
177
+ font: refs.typeface.brand,
178
+ weight: '700',
179
+ lineHeight: refs.lineHeight.md,
180
+ tracking: '0.1',
181
+ size: refs.typeScale.titleSmall,
182
+ },
183
+ },
184
+
185
+ body: {
186
+ large: {
187
+ font: refs.typeface.plain,
188
+ weight: '400',
189
+ lineHeight: refs.lineHeight.lg,
190
+ tracking: 'normal',
191
+ size: refs.typeScale.bodyLarge,
192
+ },
193
+
194
+ medium: {
195
+ font: refs.typeface.plain,
196
+ weight: '400',
197
+ lineHeight: refs.lineHeight.xl,
198
+ tracking: 'normal',
199
+ size: refs.typeScale.bodyMedium,
200
+ },
201
+
202
+ small: {
203
+ font: refs.typeface.plain,
204
+ weight: '400',
205
+ lineHeight: refs.lineHeight.lg,
206
+ tracking: 'normal',
207
+ size: refs.typeScale.bodySmall,
208
+ },
209
+ },
210
+
211
+ label: {
212
+ large: {
213
+ font: refs.typeface.plain,
214
+ weight: '700',
215
+ lineHeight: refs.lineHeight.xl,
216
+ tracking: '0.1',
217
+ size: refs.typeScale.labelLarge,
218
+ },
219
+
220
+ medium: {
221
+ font: refs.typeface.plain,
222
+ weight: '700',
223
+ lineHeight: refs.lineHeight.lg,
224
+ tracking: '0.1',
225
+ size: refs.typeScale.labelMedium,
226
+ },
227
+
228
+ small: {
229
+ font: refs.typeface.plain,
230
+ weight: '700',
231
+ lineHeight: refs.lineHeight.md,
232
+ tracking: '0.1',
233
+ size: refs.typeScale.labelSmall,
234
+ },
235
+ },
236
+ },
237
+
238
+ spacing: {
239
+ 0: '0px',
240
+ 1: refs.spacing[1],
241
+ 2: refs.spacing[2],
242
+ 3: refs.spacing[3],
243
+ 4: refs.spacing[4],
244
+ 5: refs.spacing[5],
245
+ 6: refs.spacing[6],
246
+ 7: refs.spacing[7],
247
+ 8: refs.spacing[8],
248
+ 9: refs.spacing[9],
249
+ 10: refs.spacing[10],
250
+ 11: refs.spacing[11],
251
+ 12: refs.spacing[12],
252
+ 13: refs.spacing[13],
253
+ 14: refs.spacing[14],
254
+ 15: refs.spacing[15],
255
+ 16: refs.spacing[16],
256
+ 17: refs.spacing[17],
257
+ 18: refs.spacing[18],
258
+ },
259
+ });
@@ -0,0 +1,69 @@
1
+ import { assignVars, type StyleRule } from '@vanilla-extract/css';
2
+
3
+ import { components } from './layers.css';
4
+ import { sys } from './system-contract.css';
5
+
6
+ export type ToneKey = 'neutral' | 'primary' | 'destructive' | 'success';
7
+ export interface ToneTokens {
8
+ base: string;
9
+ onBase: string;
10
+ }
11
+
12
+ export const toneTokens: Record<ToneKey, ToneTokens> = {
13
+ neutral: {
14
+ base: sys.tone.neutral,
15
+ onBase: sys.tone.onNeutral,
16
+ },
17
+ primary: {
18
+ base: sys.tone.primary,
19
+ onBase: sys.tone.onPrimary,
20
+ },
21
+ destructive: {
22
+ base: sys.tone.destructive,
23
+ onBase: sys.tone.onDestructive,
24
+ },
25
+ success: {
26
+ base: sys.tone.success,
27
+ onBase: sys.tone.onSuccess,
28
+ },
29
+ };
30
+
31
+ type ToneVarContract = Parameters<typeof assignVars>[0];
32
+
33
+ /**
34
+ * assignVars requires the contract and tokens to be the same inferred shape;
35
+ * we centralize the escape-hatch cast here so callers don't repeat it.
36
+ */
37
+ const assignTone = (toneVars: ToneVarContract, tokens: ToneTokens) =>
38
+ assignVars(toneVars as never, tokens as never);
39
+
40
+ export const createToneAssignments = (toneVars: ToneVarContract) =>
41
+ ({
42
+ neutral: assignTone(toneVars, toneTokens.neutral),
43
+ primary: assignTone(toneVars, toneTokens.primary),
44
+ destructive: assignTone(toneVars, toneTokens.destructive),
45
+ success: assignTone(toneVars, toneTokens.success),
46
+ }) as const;
47
+
48
+ export const createToneStyles = (
49
+ toneVars: ToneVarContract,
50
+ getVars?: (tokens: ToneTokens, tone: ToneKey) => Record<string, string>,
51
+ ) => {
52
+ const toneAssignments = createToneAssignments(toneVars);
53
+ const styles = {} as Record<ToneKey, StyleRule>;
54
+
55
+ (Object.keys(toneAssignments) as ToneKey[]).forEach((tone) => {
56
+ styles[tone] = {
57
+ '@layer': {
58
+ [components]: {
59
+ vars: {
60
+ ...toneAssignments[tone],
61
+ ...(getVars ? getVars(toneTokens[tone], tone) : {}),
62
+ },
63
+ },
64
+ },
65
+ };
66
+ });
67
+
68
+ return styles;
69
+ };