@vellira-ui/tokens 2.100.0 → 2.101.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 (58) hide show
  1. package/README.md +88 -39
  2. package/css.d.ts +1 -0
  3. package/dist/css/tokens.css +1 -0
  4. package/dist/dark/semantic/focus.d.ts +1 -1
  5. package/dist/dark/semantic/focus.d.ts.map +1 -1
  6. package/dist/dark/semantic/focus.js +2 -1
  7. package/dist/dark/semantic/shadow.d.ts +5 -5
  8. package/dist/dark/semantic/shadow.d.ts.map +1 -1
  9. package/dist/dark/semantic/shadow.js +2 -7
  10. package/dist/dark/theme.d.ts +25 -24
  11. package/dist/dark/theme.d.ts.map +1 -1
  12. package/dist/effects/shadow-system.d.ts +181 -0
  13. package/dist/effects/shadow-system.d.ts.map +1 -0
  14. package/dist/effects/shadow-system.js +134 -0
  15. package/dist/generated/token-types.d.ts +4 -4
  16. package/dist/generated/token-types.d.ts.map +1 -1
  17. package/dist/generated/token-types.js +4 -0
  18. package/dist/highContrast/semantic/focus.d.ts +1 -1
  19. package/dist/highContrast/semantic/focus.d.ts.map +1 -1
  20. package/dist/highContrast/semantic/focus.js +2 -1
  21. package/dist/highContrast/semantic/shadow.d.ts +5 -5
  22. package/dist/highContrast/semantic/shadow.d.ts.map +1 -1
  23. package/dist/highContrast/semantic/shadow.js +2 -7
  24. package/dist/highContrast/theme.d.ts +25 -24
  25. package/dist/highContrast/theme.d.ts.map +1 -1
  26. package/dist/index.d.ts +30 -24
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +5 -0
  29. package/dist/light/semantic/focus.d.ts +1 -1
  30. package/dist/light/semantic/focus.d.ts.map +1 -1
  31. package/dist/light/semantic/focus.js +2 -1
  32. package/dist/light/semantic/shadow.d.ts +5 -5
  33. package/dist/light/semantic/shadow.d.ts.map +1 -1
  34. package/dist/light/semantic/shadow.js +2 -7
  35. package/dist/light/theme.d.ts +25 -24
  36. package/dist/light/theme.d.ts.map +1 -1
  37. package/dist/platform-output/component-token-intents.d.ts +4 -20
  38. package/dist/platform-output/component-token-intents.d.ts.map +1 -1
  39. package/dist/platform-output/component-token-intents.js +12 -12
  40. package/dist/platform-output/component-token-web-compatibility.d.ts +44 -3
  41. package/dist/platform-output/component-token-web-compatibility.d.ts.map +1 -1
  42. package/dist/platform-output/component-token-web-compatibility.js +44 -3
  43. package/dist/preservation/token-migrations.d.ts +6 -0
  44. package/dist/preservation/token-migrations.d.ts.map +1 -1
  45. package/dist/preservation/token-migrations.js +8 -0
  46. package/dist/public-api-policy.d.ts +30 -0
  47. package/dist/public-api-policy.d.ts.map +1 -0
  48. package/dist/public-api-policy.js +26 -0
  49. package/dist/token-architecture.d.ts +3 -3
  50. package/dist/token-architecture.d.ts.map +1 -1
  51. package/dist/token-architecture.js +7 -2
  52. package/dist/tokens/shadows.d.ts +24 -24
  53. package/dist/tokens/shadows.d.ts.map +1 -1
  54. package/dist/tokens/shadows.js +2 -27
  55. package/dist/tokens/typography.d.ts +2 -0
  56. package/dist/tokens/typography.d.ts.map +1 -1
  57. package/dist/tokens/typography.js +1 -0
  58. package/package.json +6 -2
package/README.md CHANGED
@@ -23,31 +23,37 @@ pnpm add @vellira-ui/tokens
23
23
 
24
24
  ## Usage
25
25
 
26
+ Choose a named theme explicitly:
27
+
26
28
  ```ts
27
- import {
28
- darkTheme,
29
- highContrastTheme,
30
- lightTheme,
31
- theme,
32
- } from '@vellira-ui/tokens';
33
-
34
- theme.semantic.surface.default;
35
- theme.semantic.text.primary;
36
- theme.semantic.border.default;
37
- theme.semantic.status.success.fg;
38
-
39
- theme.components.button.primary.solid.default.bg;
40
- theme.components.input.default.bg;
41
-
42
- theme.tokens.typography.family.regular;
43
- theme.tokens.spacing[4];
44
- theme.tokens.radius.md;
45
-
46
- lightTheme.name;
47
- darkTheme.name;
48
- highContrastTheme.name;
29
+ import { darkTheme, highContrastTheme, lightTheme } from '@vellira-ui/tokens';
30
+
31
+ darkTheme.semantic.surface.default;
32
+ darkTheme.semantic.surface.panel;
33
+ darkTheme.semantic.text.primary;
34
+ darkTheme.semantic.border.default;
35
+ darkTheme.semantic.status.success.fg;
36
+
37
+ darkTheme.components.button.primary.solid.default.bg;
38
+ darkTheme.components.input.default.bg;
39
+
40
+ darkTheme.tokens.typography.family.regular;
41
+ darkTheme.tokens.spacing[4];
42
+ darkTheme.tokens.radius.md;
43
+
44
+ lightTheme.name; // 'light'
45
+ darkTheme.name; // 'dark'
46
+ highContrastTheme.name; // 'high-contrast'
49
47
  ```
50
48
 
49
+ There is no implicit current/default JavaScript theme object. The historical
50
+ `theme` export is a deprecated partial view of `darkTheme`; use `darkTheme`
51
+ directly. The compatibility export is scheduled for removal in Vellira 3.0.0.
52
+
53
+ The generated Web CSS separately uses Light values for `:root`, so pages without
54
+ a theme attribute have a deterministic browser fallback. That CSS default does
55
+ not make `lightTheme` an implicit JavaScript default.
56
+
51
57
  ## Semantic Tokens
52
58
 
53
59
  The package provides semantic groups that describe intent instead of coupling
@@ -62,7 +68,6 @@ Current semantic groups include:
62
68
  - `focus`
63
69
  - `icons`
64
70
  - `menu`
65
- - `navigation`
66
71
  - `overlay`
67
72
  - `shadow`
68
73
  - `skeleton`
@@ -73,18 +78,23 @@ Current semantic groups include:
73
78
  Example:
74
79
 
75
80
  ```ts
76
- theme.semantic.surface.default;
77
- theme.semantic.surface.elevated;
81
+ darkTheme.semantic.surface.canvas;
82
+ darkTheme.semantic.surface.panel;
83
+ darkTheme.semantic.surface.elevated;
78
84
 
79
- theme.semantic.text.primary;
80
- theme.semantic.text.secondary;
85
+ darkTheme.semantic.text.primary;
86
+ darkTheme.semantic.text.secondary;
81
87
 
82
- theme.semantic.border.default;
88
+ darkTheme.semantic.border.default;
83
89
 
84
- theme.semantic.status.success.fg;
85
- theme.semantic.status.error.fg;
90
+ darkTheme.semantic.status.success.fg;
91
+ darkTheme.semantic.status.error.fg;
86
92
  ```
87
93
 
94
+ `surface.canvas` is the application/root backdrop, `surface.panel` is bounded
95
+ neutral container/chrome, and `surface.elevated` is reserved for genuinely
96
+ raised or floating layers.
97
+
88
98
  Using semantic tokens instead of raw palette values keeps component styling
89
99
  consistent across renderers and themes.
90
100
 
@@ -94,12 +104,12 @@ Component tokens define renderer-neutral values for component states and
94
104
  surfaces.
95
105
 
96
106
  ```ts
97
- theme.components.button.primary.solid.default.bg;
98
- theme.components.input.focus.border;
99
- theme.components.dropdown.content.bg;
100
- theme.components.popover.content.bg;
101
- theme.components.modal.content.bg;
102
- theme.components.tooltip.content.bg;
107
+ darkTheme.components.button.primary.solid.default.bg;
108
+ darkTheme.components.input.focus.border;
109
+ darkTheme.components.dropdown.content.bg;
110
+ darkTheme.components.popover.content.bg;
111
+ darkTheme.components.modal.content.bg;
112
+ darkTheme.components.tooltip.content.bg;
103
113
  ```
104
114
 
105
115
  Color-like component tokens may use either colors or the literal `transparent`
@@ -117,12 +127,51 @@ Examples:
117
127
 
118
128
  ```css
119
129
  --color-mono-0
120
- --surface-default
130
+ --surface-canvas
131
+ --surface-panel
121
132
  --text-primary
122
133
  --border-default
123
134
  --button-primary-solid-default-bg
124
135
  ```
125
136
 
137
+ Canonical token-path types describe only the current renderer-neutral token
138
+ contract. During Vellira 2.x, a bounded set of legacy CSS variables is still
139
+ generated for migration compatibility. Those aliases remain in the generated
140
+ CSS-variable name unions because they are actually emitted, but they are not
141
+ canonical `TokenPath`/`ComponentTokenPath` entries and new code must not adopt
142
+ them.
143
+
144
+ The compatibility aliases, replacements, migration evidence, and removal
145
+ release are tracked in
146
+ `src/platform-output/component-token-web-compatibility.ts`. They are scheduled
147
+ for removal in Vellira 3.0.0.
148
+
149
+ ## Public API deprecation policy
150
+
151
+ Public token/theme cleanup follows one bounded policy:
152
+
153
+ - named theme objects are canonical (`lightTheme`, `darkTheme`,
154
+ `highContrastTheme`);
155
+ - deprecated root exports preserve their existing behavior during the 2.x
156
+ compatibility window and name a canonical replacement;
157
+ - deprecated Web CSS variables remain platform-output aliases only and do not
158
+ re-enter canonical token-path unions;
159
+ - every alias has migration/preservation evidence and an explicit removal
160
+ boundary;
161
+ - Token Architecture Normalization V1 removes these compatibility aliases at
162
+ Vellira 3.0.0 unless a separately reviewed policy revision supersedes it.
163
+
164
+ The machine-readable contract lives in `src/public-api-policy.ts`. The detailed
165
+ architecture note is `docs/architecture/token-public-api-v1.md`.
166
+
167
+ ## React and React Native
168
+
169
+ The shared theme/token source is renderer-neutral. React/Web consumers can use
170
+ named theme objects or generated CSS variables. React Native consumes the same
171
+ canonical component intent and resolves platform representation through the
172
+ native output adapter; renderer-specific token branches are not part of the
173
+ public canonical component contract.
174
+
126
175
  ## Documentation
127
176
 
128
177
  - [Design Tokens](https://docs.vellira.dev/design-system/tokens)
@@ -170,8 +219,8 @@ The preservation contract covers the complete current public visual surface:
170
219
  overlay primitives and control-size values;
171
220
  - generated Web CSS variable names together with their serialized values, using
172
221
  the same serializer as the published `@vellira-ui/tokens/css` artifact;
173
- - the current React Native output contract, which consumes the canonical theme
174
- objects directly until a dedicated native platform adapter is introduced.
222
+ - the current React Native output contract derived from canonical component
223
+ intents and platform adapters.
175
224
 
176
225
  Normal token changes must not regenerate the baseline just to make a failure
177
226
  disappear. Instead, record the change in
package/css.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -38,6 +38,7 @@
38
38
  --font-weight-regular: 400;
39
39
  --font-weight-medium: 500;
40
40
  --font-weight-semibold: 600;
41
+ --font-weight-bold: 700;
41
42
  --font-size-xs: 12px;
42
43
  --font-size-sm: 14px;
43
44
  --font-size-md: 16px;
@@ -2,7 +2,7 @@ export declare const focus: {
2
2
  readonly ring: {
3
3
  readonly color: "#B8A8FF";
4
4
  readonly width: "2px";
5
- readonly shadow: "0 0 8px rgba(184, 168, 255, 0.14)";
5
+ readonly shadow: string;
6
6
  readonly offsetColor: "#181521";
7
7
  };
8
8
  };
@@ -1 +1 @@
1
- {"version":3,"file":"focus.d.ts","sourceRoot":"","sources":["../../../src/dark/semantic/focus.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,KAAK;;;;;;;CAOR,CAAC"}
1
+ {"version":3,"file":"focus.d.ts","sourceRoot":"","sources":["../../../src/dark/semantic/focus.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,KAAK;;;;;;;CAOR,CAAC"}
@@ -1,9 +1,10 @@
1
+ import { createFocusRingShadowToken } from '../../effects/shadow-system.js';
1
2
  import { colors } from '../../primitives/colors.js';
2
3
  export const focus = {
3
4
  ring: {
4
5
  color: colors.primary[300],
5
6
  width: '2px',
6
- shadow: '0 0 8px rgba(184, 168, 255, 0.14)',
7
+ shadow: createFocusRingShadowToken('dark'),
7
8
  offsetColor: colors.vellira[950],
8
9
  },
9
10
  };
@@ -1,8 +1,8 @@
1
1
  export declare const shadow: {
2
- readonly sm: "0 1px 2px rgba(0, 0, 0, 0.12)";
3
- readonly md: "0 4px 12px rgba(0, 0, 0, 0.22)";
4
- readonly lg: "0 12px 40px rgba(0, 0, 0, 0.35), 0 2px 8px rgba(0, 0, 0, 0.25)";
5
- readonly xl: "0 20px 60px rgba(0, 0, 0, 0.45), 0 4px 16px rgba(0, 0, 0, 0.3)";
6
- readonly inset: "inset 0 1px 0 rgba(255, 255, 255, 0.06)";
2
+ readonly sm: string;
3
+ readonly md: string;
4
+ readonly lg: string;
5
+ readonly xl: string;
6
+ readonly inset: string;
7
7
  };
8
8
  //# sourceMappingURL=shadow.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shadow.d.ts","sourceRoot":"","sources":["../../../src/dark/semantic/shadow.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM;;;;;;CAMT,CAAC"}
1
+ {"version":3,"file":"shadow.d.ts","sourceRoot":"","sources":["../../../src/dark/semantic/shadow.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,MAAM;;;;;;CAAqC,CAAC"}
@@ -1,7 +1,2 @@
1
- export const shadow = {
2
- sm: '0 1px 2px rgba(0, 0, 0, 0.12)',
3
- md: '0 4px 12px rgba(0, 0, 0, 0.22)',
4
- lg: '0 12px 40px rgba(0, 0, 0, 0.35), 0 2px 8px rgba(0, 0, 0, 0.25)',
5
- xl: '0 20px 60px rgba(0, 0, 0, 0.45), 0 4px 16px rgba(0, 0, 0, 0.3)',
6
- inset: 'inset 0 1px 0 rgba(255, 255, 255, 0.06)',
7
- };
1
+ import { createSemanticShadowTokens } from '../../effects/shadow-system.js';
2
+ export const shadow = createSemanticShadowTokens('dark');
@@ -152,30 +152,30 @@ export declare const darkTheme: {
152
152
  readonly full: 999;
153
153
  };
154
154
  readonly shadows: {
155
- readonly sm: {
156
- readonly x: 0;
157
- readonly y: 1;
158
- readonly blur: 3;
159
- readonly color: "#000000";
160
- readonly opacity: 0.04;
161
- readonly elevation: 1;
162
- };
163
- readonly md: {
164
- readonly x: 0;
165
- readonly y: 6;
166
- readonly blur: 16;
167
- readonly color: "#000000";
168
- readonly opacity: 0.08;
169
- readonly elevation: 4;
170
- };
171
- readonly lg: {
172
- readonly x: 0;
173
- readonly y: 12;
174
- readonly blur: 32;
175
- readonly color: "#000000";
176
- readonly opacity: 0.1;
177
- readonly elevation: 8;
178
- };
155
+ readonly sm: Readonly<{
156
+ x: number;
157
+ y: number;
158
+ blur: number;
159
+ color: string;
160
+ opacity: number;
161
+ elevation: number;
162
+ }>;
163
+ readonly md: Readonly<{
164
+ x: number;
165
+ y: number;
166
+ blur: number;
167
+ color: string;
168
+ opacity: number;
169
+ elevation: number;
170
+ }>;
171
+ readonly lg: Readonly<{
172
+ x: number;
173
+ y: number;
174
+ blur: number;
175
+ color: string;
176
+ opacity: number;
177
+ elevation: number;
178
+ }>;
179
179
  };
180
180
  readonly spacing: {
181
181
  readonly 0: 0;
@@ -213,6 +213,7 @@ export declare const darkTheme: {
213
213
  readonly regular: "400";
214
214
  readonly medium: "500";
215
215
  readonly semibold: "600";
216
+ readonly bold: "700";
216
217
  };
217
218
  readonly lineHeight: {
218
219
  readonly xs: 16;
@@ -1 +1 @@
1
- {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/dark/theme.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,UAAU,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAEhD,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYZ,CAAC"}
1
+ {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/dark/theme.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,UAAU,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAEhD,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYZ,CAAC"}
@@ -0,0 +1,181 @@
1
+ export declare const shadowThemeNames: readonly ["light", "dark", "high-contrast"];
2
+ export type ShadowThemeName = (typeof shadowThemeNames)[number];
3
+ export declare const elevationShadowLevels: readonly ["sm", "md", "lg", "xl"];
4
+ export type ElevationShadowLevel = (typeof elevationShadowLevels)[number];
5
+ export type ShadowLayer = Readonly<{
6
+ x: number;
7
+ y: number;
8
+ blur: number;
9
+ spread: number;
10
+ color: string;
11
+ opacity: number;
12
+ inset: boolean;
13
+ }>;
14
+ export type ShadowEffect = Readonly<{
15
+ layers: readonly ShadowLayer[];
16
+ }>;
17
+ export type ReactNativeShadowOutput = Readonly<{
18
+ x: number;
19
+ y: number;
20
+ blur: number;
21
+ color: string;
22
+ opacity: number;
23
+ elevation: number;
24
+ }>;
25
+ export declare const canonicalShadowEffects: {
26
+ readonly elevation: {
27
+ readonly sm: {
28
+ readonly themes: {
29
+ readonly light: Readonly<{
30
+ layers: readonly ShadowLayer[];
31
+ }>;
32
+ readonly dark: Readonly<{
33
+ layers: readonly ShadowLayer[];
34
+ }>;
35
+ readonly 'high-contrast': Readonly<{
36
+ layers: readonly ShadowLayer[];
37
+ }>;
38
+ };
39
+ readonly reactNativeApproximation: {
40
+ readonly kind: "direct";
41
+ readonly output: Readonly<{
42
+ x: number;
43
+ y: number;
44
+ blur: number;
45
+ color: string;
46
+ opacity: number;
47
+ elevation: number;
48
+ }>;
49
+ };
50
+ };
51
+ readonly md: {
52
+ readonly themes: {
53
+ readonly light: Readonly<{
54
+ layers: readonly ShadowLayer[];
55
+ }>;
56
+ readonly dark: Readonly<{
57
+ layers: readonly ShadowLayer[];
58
+ }>;
59
+ readonly 'high-contrast': Readonly<{
60
+ layers: readonly ShadowLayer[];
61
+ }>;
62
+ };
63
+ readonly reactNativeApproximation: {
64
+ readonly kind: "direct";
65
+ readonly output: Readonly<{
66
+ x: number;
67
+ y: number;
68
+ blur: number;
69
+ color: string;
70
+ opacity: number;
71
+ elevation: number;
72
+ }>;
73
+ };
74
+ };
75
+ readonly lg: {
76
+ readonly themes: {
77
+ readonly light: Readonly<{
78
+ layers: readonly ShadowLayer[];
79
+ }>;
80
+ readonly dark: Readonly<{
81
+ layers: readonly ShadowLayer[];
82
+ }>;
83
+ readonly 'high-contrast': Readonly<{
84
+ layers: readonly ShadowLayer[];
85
+ }>;
86
+ };
87
+ readonly reactNativeApproximation: {
88
+ readonly kind: "direct";
89
+ readonly output: Readonly<{
90
+ x: number;
91
+ y: number;
92
+ blur: number;
93
+ color: string;
94
+ opacity: number;
95
+ elevation: number;
96
+ }>;
97
+ };
98
+ };
99
+ readonly xl: {
100
+ readonly themes: {
101
+ readonly light: Readonly<{
102
+ layers: readonly ShadowLayer[];
103
+ }>;
104
+ readonly dark: Readonly<{
105
+ layers: readonly ShadowLayer[];
106
+ }>;
107
+ readonly 'high-contrast': Readonly<{
108
+ layers: readonly ShadowLayer[];
109
+ }>;
110
+ };
111
+ readonly reactNativeApproximation: {
112
+ readonly kind: "reference";
113
+ readonly level: "lg";
114
+ readonly reason: "React Native preserves the pre-unification Modal output by approximating xl with lg.";
115
+ };
116
+ };
117
+ };
118
+ readonly inset: {
119
+ readonly themes: {
120
+ readonly light: Readonly<{
121
+ layers: readonly ShadowLayer[];
122
+ }>;
123
+ readonly dark: Readonly<{
124
+ layers: readonly ShadowLayer[];
125
+ }>;
126
+ readonly 'high-contrast': Readonly<{
127
+ layers: readonly ShadowLayer[];
128
+ }>;
129
+ };
130
+ };
131
+ readonly focusRing: {
132
+ readonly themes: {
133
+ readonly light: Readonly<{
134
+ layers: readonly ShadowLayer[];
135
+ }>;
136
+ readonly dark: Readonly<{
137
+ layers: readonly ShadowLayer[];
138
+ }>;
139
+ readonly 'high-contrast': Readonly<{
140
+ layers: readonly ShadowLayer[];
141
+ }>;
142
+ };
143
+ };
144
+ };
145
+ export declare function serializeShadowEffectForWeb(value: ShadowEffect): string;
146
+ export declare function createSemanticShadowTokens(themeName: ShadowThemeName): {
147
+ readonly sm: string;
148
+ readonly md: string;
149
+ readonly lg: string;
150
+ readonly xl: string;
151
+ readonly inset: string;
152
+ };
153
+ export declare function createFocusRingShadowToken(themeName: ShadowThemeName): string;
154
+ export declare function resolveReactNativeElevationShadow(level: ElevationShadowLevel): ReactNativeShadowOutput;
155
+ export declare function createReactNativeShadowTokens(): {
156
+ readonly sm: Readonly<{
157
+ x: number;
158
+ y: number;
159
+ blur: number;
160
+ color: string;
161
+ opacity: number;
162
+ elevation: number;
163
+ }>;
164
+ readonly md: Readonly<{
165
+ x: number;
166
+ y: number;
167
+ blur: number;
168
+ color: string;
169
+ opacity: number;
170
+ elevation: number;
171
+ }>;
172
+ readonly lg: Readonly<{
173
+ x: number;
174
+ y: number;
175
+ blur: number;
176
+ color: string;
177
+ opacity: number;
178
+ elevation: number;
179
+ }>;
180
+ };
181
+ //# sourceMappingURL=shadow-system.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shadow-system.d.ts","sourceRoot":"","sources":["../../src/effects/shadow-system.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,gBAAgB,6CAA8C,CAAC;AAC5E,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhE,eAAO,MAAM,qBAAqB,mCAAoC,CAAC;AACvE,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1E,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC;IACjC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC;IAClC,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC;CAChC,CAAC,CAAC;AAEH,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAAC;IAC7C,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CAAC;AAsDH,eAAO,MAAM,sBAAsB;;;;;4BAhEzB,SAAS,WAAW,EAAE;;;4BAAtB,SAAS,WAAW,EAAE;;;4BAAtB,SAAS,WAAW,EAAE;;;;;;uBAI3B,MAAM;uBACN,MAAM;0BACH,MAAM;2BACL,MAAM;6BACJ,MAAM;+BACJ,MAAM;;;;;;;4BATT,SAAS,WAAW,EAAE;;;4BAAtB,SAAS,WAAW,EAAE;;;4BAAtB,SAAS,WAAW,EAAE;;;;;;uBAI3B,MAAM;uBACN,MAAM;0BACH,MAAM;2BACL,MAAM;6BACJ,MAAM;+BACJ,MAAM;;;;;;;4BATT,SAAS,WAAW,EAAE;;;4BAAtB,SAAS,WAAW,EAAE;;;4BAAtB,SAAS,WAAW,EAAE;;;;;;uBAI3B,MAAM;uBACN,MAAM;0BACH,MAAM;2BACL,MAAM;6BACJ,MAAM;+BACJ,MAAM;;;;;;;4BATT,SAAS,WAAW,EAAE;;;4BAAtB,SAAS,WAAW,EAAE;;;4BAAtB,SAAS,WAAW,EAAE;;;;;;;;;;;;;wBAAtB,SAAS,WAAW,EAAE;;;wBAAtB,SAAS,WAAW,EAAE;;;wBAAtB,SAAS,WAAW,EAAE;;;;;;;wBAAtB,SAAS,WAAW,EAAE;;;wBAAtB,SAAS,WAAW,EAAE;;;wBAAtB,SAAS,WAAW,EAAE;;;;CAkIW,CAAC;AA2D5C,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAMvE;AAED,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,eAAe;;;;;;EAkBpE;AAED,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,eAAe,GAAG,MAAM,CAI7E;AAED,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,oBAAoB,GAC1B,uBAAuB,CASzB;AAED,wBAAgB,6BAA6B;;WAxOxC,MAAM;WACN,MAAM;cACH,MAAM;eACL,MAAM;iBACJ,MAAM;mBACJ,MAAM;;;WALd,MAAM;WACN,MAAM;cACH,MAAM;eACL,MAAM;iBACJ,MAAM;mBACJ,MAAM;;;WALd,MAAM;WACN,MAAM;cACH,MAAM;eACL,MAAM;iBACJ,MAAM;mBACJ,MAAM;;EAyOlB"}
@@ -0,0 +1,134 @@
1
+ import { colors } from '../primitives/colors.js';
2
+ export const shadowThemeNames = ['light', 'dark', 'high-contrast'];
3
+ export const elevationShadowLevels = ['sm', 'md', 'lg', 'xl'];
4
+ const effect = (...layers) => ({ layers });
5
+ const layer = (x, y, blur, spread, color, opacity, inset = false) => ({ x, y, blur, spread, color, opacity, inset });
6
+ const nativeShadow = (x, y, blur, color, opacity, elevation) => ({ x, y, blur, color, opacity, elevation });
7
+ const nativeSm = nativeShadow(0, 1, 3, colors.mono[950], 0.04, 1);
8
+ const nativeMd = nativeShadow(0, 6, 16, colors.mono[950], 0.08, 4);
9
+ const nativeLg = nativeShadow(0, 12, 32, colors.mono[950], 0.1, 8);
10
+ export const canonicalShadowEffects = {
11
+ elevation: {
12
+ sm: {
13
+ themes: {
14
+ light: effect(layer(0, 1, 2, 0, colors.vellira[950], 0.08)),
15
+ dark: effect(layer(0, 1, 2, 0, colors.mono[950], 0.12)),
16
+ 'high-contrast': effect(layer(0, 1, 2, 0, colors.mono[950], 0.5)),
17
+ },
18
+ reactNativeApproximation: { kind: 'direct', output: nativeSm },
19
+ },
20
+ md: {
21
+ themes: {
22
+ light: effect(layer(0, 4, 12, 0, colors.vellira[950], 0.12)),
23
+ dark: effect(layer(0, 4, 12, 0, colors.mono[950], 0.22)),
24
+ 'high-contrast': effect(layer(0, 4, 12, 0, colors.mono[950], 0.6)),
25
+ },
26
+ reactNativeApproximation: { kind: 'direct', output: nativeMd },
27
+ },
28
+ lg: {
29
+ themes: {
30
+ light: effect(layer(0, 12, 40, 0, colors.vellira[950], 0.16), layer(0, 2, 8, 0, colors.vellira[950], 0.1)),
31
+ dark: effect(layer(0, 12, 40, 0, colors.mono[950], 0.35), layer(0, 2, 8, 0, colors.mono[950], 0.25)),
32
+ 'high-contrast': effect(layer(0, 12, 40, 0, colors.mono[950], 0.7)),
33
+ },
34
+ reactNativeApproximation: { kind: 'direct', output: nativeLg },
35
+ },
36
+ xl: {
37
+ themes: {
38
+ light: effect(layer(0, 20, 60, 0, colors.vellira[950], 0.2), layer(0, 4, 16, 0, colors.vellira[950], 0.14)),
39
+ dark: effect(layer(0, 20, 60, 0, colors.mono[950], 0.45), layer(0, 4, 16, 0, colors.mono[950], 0.3)),
40
+ 'high-contrast': effect(layer(0, 20, 60, 0, colors.mono[950], 0.8)),
41
+ },
42
+ reactNativeApproximation: {
43
+ kind: 'reference',
44
+ level: 'lg',
45
+ reason: 'React Native preserves the pre-unification Modal output by approximating xl with lg.',
46
+ },
47
+ },
48
+ },
49
+ inset: {
50
+ themes: {
51
+ light: effect(layer(0, 1, 0, 0, colors.mono[50], 0.55, true)),
52
+ dark: effect(layer(0, 1, 0, 0, colors.mono[50], 0.06, true)),
53
+ 'high-contrast': effect(layer(0, 1, 0, 0, colors.mono[50], 0.14, true)),
54
+ },
55
+ },
56
+ focusRing: {
57
+ themes: {
58
+ light: effect(layer(0, 0, 8, 0, colors.primary[600], 0.14)),
59
+ dark: effect(layer(0, 0, 8, 0, colors.primary[300], 0.14)),
60
+ 'high-contrast': effect(layer(0, 0, 0, 1, colors.mono[50], 0.28)),
61
+ },
62
+ },
63
+ };
64
+ function parseHexColor(color) {
65
+ const match = color.match(/^#([0-9a-f]{6})$/i);
66
+ if (!match) {
67
+ throw new Error(`Shadow layer color must be a six-digit hex value, received ${color}.`);
68
+ }
69
+ const value = match[1];
70
+ return [
71
+ Number.parseInt(value.slice(0, 2), 16),
72
+ Number.parseInt(value.slice(2, 4), 16),
73
+ Number.parseInt(value.slice(4, 6), 16),
74
+ ];
75
+ }
76
+ function formatLength(value) {
77
+ if (!Number.isFinite(value)) {
78
+ throw new Error(`Shadow length must be finite, received ${value}.`);
79
+ }
80
+ return value === 0 ? '0' : `${value}px`;
81
+ }
82
+ function serializeLayerForWeb(value) {
83
+ if (!Number.isFinite(value.blur) || value.blur < 0) {
84
+ throw new Error(`Shadow blur must be finite and non-negative, received ${value.blur}.`);
85
+ }
86
+ if (!Number.isFinite(value.opacity) ||
87
+ value.opacity < 0 ||
88
+ value.opacity > 1) {
89
+ throw new Error(`Shadow opacity must be finite and within [0, 1], received ${value.opacity}.`);
90
+ }
91
+ const [red, green, blue] = parseHexColor(value.color);
92
+ const lengths = [
93
+ formatLength(value.x),
94
+ formatLength(value.y),
95
+ formatLength(value.blur),
96
+ ];
97
+ if (value.spread !== 0) {
98
+ lengths.push(formatLength(value.spread));
99
+ }
100
+ const color = `rgba(${red}, ${green}, ${blue}, ${value.opacity})`;
101
+ return `${value.inset ? 'inset ' : ''}${lengths.join(' ')} ${color}`;
102
+ }
103
+ export function serializeShadowEffectForWeb(value) {
104
+ if (value.layers.length === 0) {
105
+ throw new Error('Shadow effect must contain at least one layer.');
106
+ }
107
+ return value.layers.map(serializeLayerForWeb).join(', ');
108
+ }
109
+ export function createSemanticShadowTokens(themeName) {
110
+ return {
111
+ sm: serializeShadowEffectForWeb(canonicalShadowEffects.elevation.sm.themes[themeName]),
112
+ md: serializeShadowEffectForWeb(canonicalShadowEffects.elevation.md.themes[themeName]),
113
+ lg: serializeShadowEffectForWeb(canonicalShadowEffects.elevation.lg.themes[themeName]),
114
+ xl: serializeShadowEffectForWeb(canonicalShadowEffects.elevation.xl.themes[themeName]),
115
+ inset: serializeShadowEffectForWeb(canonicalShadowEffects.inset.themes[themeName]),
116
+ };
117
+ }
118
+ export function createFocusRingShadowToken(themeName) {
119
+ return serializeShadowEffectForWeb(canonicalShadowEffects.focusRing.themes[themeName]);
120
+ }
121
+ export function resolveReactNativeElevationShadow(level) {
122
+ const approximation = canonicalShadowEffects.elevation[level].reactNativeApproximation;
123
+ if (approximation.kind === 'direct') {
124
+ return approximation.output;
125
+ }
126
+ return resolveReactNativeElevationShadow(approximation.level);
127
+ }
128
+ export function createReactNativeShadowTokens() {
129
+ return {
130
+ sm: resolveReactNativeElevationShadow('sm'),
131
+ md: resolveReactNativeElevationShadow('md'),
132
+ lg: resolveReactNativeElevationShadow('lg'),
133
+ };
134
+ }