@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.
- package/README.md +88 -39
- package/css.d.ts +1 -0
- package/dist/css/tokens.css +1 -0
- package/dist/dark/semantic/focus.d.ts +1 -1
- package/dist/dark/semantic/focus.d.ts.map +1 -1
- package/dist/dark/semantic/focus.js +2 -1
- package/dist/dark/semantic/shadow.d.ts +5 -5
- package/dist/dark/semantic/shadow.d.ts.map +1 -1
- package/dist/dark/semantic/shadow.js +2 -7
- package/dist/dark/theme.d.ts +25 -24
- package/dist/dark/theme.d.ts.map +1 -1
- package/dist/effects/shadow-system.d.ts +181 -0
- package/dist/effects/shadow-system.d.ts.map +1 -0
- package/dist/effects/shadow-system.js +134 -0
- package/dist/generated/token-types.d.ts +4 -4
- package/dist/generated/token-types.d.ts.map +1 -1
- package/dist/generated/token-types.js +4 -0
- package/dist/highContrast/semantic/focus.d.ts +1 -1
- package/dist/highContrast/semantic/focus.d.ts.map +1 -1
- package/dist/highContrast/semantic/focus.js +2 -1
- package/dist/highContrast/semantic/shadow.d.ts +5 -5
- package/dist/highContrast/semantic/shadow.d.ts.map +1 -1
- package/dist/highContrast/semantic/shadow.js +2 -7
- package/dist/highContrast/theme.d.ts +25 -24
- package/dist/highContrast/theme.d.ts.map +1 -1
- package/dist/index.d.ts +30 -24
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/light/semantic/focus.d.ts +1 -1
- package/dist/light/semantic/focus.d.ts.map +1 -1
- package/dist/light/semantic/focus.js +2 -1
- package/dist/light/semantic/shadow.d.ts +5 -5
- package/dist/light/semantic/shadow.d.ts.map +1 -1
- package/dist/light/semantic/shadow.js +2 -7
- package/dist/light/theme.d.ts +25 -24
- package/dist/light/theme.d.ts.map +1 -1
- package/dist/platform-output/component-token-intents.d.ts +4 -20
- package/dist/platform-output/component-token-intents.d.ts.map +1 -1
- package/dist/platform-output/component-token-intents.js +12 -12
- package/dist/platform-output/component-token-web-compatibility.d.ts +44 -3
- package/dist/platform-output/component-token-web-compatibility.d.ts.map +1 -1
- package/dist/platform-output/component-token-web-compatibility.js +44 -3
- package/dist/preservation/token-migrations.d.ts +6 -0
- package/dist/preservation/token-migrations.d.ts.map +1 -1
- package/dist/preservation/token-migrations.js +8 -0
- package/dist/public-api-policy.d.ts +30 -0
- package/dist/public-api-policy.d.ts.map +1 -0
- package/dist/public-api-policy.js +26 -0
- package/dist/token-architecture.d.ts +3 -3
- package/dist/token-architecture.d.ts.map +1 -1
- package/dist/token-architecture.js +7 -2
- package/dist/tokens/shadows.d.ts +24 -24
- package/dist/tokens/shadows.d.ts.map +1 -1
- package/dist/tokens/shadows.js +2 -27
- package/dist/tokens/typography.d.ts +2 -0
- package/dist/tokens/typography.d.ts.map +1 -1
- package/dist/tokens/typography.js +1 -0
- 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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
77
|
-
|
|
81
|
+
darkTheme.semantic.surface.canvas;
|
|
82
|
+
darkTheme.semantic.surface.panel;
|
|
83
|
+
darkTheme.semantic.surface.elevated;
|
|
78
84
|
|
|
79
|
-
|
|
80
|
-
|
|
85
|
+
darkTheme.semantic.text.primary;
|
|
86
|
+
darkTheme.semantic.text.secondary;
|
|
81
87
|
|
|
82
|
-
|
|
88
|
+
darkTheme.semantic.border.default;
|
|
83
89
|
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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-
|
|
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
|
|
174
|
-
|
|
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 {};
|
package/dist/css/tokens.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"focus.d.ts","sourceRoot":"","sources":["../../../src/dark/semantic/focus.ts"],"names":[],"mappings":"
|
|
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: '
|
|
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:
|
|
3
|
-
readonly md:
|
|
4
|
-
readonly lg:
|
|
5
|
-
readonly xl:
|
|
6
|
-
readonly inset:
|
|
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":"
|
|
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
|
-
|
|
2
|
-
|
|
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');
|
package/dist/dark/theme.d.ts
CHANGED
|
@@ -152,30 +152,30 @@ export declare const darkTheme: {
|
|
|
152
152
|
readonly full: 999;
|
|
153
153
|
};
|
|
154
154
|
readonly shadows: {
|
|
155
|
-
readonly sm: {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
163
|
-
readonly md: {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
}
|
|
171
|
-
readonly lg: {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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;
|
package/dist/dark/theme.d.ts.map
CHANGED
|
@@ -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
|
|
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
|
+
}
|