@weasel-js/theme 1.5.1 → 1.6.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/dist/tokens.css CHANGED
@@ -18,6 +18,9 @@
18
18
  /* Midnight blue-violet. Deep and saturated; anchors primary actions on light and dark surfaces alike. */
19
19
  --wzl-accent-base: #2e1f7a;
20
20
  --wzl-accent-strong: #5841b8;
21
+ --wzl-secondary-soft: #704e09;
22
+ --wzl-secondary-base: #dc9d15;
23
+ --wzl-secondary-strong: #f1cb8d;
21
24
  /* First of ten categorical spot colors for plotting, status and data viz. Take them in sequence: the order is farthest-point over hue, so the first N are as separated as N colors can be (first three 87° apart, all ten 32°). Mode-invariant on purpose — a series keeps its color when the mode flips, which is why they are tuned for a dark surface and clear only 1.5:1 on a light one. */
22
25
  --wzl-swatch-fuchsia: #f641f7;
23
26
  --wzl-swatch-green: #48e628;
@@ -29,6 +32,26 @@
29
32
  --wzl-swatch-citron: #d5d23a;
30
33
  --wzl-swatch-rose: #fa4590;
31
34
  --wzl-swatch-violet: #955cf9;
35
+ /* Shortcut keys and index badges. The floor for chrome text. */
36
+ --wzl-font-size-2xs: 9px;
37
+ /* Tool-button labels under an icon. */
38
+ --wzl-font-size-xs: 10px;
39
+ /* Chrome labels, status readouts, section headings. */
40
+ --wzl-font-size-sm: 11px;
41
+ /* Controls and body text. */
42
+ --wzl-font-size-md: 13px;
43
+ /* Panel and dialog titles. */
44
+ --wzl-font-size-lg: 16px;
45
+ /* The largest chrome text — a lab or app title. */
46
+ --wzl-font-size-xl: 20px;
47
+ --wzl-space-1: 2px;
48
+ --wzl-space-2: 4px;
49
+ --wzl-space-3: 6px;
50
+ --wzl-space-4: 8px;
51
+ --wzl-space-5: 10px;
52
+ --wzl-space-6: 12px;
53
+ --wzl-space-7: 14px;
54
+ --wzl-space-8: 16px;
32
55
  --wzl-surface: var(--wzl-gray-800);
33
56
  --wzl-surface-raised: var(--wzl-gray-700);
34
57
  --wzl-surface-sunken: var(--wzl-gray-900);
@@ -40,10 +63,55 @@
40
63
  --wzl-border-strong: var(--wzl-gray-400);
41
64
  /* Accent for foreground use — text, icons, selected labels drawn on a surface. accent is a fill; the midnight base is too dim to read as text on dark surfaces. */
42
65
  --wzl-accent-fg: var(--wzl-accent-strong);
66
+ /* Secondary accent for foreground use: a second voice beside the accent, such as a value the panel derived rather than one the user set. Picked from the ramp so it clears 4.5:1 on the surface in both modes. */
67
+ --wzl-secondary-fg: var(--wzl-secondary-base);
43
68
  /* Text drawn on a filled foreground-colored element (e.g. a slider thumb). Flips with the mode, so it is a semantic, not an alias to a primitive. */
44
69
  --wzl-fg-inverse: var(--wzl-gray-900);
45
70
  /* Elevation. Always darker than any surface — never derived from fg, which is near-white on dark. */
46
71
  --wzl-shadow: rgba(0, 0, 0, 0.6);
72
+ /* Fill of a PropertyPanel. */
73
+ --wzl-panel-surface: var(--wzl-surface-raised);
74
+ --wzl-panel-border-color: var(--wzl-border);
75
+ --wzl-panel-border-style: solid;
76
+ --wzl-panel-border-width: 1px;
77
+ --wzl-panel-radius: var(--wzl-radius-lg);
78
+ /* A panel’s padding when no density sets one. */
79
+ --wzl-panel-pad: 14px 16px;
80
+ --wzl-panel-blur: var(--wzl-glass-blur);
81
+ /* How much of a panel’s tone mixes into its surface. */
82
+ --wzl-panel-tone-mix: 14%;
83
+ --wzl-panel-title-font: var(--wzl-font-display);
84
+ --wzl-panel-title-weight: var(--wzl-font-weight-light);
85
+ --wzl-panel-title-size: var(--wzl-font-size-lg);
86
+ --wzl-panel-title-case: none;
87
+ --wzl-panel-title-tracking: 0.01em;
88
+ --wzl-panel-title-color: var(--wzl-fg);
89
+ --wzl-panel-title-inset: 0;
90
+ --wzl-stance-scope-border-width: 0;
91
+ --wzl-stance-scope-radius: 8px;
92
+ --wzl-stance-scope-tone-mix: 22%;
93
+ --wzl-stance-scope-nested-radius: 6px;
94
+ /* A scope panel inside another sits back into it. */
95
+ --wzl-stance-scope-nested-surface: var(--wzl-surface);
96
+ --wzl-stance-aside-surface: transparent;
97
+ --wzl-stance-aside-border-color: var(--wzl-line-subtle);
98
+ --wzl-stance-aside-blur: 0px;
99
+ --wzl-stance-aside-title-color: var(--wzl-fg-subtle);
100
+ --wzl-stance-advanced-title-color: var(--wzl-fg-subtle);
101
+ --wzl-stance-debug-border-style: dashed;
102
+ --wzl-stance-debug-title-font: var(--wzl-font-mono);
103
+ --wzl-stance-debug-title-case: none;
104
+ --wzl-stance-danger-tone: var(--wzl-danger);
105
+ --wzl-stance-danger-border-color: var(--wzl-danger);
106
+ --wzl-stance-danger-title-color: var(--wzl-danger);
107
+ --wzl-stance-notice-tone: var(--wzl-accent);
108
+ --wzl-stance-notice-tone-mix: 8%;
109
+ --wzl-stance-important-border-color: var(--wzl-accent-fg);
110
+ --wzl-stance-important-title-color: var(--wzl-accent-fg);
111
+ --wzl-stance-preview-pad: 0;
112
+ --wzl-stance-preview-title-size: var(--wzl-font-size-xs);
113
+ --wzl-stance-preview-title-case: none;
114
+ --wzl-stance-preview-title-inset: 6px 10px 0;
47
115
  --wzl-danger-base: #d94a3f;
48
116
  --wzl-warning-base: #d99a3f;
49
117
  --wzl-success-base: #2ec27e;
@@ -58,6 +126,8 @@
58
126
  --wzl-curve-color: var(--wzl-accent-strong);
59
127
  --wzl-accent: var(--wzl-accent-base);
60
128
  --wzl-accent-hover: var(--wzl-accent-strong);
129
+ /* Honey amber in dark mode and teal in light, where a darkened amber reads as brown. A fill; use secondary-fg for text. */
130
+ --wzl-secondary: var(--wzl-secondary-base);
61
131
  --wzl-danger: var(--wzl-danger-base);
62
132
  --wzl-warning: var(--wzl-warning-base);
63
133
  --wzl-success: var(--wzl-success-base);
@@ -78,10 +148,16 @@
78
148
  --wzl-line-width: 2px;
79
149
  /* Drawn data curves. Heavier than structural lines so data reads as primary content. */
80
150
  --wzl-curve-width: 3px;
81
- /* Height of a horizontal toolbar strip (ActionsBar, OptionsBar, ToolOptionsBar). Taller than control-h so the controls inside a strip are not flush with its edges. */
151
+ /* Height of a horizontal toolbar strip (ButtonBar, OptionsBar, ToolOptionsBar). Taller than control-h so the controls inside a strip are not flush with its edges. */
82
152
  --wzl-tb-height: 28px;
153
+ /* Height of the smallest interactive control -- a stepper, a keycap, a swatch button in a dense row. The rank below control-h-sm. */
154
+ --wzl-control-h-xs: 18px;
155
+ /* Height of a control in a dense inspector -- a Properties field, a small Button. The rank below control-h, which sizes a standalone control. */
156
+ --wzl-control-h-sm: 20px;
83
157
  /* Height of an interactive control — button, input, select, segmented control. Distinct from tb-height, which sizes the strip a row of them sits in. */
84
158
  --wzl-control-h: 24px;
159
+ /* Side of a square icon button -- a dialog close, a row remove, a field clear. Smaller than control-h because it carries a glyph rather than a label, and square, so it sizes both axes. */
160
+ --wzl-icon-button-size: 22px;
85
161
  /* Height of a linear range track. The kit's single-thumb ranges all wear this; Slider's default 24px canvas track does not. */
86
162
  --wzl-slider-track-h: 4px;
87
163
  /* Diameter of a linear range thumb. */
@@ -96,26 +172,22 @@
96
172
  --wzl-handle-size-sm: 7px;
97
173
  /* A handle that is a category of its own rather than one of a row — a curve's endpoint. Larger so it separates from the handles it sits in line with. */
98
174
  --wzl-handle-size-lg: 10px;
175
+ /* One square of the transparency checker drawn under a paint that is empty, mixed or translucent. Paint it as repeating-conic-gradient(var(--wzl-checker-a) 0% 25%, var(--wzl-checker-b) 0% 50%) 50% / var(--wzl-checker-size) var(--wzl-checker-size). */
176
+ --wzl-checker-a: var(--wzl-border);
177
+ /* The other square of the transparency checker. */
178
+ --wzl-checker-b: var(--wzl-surface);
179
+ /* Edge of one repeat of the transparency checker: two squares by two. */
180
+ --wzl-checker-size: 8px;
181
+ /* Ground of a canvas app's workspace — the area around the document page. */
182
+ --wzl-workspace-surface: var(--wzl-surface-sunken);
183
+ /* Marks drawn over workspace-surface, such as its diagonal stripes, so the page reads as the thing on top. */
184
+ --wzl-workspace-line: var(--wzl-line-subtle);
99
185
  /* Horizontal padding inside a boxed field. Pairs with --wzl-field-h, which is a container override and has no :root default. */
100
186
  --wzl-field-pad-x: 8px;
101
187
  /* Backdrop blur radius for frosted surfaces. Pairs with glass-tint. */
102
188
  --wzl-glass-blur: 3px;
103
- /* Shortcut keys and index badges. The floor for chrome text. */
104
- --wzl-font-size-2xs: 9px;
105
- /* Tool-button labels under an icon. */
106
- --wzl-font-size-xs: 10px;
107
- /* Chrome labels, status readouts, section headings. */
108
- --wzl-font-size-sm: 11px;
109
189
  /* Controls and body text. */
110
- --wzl-font-size: 13px;
111
- /* Panel and dialog titles. */
112
- --wzl-font-size-lg: 16px;
113
- /* The largest chrome text — a lab or app title. */
114
- --wzl-font-size-xl: 20px;
115
- --wzl-space-xs: 4px;
116
- --wzl-space-sm: 8px;
117
- --wzl-space-md: 12px;
118
- --wzl-space-lg: 16px;
190
+ --wzl-font-size: var(--wzl-font-size-md);
119
191
  --wzl-tracking-none: 0;
120
192
  /* Uppercase section headings. */
121
193
  --wzl-tracking-wide: 0.06em;
@@ -149,11 +221,22 @@
149
221
  --wzl-font-weight-normal: 300;
150
222
  --wzl-font-weight-medium: 350;
151
223
  --wzl-font-weight-bold: 400;
224
+ /* Alias for space-2. The t-shirt names name every other rung of the ladder. */
225
+ --wzl-space-xs: var(--wzl-space-2);
226
+ /* Alias for space-4. The t-shirt names name every other rung of the ladder. */
227
+ --wzl-space-sm: var(--wzl-space-4);
228
+ /* Alias for space-6. The t-shirt names name every other rung of the ladder. */
229
+ --wzl-space-md: var(--wzl-space-6);
230
+ /* Alias for space-8. The t-shirt names name every other rung of the ladder. */
231
+ --wzl-space-lg: var(--wzl-space-8);
152
232
  }
153
233
 
154
234
  [data-wzl-theme='weasel'][data-wzl-mode='dark'],
155
235
  [data-wzl-mode='dark'] {
156
236
  color-scheme: dark;
237
+ --wzl-secondary-soft: #704e09;
238
+ --wzl-secondary-base: #dc9d15;
239
+ --wzl-secondary-strong: #f1cb8d;
157
240
  --wzl-surface: var(--wzl-gray-800);
158
241
  --wzl-surface-raised: var(--wzl-gray-700);
159
242
  --wzl-surface-sunken: var(--wzl-gray-900);
@@ -165,16 +248,34 @@
165
248
  --wzl-accent-fg: var(--wzl-accent-strong);
166
249
  --wzl-fg-inverse: var(--wzl-gray-900);
167
250
  --wzl-shadow: rgba(0, 0, 0, 0.6);
251
+ --wzl-secondary-fg: var(--wzl-secondary-base);
252
+ --wzl-panel-surface: var(--wzl-surface-raised);
253
+ --wzl-panel-border-color: var(--wzl-border);
254
+ --wzl-panel-title-color: var(--wzl-fg);
255
+ --wzl-stance-scope-nested-surface: var(--wzl-surface);
256
+ --wzl-stance-aside-border-color: var(--wzl-line-subtle);
257
+ --wzl-stance-aside-title-color: var(--wzl-fg-subtle);
258
+ --wzl-stance-advanced-title-color: var(--wzl-fg-subtle);
259
+ --wzl-stance-important-border-color: var(--wzl-accent-fg);
260
+ --wzl-stance-important-title-color: var(--wzl-accent-fg);
168
261
  --wzl-line-subtle: color-mix(in srgb, var(--wzl-fg) 10%, transparent);
169
262
  --wzl-line: color-mix(in srgb, var(--wzl-fg) 20%, transparent);
170
263
  --wzl-line-strong: color-mix(in srgb, var(--wzl-fg) 40%, transparent);
264
+ --wzl-secondary: var(--wzl-secondary-base);
171
265
  --wzl-surface-hover: color-mix(in srgb, var(--wzl-fg) 10%, transparent);
172
266
  --wzl-surface-pressed: color-mix(in srgb, var(--wzl-fg) 18%, transparent);
267
+ --wzl-checker-a: var(--wzl-border);
268
+ --wzl-checker-b: var(--wzl-surface);
269
+ --wzl-workspace-surface: var(--wzl-surface-sunken);
270
+ --wzl-workspace-line: var(--wzl-line-subtle);
173
271
  }
174
272
 
175
273
  [data-wzl-theme='weasel'][data-wzl-mode='light'],
176
274
  [data-wzl-mode='light'] {
177
275
  color-scheme: light;
276
+ --wzl-secondary-soft: #016458;
277
+ --wzl-secondary-base: #3ee1cb;
278
+ --wzl-secondary-strong: #94e3d5;
178
279
  --wzl-surface: var(--wzl-gray-50);
179
280
  --wzl-surface-raised: var(--wzl-gray-100);
180
281
  --wzl-surface-sunken: var(--wzl-gray-200);
@@ -186,9 +287,78 @@
186
287
  --wzl-accent-fg: var(--wzl-accent-base);
187
288
  --wzl-fg-inverse: var(--wzl-gray-50);
188
289
  --wzl-shadow: rgba(0, 0, 0, 0.18);
290
+ --wzl-secondary-fg: var(--wzl-secondary-soft);
291
+ --wzl-panel-surface: var(--wzl-surface-raised);
292
+ --wzl-panel-border-color: var(--wzl-border);
293
+ --wzl-panel-title-color: var(--wzl-fg);
294
+ --wzl-stance-scope-nested-surface: var(--wzl-surface);
295
+ --wzl-stance-aside-border-color: var(--wzl-line-subtle);
296
+ --wzl-stance-aside-title-color: var(--wzl-fg-subtle);
297
+ --wzl-stance-advanced-title-color: var(--wzl-fg-subtle);
298
+ --wzl-stance-important-border-color: var(--wzl-accent-fg);
299
+ --wzl-stance-important-title-color: var(--wzl-accent-fg);
189
300
  --wzl-line-subtle: color-mix(in srgb, var(--wzl-fg) 10%, transparent);
190
301
  --wzl-line: color-mix(in srgb, var(--wzl-fg) 20%, transparent);
191
302
  --wzl-line-strong: color-mix(in srgb, var(--wzl-fg) 40%, transparent);
303
+ --wzl-secondary: var(--wzl-secondary-base);
192
304
  --wzl-surface-hover: color-mix(in srgb, var(--wzl-fg) 10%, transparent);
193
305
  --wzl-surface-pressed: color-mix(in srgb, var(--wzl-fg) 18%, transparent);
306
+ --wzl-checker-a: var(--wzl-border);
307
+ --wzl-checker-b: var(--wzl-surface);
308
+ --wzl-workspace-surface: var(--wzl-surface-sunken);
309
+ --wzl-workspace-line: var(--wzl-line-subtle);
310
+ }
311
+
312
+ [data-wzl-theme='weasel'][data-wzl-density='compact'],
313
+ [data-wzl-density='compact'] {
314
+ --wzl-font-size-2xs: 7px;
315
+ --wzl-font-size-xs: 8px;
316
+ --wzl-font-size-sm: 9px;
317
+ --wzl-font-size-md: 11px;
318
+ --wzl-font-size-lg: 14px;
319
+ --wzl-font-size-xl: 17px;
320
+ --wzl-tb-height: 24px;
321
+ --wzl-control-h-xs: 16px;
322
+ --wzl-control-h-sm: 18px;
323
+ --wzl-control-h: 20px;
324
+ --wzl-icon-button-size: 20px;
325
+ --wzl-panel-title-size: var(--wzl-font-size-lg);
326
+ --wzl-stance-preview-title-size: var(--wzl-font-size-xs);
327
+ --wzl-font-size: var(--wzl-font-size-md);
328
+ }
329
+
330
+ [data-wzl-theme='weasel'][data-wzl-density='comfortable'],
331
+ [data-wzl-density='comfortable'] {
332
+ --wzl-font-size-2xs: 9px;
333
+ --wzl-font-size-xs: 10px;
334
+ --wzl-font-size-sm: 11px;
335
+ --wzl-font-size-md: 13px;
336
+ --wzl-font-size-lg: 16px;
337
+ --wzl-font-size-xl: 20px;
338
+ --wzl-tb-height: 28px;
339
+ --wzl-control-h-xs: 18px;
340
+ --wzl-control-h-sm: 20px;
341
+ --wzl-control-h: 24px;
342
+ --wzl-icon-button-size: 22px;
343
+ --wzl-panel-title-size: var(--wzl-font-size-lg);
344
+ --wzl-stance-preview-title-size: var(--wzl-font-size-xs);
345
+ --wzl-font-size: var(--wzl-font-size-md);
346
+ }
347
+
348
+ [data-wzl-theme='weasel'][data-wzl-density='roomy'],
349
+ [data-wzl-density='roomy'] {
350
+ --wzl-font-size-2xs: 10px;
351
+ --wzl-font-size-xs: 12px;
352
+ --wzl-font-size-sm: 13px;
353
+ --wzl-font-size-md: 15px;
354
+ --wzl-font-size-lg: 18px;
355
+ --wzl-font-size-xl: 23px;
356
+ --wzl-tb-height: 32px;
357
+ --wzl-control-h-xs: 22px;
358
+ --wzl-control-h-sm: 24px;
359
+ --wzl-control-h: 28px;
360
+ --wzl-icon-button-size: 26px;
361
+ --wzl-panel-title-size: var(--wzl-font-size-lg);
362
+ --wzl-stance-preview-title-size: var(--wzl-font-size-xs);
363
+ --wzl-font-size: var(--wzl-font-size-md);
194
364
  }
package/fonts/README.md CHANGED
@@ -8,11 +8,11 @@ third-party host at runtime.
8
8
  | `oswald-latin-variable.woff2` | `--wzl-font-ui`, `--wzl-font-display` | condensed UI/display face, variable `wght 200–700` |
9
9
  | `inter-latin.woff2` | `--wzl-font-body` | body/prose face, weight 400 |
10
10
 
11
- Loading them is opt-in: `import '@weasel-js/theme/fonts.css'`. Skip it and the
12
- token font stacks fall back to `system-ui`.
11
+ Loading them is opt-in: `import '@weasel-js/theme/fonts.css'`, or
12
+ `faces.css` for the `@font-face` rules without the `:root` font. Skip both and
13
+ the token font stacks fall back to `system-ui`.
13
14
 
14
- **Not opt-in through labkit.** `@weasel-js/labkit` concatenates these
15
- `@font-face` rules into its one `dist/styles.css` and copies both `.woff2`
15
+ **Not opt-in through labkit.** `@weasel-js/labkit` concatenates `faces.css` into its one `dist/styles.css` and copies both `.woff2`
16
16
  files to `dist/fonts/`, so a lab renders in them without importing anything
17
17
  here. Renaming or dropping a face changes what a consumer's text looks like
18
18
  with no error anywhere.
@@ -32,8 +32,7 @@ python3 -m venv /tmp/fontvenv
32
32
 
33
33
  Upstream `fonts/variable/Oswald[wght].ttf` from
34
34
  https://github.com/googlefonts/OswaldFont, subset to the Google Fonts `latin`
35
- range plus the three combining marks labkit's `@font-face` declares
36
- (`U+0304`, `U+0308`, `U+0329`):
35
+ range plus three combining marks (`U+0304`, `U+0308`, `U+0329`):
37
36
 
38
37
  ```sh
39
38
  /tmp/fontvenv/bin/pyftsubset "Oswald[wght].ttf" \
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weasel-js/theme",
3
- "version": "1.5.1",
3
+ "version": "1.6.0",
4
4
  "description": "Design tokens shared by weasel-ui and weasel-hud — CSS variables + a parallel TS export.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -25,10 +25,11 @@
25
25
  },
26
26
  "./tokens.css": "./dist/tokens.css",
27
27
  "./fonts.css": "./dist/fonts.css",
28
+ "./faces.css": "./dist/faces.css",
28
29
  "./package.json": "./package.json"
29
30
  },
30
31
  "dependencies": {
31
- "@weasel-js/paint": "1.5.1"
32
+ "@weasel-js/paint": "1.6.0"
32
33
  },
33
34
  "peerDependencies": {
34
35
  "react": ">=18"
@@ -60,7 +61,7 @@
60
61
  ],
61
62
  "scripts": {
62
63
  "gen:tokens": "tsx scripts/build-tokens.ts",
63
- "build": "npm run gen:tokens && tsup && cp src/generated/tokens.css dist/tokens.css && cp src/fonts.css dist/fonts.css"
64
+ "build": "npm run gen:tokens && tsup && cp src/generated/tokens.css dist/tokens.css && cp src/fonts.css src/faces.css dist/"
64
65
  },
65
66
  "publishConfig": {
66
67
  "access": "public",
@@ -1,175 +0,0 @@
1
- // src/axes.ts
2
- function isByAxis(v) {
3
- return typeof v === "object" && v !== null && !Array.isArray(v) && typeof v.by === "string";
4
- }
5
- function fullSelection(axes, selection = {}) {
6
- const out = {};
7
- for (const [name, def] of Object.entries(axes)) {
8
- const v = selection[name];
9
- out[name] = v !== void 0 && v in def.values ? v : def.default;
10
- }
11
- return out;
12
- }
13
- function mergeAxes(parent, child) {
14
- const out = { ...parent };
15
- for (const [name, def] of Object.entries(child)) {
16
- out[name] = { ...def, values: { ...parent[name]?.values, ...def.values } };
17
- }
18
- return out;
19
- }
20
- function enumerateSelections(axes) {
21
- let out = [{}];
22
- for (const [name, def] of Object.entries(axes)) {
23
- out = out.flatMap((s) => Object.keys(def.values).map((v) => ({ ...s, [name]: v })));
24
- }
25
- return out;
26
- }
27
- function selectionKey(axes, selection) {
28
- const full = fullSelection(axes, selection);
29
- return Object.keys(axes).map((a) => `${a}=${full[a]}`).join(",");
30
- }
31
- function pick(v, selection) {
32
- let cur = v;
33
- while (isByAxis(cur)) {
34
- const axis = cur.by;
35
- const value = selection[axis];
36
- if (value === void 0 || value === "by" || !(value in cur)) return { ok: false, axis, value: value ?? "" };
37
- cur = cur[value];
38
- }
39
- return { ok: true, value: cur };
40
- }
41
- function pickAll(record, selection) {
42
- const out = {};
43
- for (const [name, v] of Object.entries(record)) {
44
- const picked = pick(v, selection);
45
- if (picked.ok) out[name] = picked.value;
46
- }
47
- return out;
48
- }
49
-
50
- // src/dtcg/value.ts
51
- function fontStack(value) {
52
- return value.map((f) => typeof f === "string" && /\s/.test(f) ? `'${f}'` : String(f)).join(", ");
53
- }
54
- function serializeTokenValue(type, value) {
55
- if (Array.isArray(value)) {
56
- if (type === "cubicBezier") return `cubic-bezier(${value.join(", ")})`;
57
- if (type === "fontFamily") return fontStack(value);
58
- return value.join(", ");
59
- }
60
- return String(value);
61
- }
62
- var BEZIER = /^cubic-bezier\(\s*([^)]*)\)$/i;
63
- function parseTokenValue(type, text) {
64
- const raw = text.trim();
65
- if (type === "cubicBezier") {
66
- const inner = BEZIER.exec(raw)?.[1] ?? raw;
67
- const parts = inner.split(",").map((p) => Number(p.trim()));
68
- return parts.length === 4 && parts.every((n) => Number.isFinite(n)) ? parts : raw;
69
- }
70
- if (type === "fontFamily") {
71
- const families = raw.split(",").map((f) => f.trim().replace(/^['"]|['"]$/g, "").trim()).filter((f) => f !== "");
72
- return families.length > 0 ? families : raw;
73
- }
74
- return raw;
75
- }
76
-
77
- // src/dtcg/color.ts
78
- function withAlpha(color, alpha) {
79
- const rgba = parseRgba(color.trim());
80
- if (!rgba) return `color-mix(in srgb, ${color.trim()} ${round(alpha * 100, 4)}%, transparent)`;
81
- const [r, g, b, a] = rgba;
82
- return `rgba(${r}, ${g}, ${b}, ${round(a * alpha, 3)})`;
83
- }
84
- function round(n, places) {
85
- return Number(n.toFixed(places));
86
- }
87
- function parseRgba(s) {
88
- if (s.toLowerCase() === "transparent") return [0, 0, 0, 0];
89
- return parseHex(s) ?? parseRgbFn(s);
90
- }
91
- function parseHex(s) {
92
- const m = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.exec(s);
93
- if (!m) return null;
94
- const body = m[1];
95
- const full = body.length <= 4 ? body.replace(/./g, (c) => c + c) : body;
96
- const byte = (i) => Number.parseInt(full.slice(i, i + 2), 16);
97
- return [byte(0), byte(2), byte(4), full.length === 8 ? byte(6) / 255 : 1];
98
- }
99
- function parseRgbFn(s) {
100
- const m = /^rgba?\(([^()]*)\)$/i.exec(s);
101
- if (!m) return null;
102
- const [channels, alphaPart, extra] = m[1].split("/");
103
- if (extra !== void 0) return null;
104
- const parts = channels.trim().split(/\s*,\s*|\s+/);
105
- if (alphaPart !== void 0) parts.push(alphaPart.trim());
106
- if (parts.length !== 3 && parts.length !== 4) return null;
107
- const channel = (p) => p.endsWith("%") ? Number.parseFloat(p) / 100 * 255 : Number(p);
108
- const alpha = (p) => p.endsWith("%") ? Number.parseFloat(p) / 100 : Number(p);
109
- const [r, g, b] = parts.slice(0, 3).map(channel);
110
- const a = parts[3] === void 0 ? 1 : alpha(parts[3]);
111
- if (![r, g, b, a].every(Number.isFinite)) return null;
112
- return [Math.round(r), Math.round(g), Math.round(b), a];
113
- }
114
-
115
- // src/dtcg/resolve.ts
116
- var REF = /^\{([^}]+)\}$/;
117
- function refTarget(value) {
118
- if (typeof value !== "string") return null;
119
- const m = REF.exec(value.trim());
120
- if (!m) return null;
121
- const path = m[1];
122
- const dot = path.indexOf(".");
123
- return dot === -1 ? path : path.slice(dot + 1);
124
- }
125
- function resolveTokens(tokens) {
126
- const out = {};
127
- const inProgress = /* @__PURE__ */ new Set();
128
- const resolveOne = (name) => {
129
- const cached = out[name];
130
- if (cached !== void 0) return cached;
131
- const token = tokens[name];
132
- if (!token) throw new Error(`Unknown token "${name}"`);
133
- if (inProgress.has(name)) {
134
- throw new Error(`Reference cycle at token "${name}" (${[...inProgress].join(" \u2192 ")})`);
135
- }
136
- inProgress.add(name);
137
- const target = refTarget(token.value);
138
- let value;
139
- if (target === null) {
140
- value = serializeTokenValue(token.type, token.value);
141
- } else if (!tokens[target]) {
142
- throw new Error(`Token "${name}" references "${target}", which is not defined`);
143
- } else {
144
- value = resolveOne(target);
145
- }
146
- if (token.alpha !== void 0) value = withAlpha(value, token.alpha);
147
- inProgress.delete(name);
148
- out[name] = value;
149
- return value;
150
- };
151
- for (const name of Object.keys(tokens)) resolveOne(name);
152
- return out;
153
- }
154
-
155
- // src/resolveTheme.ts
156
- function themeChain(theme) {
157
- const out = [];
158
- for (let t = theme; t; t = t.extends) out.unshift(t);
159
- return out;
160
- }
161
- function themeAxes(theme) {
162
- return themeChain(theme).reduce((axes, t) => mergeAxes(axes, t.axes), {});
163
- }
164
- function resolveTheme(theme, selection = {}) {
165
- const sel = fullSelection(themeAxes(theme), selection);
166
- let merged = {};
167
- for (const t of themeChain(theme)) merged = { ...merged, ...pickAll(t.tokens, sel) };
168
- const out = {};
169
- for (const [name, value] of Object.entries(resolveTokens(merged))) out[`--wzl-${name}`] = value;
170
- return out;
171
- }
172
-
173
- export { enumerateSelections, fullSelection, isByAxis, mergeAxes, parseTokenValue, pick, pickAll, resolveTheme, resolveTokens, selectionKey, serializeTokenValue, themeAxes };
174
- //# sourceMappingURL=chunk-LL2ERJPZ.js.map
175
- //# sourceMappingURL=chunk-LL2ERJPZ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/axes.ts","../src/dtcg/value.ts","../src/dtcg/color.ts","../src/dtcg/resolve.ts","../src/resolveTheme.ts"],"names":[],"mappings":";AA0BO,SAAS,SAAS,CAAA,EAAkC;AACzD,EAAA,OAAO,OAAO,CAAA,KAAM,QAAA,IAAY,CAAA,KAAM,IAAA,IAAQ,CAAC,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,IAAK,OAAQ,CAAA,CAAuB,EAAA,KAAO,QAAA;AAC3G;AAGO,SAAS,aAAA,CAAc,IAAA,EAAgB,SAAA,GAAuB,EAAC,EAAc;AAClF,EAAA,MAAM,MAA8B,EAAC;AACrC,EAAA,KAAA,MAAW,CAAC,IAAA,EAAM,GAAG,KAAK,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAA,EAAG;AAC9C,IAAA,MAAM,CAAA,GAAI,UAAU,IAAI,CAAA;AACxB,IAAA,GAAA,CAAI,IAAI,IAAI,CAAA,KAAM,MAAA,IAAa,KAAK,GAAA,CAAI,MAAA,GAAS,IAAI,GAAA,CAAI,OAAA;AAAA,EAC3D;AACA,EAAA,OAAO,GAAA;AACT;AAGO,SAAS,SAAA,CAAU,QAAkB,KAAA,EAA2B;AACrE,EAAA,MAAM,GAAA,GAA+B,EAAE,GAAG,MAAA,EAAO;AACjD,EAAA,KAAA,MAAW,CAAC,IAAA,EAAM,GAAG,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC/C,IAAA,GAAA,CAAI,IAAI,CAAA,GAAI,EAAE,GAAG,KAAK,MAAA,EAAQ,EAAE,GAAG,MAAA,CAAO,IAAI,CAAA,EAAG,MAAA,EAAQ,GAAG,GAAA,CAAI,QAAO,EAAE;AAAA,EAC3E;AACA,EAAA,OAAO,GAAA;AACT;AAEO,SAAS,oBAAoB,IAAA,EAA6B;AAC/D,EAAA,IAAI,GAAA,GAAgC,CAAC,EAAE,CAAA;AACvC,EAAA,KAAA,MAAW,CAAC,IAAA,EAAM,GAAG,KAAK,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAA,EAAG;AAC9C,IAAA,GAAA,GAAM,GAAA,CAAI,QAAQ,CAAC,CAAA,KAAM,OAAO,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,GAAG,CAAA,EAAG,CAAC,IAAI,GAAG,CAAA,GAAI,CAAC,CAAA;AAAA,EACpF;AACA,EAAA,OAAO,GAAA;AACT;AAGO,SAAS,YAAA,CAAa,MAAgB,SAAA,EAA8B;AACzE,EAAA,MAAM,IAAA,GAAO,aAAA,CAAc,IAAA,EAAM,SAAS,CAAA;AAC1C,EAAA,OAAO,OAAO,IAAA,CAAK,IAAI,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,KAAK,CAAC,CAAC,CAAA,CAAE,CAAA,CAAE,KAAK,GAAG,CAAA;AACjE;AAEO,SAAS,IAAA,CAAQ,GAAe,SAAA,EAAiC;AACtE,EAAA,IAAI,GAAA,GAAe,CAAA;AACnB,EAAA,OAAO,QAAA,CAAS,GAAG,CAAA,EAAG;AACpB,IAAA,MAAM,OAAO,GAAA,CAAI,EAAA;AACjB,IAAA,MAAM,KAAA,GAAQ,UAAU,IAAI,CAAA;AAC5B,IAAA,IAAI,KAAA,KAAU,MAAA,IAAa,KAAA,KAAU,IAAA,IAAQ,EAAE,KAAA,IAAS,GAAA,CAAA,EAAM,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,IAAA,EAAM,KAAA,EAAO,SAAS,EAAA,EAAG;AAC3G,IAAA,GAAA,GAAM,IAAI,KAAK,CAAA;AAAA,EACjB;AACA,EAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,KAAA,EAAO,GAAA,EAAS;AACrC;AAGO,SAAS,OAAA,CAAW,QAA8C,SAAA,EAAyC;AAChH,EAAA,MAAM,MAAyB,EAAC;AAChC,EAAA,KAAA,MAAW,CAAC,IAAA,EAAM,CAAC,KAAK,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAA,EAAG;AAC9C,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,CAAA,EAAG,SAAS,CAAA;AAChC,IAAA,IAAI,MAAA,CAAO,EAAA,EAAI,GAAA,CAAI,IAAI,IAAI,MAAA,CAAO,KAAA;AAAA,EACpC;AACA,EAAA,OAAO,GAAA;AACT;;;AC3EA,SAAS,UAAU,KAAA,EAA6C;AAC9D,EAAA,OAAO,MAAM,GAAA,CAAI,CAAC,MAAO,OAAO,CAAA,KAAM,YAAY,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,GAAI,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA,CAAA,GAAM,MAAA,CAAO,CAAC,CAAE,CAAA,CAAE,KAAK,IAAI,CAAA;AACnG;AAOO,SAAS,mBAAA,CAAoB,MAAc,KAAA,EAA2B;AAC3E,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACxB,IAAA,IAAI,SAAS,aAAA,EAAe,OAAO,gBAAgB,KAAA,CAAM,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,CAAA;AACnE,IAAA,IAAI,IAAA,KAAS,YAAA,EAAc,OAAO,SAAA,CAAU,KAAK,CAAA;AACjD,IAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AAAA,EACxB;AACA,EAAA,OAAO,OAAO,KAAK,CAAA;AACrB;AAEA,IAAM,MAAA,GAAS,+BAAA;AAOR,SAAS,eAAA,CAAgB,MAAc,IAAA,EAA0B;AACtE,EAAA,MAAM,GAAA,GAAM,KAAK,IAAA,EAAK;AACtB,EAAA,IAAI,SAAS,aAAA,EAAe;AAC1B,IAAA,MAAM,QAAQ,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA,GAAI,CAAC,CAAA,IAAK,GAAA;AACvC,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,MAAA,CAAO,CAAA,CAAE,IAAA,EAAM,CAAC,CAAA;AAC1D,IAAA,OAAO,KAAA,CAAM,MAAA,KAAW,CAAA,IAAK,KAAA,CAAM,KAAA,CAAM,CAAC,CAAA,KAAM,MAAA,CAAO,QAAA,CAAS,CAAC,CAAC,CAAA,GAAI,KAAA,GAAQ,GAAA;AAAA,EAChF;AACA,EAAA,IAAI,SAAS,YAAA,EAAc;AACzB,IAAA,MAAM,QAAA,GAAW,IACd,KAAA,CAAM,GAAG,EACT,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAK,CAAE,QAAQ,cAAA,EAAgB,EAAE,EAAE,IAAA,EAAM,EACtD,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,KAAM,EAAE,CAAA;AACzB,IAAA,OAAO,QAAA,CAAS,MAAA,GAAS,CAAA,GAAI,QAAA,GAAW,GAAA;AAAA,EAC1C;AACA,EAAA,OAAO,GAAA;AACT;;;ACtCO,SAAS,SAAA,CAAU,OAAe,KAAA,EAAuB;AAC9D,EAAA,MAAM,IAAA,GAAO,SAAA,CAAU,KAAA,CAAM,IAAA,EAAM,CAAA;AACnC,EAAA,IAAI,CAAC,IAAA,EAAM,OAAO,CAAA,mBAAA,EAAsB,KAAA,CAAM,IAAA,EAAM,CAAA,CAAA,EAAI,KAAA,CAAM,KAAA,GAAQ,GAAA,EAAK,CAAC,CAAC,CAAA,eAAA,CAAA;AAC7E,EAAA,MAAM,CAAC,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,GAAI,IAAA;AACrB,EAAA,OAAO,CAAA,KAAA,EAAQ,CAAC,CAAA,EAAA,EAAK,CAAC,CAAA,EAAA,EAAK,CAAC,CAAA,EAAA,EAAK,KAAA,CAAM,CAAA,GAAI,KAAA,EAAO,CAAC,CAAC,CAAA,CAAA,CAAA;AACtD;AAIA,SAAS,KAAA,CAAM,GAAW,MAAA,EAAwB;AAChD,EAAA,OAAO,MAAA,CAAO,CAAA,CAAE,OAAA,CAAQ,MAAM,CAAC,CAAA;AACjC;AAEA,SAAS,UAAU,CAAA,EAAwB;AACzC,EAAA,IAAI,CAAA,CAAE,aAAY,KAAM,aAAA,SAAsB,CAAC,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA;AACzD,EAAA,OAAO,QAAA,CAAS,CAAC,CAAA,IAAK,UAAA,CAAW,CAAC,CAAA;AACpC;AAEA,SAAS,SAAS,CAAA,EAAwB;AACxC,EAAA,MAAM,CAAA,GAAI,6CAAA,CAA8C,IAAA,CAAK,CAAC,CAAA;AAC9D,EAAA,IAAI,CAAC,GAAG,OAAO,IAAA;AACf,EAAA,MAAM,IAAA,GAAO,EAAE,CAAC,CAAA;AAChB,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,MAAA,IAAU,CAAA,GAAI,IAAA,CAAK,OAAA,CAAQ,IAAA,EAAM,CAAC,CAAA,KAAM,CAAA,GAAI,CAAC,CAAA,GAAI,IAAA;AACnE,EAAA,MAAM,IAAA,GAAO,CAAC,CAAA,KAAc,MAAA,CAAO,QAAA,CAAS,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,CAAA,GAAI,CAAC,CAAA,EAAG,EAAE,CAAA;AACpE,EAAA,OAAO,CAAC,IAAA,CAAK,CAAC,CAAA,EAAG,IAAA,CAAK,CAAC,CAAA,EAAG,IAAA,CAAK,CAAC,CAAA,EAAG,KAAK,MAAA,KAAW,CAAA,GAAI,KAAK,CAAC,CAAA,GAAI,MAAM,CAAC,CAAA;AAC1E;AAEA,SAAS,WAAW,CAAA,EAAwB;AAC1C,EAAA,MAAM,CAAA,GAAI,sBAAA,CAAuB,IAAA,CAAK,CAAC,CAAA;AACvC,EAAA,IAAI,CAAC,GAAG,OAAO,IAAA;AACf,EAAA,MAAM,CAAC,UAAU,SAAA,EAAW,KAAK,IAAI,CAAA,CAAE,CAAC,CAAA,CAAE,KAAA,CAAM,GAAG,CAAA;AACnD,EAAA,IAAI,KAAA,KAAU,QAAW,OAAO,IAAA;AAChC,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,IAAA,EAAK,CAAE,MAAM,aAAa,CAAA;AACjD,EAAA,IAAI,cAAc,MAAA,EAAW,KAAA,CAAM,IAAA,CAAK,SAAA,CAAU,MAAM,CAAA;AACxD,EAAA,IAAI,MAAM,MAAA,KAAW,CAAA,IAAK,KAAA,CAAM,MAAA,KAAW,GAAG,OAAO,IAAA;AAErD,EAAA,MAAM,OAAA,GAAU,CAAC,CAAA,KAAe,CAAA,CAAE,SAAS,GAAG,CAAA,GAAK,MAAA,CAAO,UAAA,CAAW,CAAC,CAAA,GAAI,GAAA,GAAO,GAAA,GAAM,OAAO,CAAC,CAAA;AAC/F,EAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,KAAe,CAAA,CAAE,QAAA,CAAS,GAAG,CAAA,GAAI,MAAA,CAAO,UAAA,CAAW,CAAC,CAAA,GAAI,GAAA,GAAM,OAAO,CAAC,CAAA;AACrF,EAAA,MAAM,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,GAAI,KAAA,CAAM,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA,CAAE,GAAA,CAAI,OAAO,CAAA;AAC/C,EAAA,MAAM,CAAA,GAAI,MAAM,CAAC,CAAA,KAAM,SAAY,CAAA,GAAI,KAAA,CAAM,KAAA,CAAM,CAAC,CAAC,CAAA;AACrD,EAAA,IAAI,CAAC,CAAC,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,CAAE,KAAA,CAAM,MAAA,CAAO,QAAQ,CAAA,EAAG,OAAO,IAAA;AACjD,EAAA,OAAO,CAAC,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,CAAC,GAAG,CAAC,CAAA;AACxD;;;AC9CA,IAAM,GAAA,GAAM,eAAA;AAEZ,SAAS,UAAU,KAAA,EAAkC;AACnD,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,IAAA;AACtC,EAAA,MAAM,CAAA,GAAI,GAAA,CAAI,IAAA,CAAK,KAAA,CAAM,MAAM,CAAA;AAC/B,EAAA,IAAI,CAAC,GAAG,OAAO,IAAA;AACf,EAAA,MAAM,IAAA,GAAO,EAAE,CAAC,CAAA;AAChB,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AAC5B,EAAA,OAAO,QAAQ,EAAA,GAAK,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,MAAM,CAAC,CAAA;AAC/C;AAQO,SAAS,cAAc,MAAA,EAAsC;AAClE,EAAA,MAAM,MAAwB,EAAC;AAC/B,EAAA,MAAM,UAAA,uBAAiB,GAAA,EAAY;AAEnC,EAAA,MAAM,UAAA,GAAa,CAAC,IAAA,KAAyB;AAC3C,IAAA,MAAM,MAAA,GAAS,IAAI,IAAI,CAAA;AACvB,IAAA,IAAI,MAAA,KAAW,QAAW,OAAO,MAAA;AAEjC,IAAA,MAAM,KAAA,GAAQ,OAAO,IAAI,CAAA;AACzB,IAAA,IAAI,CAAC,KAAA,EAAO,MAAM,IAAI,KAAA,CAAM,CAAA,eAAA,EAAkB,IAAI,CAAA,CAAA,CAAG,CAAA;AAErD,IAAA,IAAI,UAAA,CAAW,GAAA,CAAI,IAAI,CAAA,EAAG;AACxB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,0BAAA,EAA6B,IAAI,CAAA,GAAA,EAAM,CAAC,GAAG,UAAU,CAAA,CAAE,IAAA,CAAK,UAAK,CAAC,CAAA,CAAA,CAAG,CAAA;AAAA,IACvF;AACA,IAAA,UAAA,CAAW,IAAI,IAAI,CAAA;AAEnB,IAAA,MAAM,MAAA,GAAS,SAAA,CAAU,KAAA,CAAM,KAAK,CAAA;AACpC,IAAA,IAAI,KAAA;AACJ,IAAA,IAAI,WAAW,IAAA,EAAM;AACnB,MAAA,KAAA,GAAQ,mBAAA,CAAoB,KAAA,CAAM,IAAA,EAAM,KAAA,CAAM,KAAK,CAAA;AAAA,IACrD,CAAA,MAAA,IAAW,CAAC,MAAA,CAAO,MAAM,CAAA,EAAG;AAC1B,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,OAAA,EAAU,IAAI,CAAA,cAAA,EAAiB,MAAM,CAAA,uBAAA,CAAyB,CAAA;AAAA,IAChF,CAAA,MAAO;AACL,MAAA,KAAA,GAAQ,WAAW,MAAM,CAAA;AAAA,IAC3B;AAEA,IAAA,IAAI,MAAM,KAAA,KAAU,MAAA,UAAmB,SAAA,CAAU,KAAA,EAAO,MAAM,KAAK,CAAA;AAEnE,IAAA,UAAA,CAAW,OAAO,IAAI,CAAA;AACtB,IAAA,GAAA,CAAI,IAAI,CAAA,GAAI,KAAA;AACZ,IAAA,OAAO,KAAA;AAAA,EACT,CAAA;AAEA,EAAA,KAAA,MAAW,QAAQ,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA,aAAc,IAAI,CAAA;AACvD,EAAA,OAAO,GAAA;AACT;;;AC9CO,SAAS,WAAW,KAAA,EAAuB;AAChD,EAAA,MAAM,MAAe,EAAC;AACtB,EAAA,KAAA,IAAS,CAAA,GAAkB,OAAO,CAAA,EAAG,CAAA,GAAI,EAAE,OAAA,EAAS,GAAA,CAAI,QAAQ,CAAC,CAAA;AACjE,EAAA,OAAO,GAAA;AACT;AAGO,SAAS,UAAU,KAAA,EAAwB;AAChD,EAAA,OAAO,UAAA,CAAW,KAAK,CAAA,CAAE,MAAA,CAAiB,CAAC,IAAA,EAAM,CAAA,KAAM,SAAA,CAAU,IAAA,EAAM,CAAA,CAAE,IAAI,CAAA,EAAG,EAAE,CAAA;AACpF;AASO,SAAS,YAAA,CAAa,KAAA,EAAc,SAAA,GAAuB,EAAC,EAAkB;AACnF,EAAA,MAAM,GAAA,GAAM,aAAA,CAAc,SAAA,CAAU,KAAK,GAAG,SAAS,CAAA;AACrD,EAAA,IAAI,SAAqB,EAAC;AAC1B,EAAA,KAAA,MAAW,CAAA,IAAK,UAAA,CAAW,KAAK,CAAA,EAAG,MAAA,GAAS,EAAE,GAAG,MAAA,EAAQ,GAAG,OAAA,CAAQ,CAAA,CAAE,MAAA,EAAQ,GAAG,CAAA,EAAE;AACnF,EAAA,MAAM,MAA8B,EAAC;AACrC,EAAA,KAAA,MAAW,CAAC,IAAA,EAAM,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,aAAA,CAAc,MAAM,CAAC,CAAA,EAAG,GAAA,CAAI,CAAA,MAAA,EAAS,IAAI,EAAE,CAAA,GAAI,KAAA;AAC1F,EAAA,OAAO,GAAA;AACT","file":"chunk-LL2ERJPZ.js","sourcesContent":["/** One value of an axis. `scheme` becomes `color-scheme` in that value's CSS blocks. */\nexport interface AxisValue {\n readonly scheme?: 'dark' | 'light';\n}\n\nexport interface AxisDef {\n readonly default: string;\n readonly values: Readonly<Record<string, AxisValue>>;\n}\n\n/** Key order is declaration order, which selectors and selection keys follow. */\nexport type AxisDefs = Readonly<Record<string, AxisDef>>;\n\n/** A partial choice of axis values, e.g. `{ mode: 'light' }`. */\nexport type Selection = Readonly<Record<string, string>>;\n\n/** `{ by: 'mode', dark: …, light: … }`: a value that differs per axis value. */\nexport interface ByAxis<T> {\n readonly by: string;\n readonly [axisValue: string]: Varying<T> | string;\n}\n\nexport type Varying<T> = T | ByAxis<T>;\n\nexport type Picked<T> = { ok: true; value: T } | { ok: false; axis: string; value: string };\n\nexport function isByAxis(v: unknown): v is ByAxis<unknown> {\n return typeof v === 'object' && v !== null && !Array.isArray(v) && typeof (v as { by?: unknown }).by === 'string';\n}\n\n/** Every axis given a known value; anything missing or unknown takes its default. */\nexport function fullSelection(axes: AxisDefs, selection: Selection = {}): Selection {\n const out: Record<string, string> = {};\n for (const [name, def] of Object.entries(axes)) {\n const v = selection[name];\n out[name] = v !== undefined && v in def.values ? v : def.default;\n }\n return out;\n}\n\n/** A child's axes over its parent's: an axis both declare keeps both sets of values, the child's entries and default winning. */\nexport function mergeAxes(parent: AxisDefs, child: AxisDefs): AxisDefs {\n const out: Record<string, AxisDef> = { ...parent };\n for (const [name, def] of Object.entries(child)) {\n out[name] = { ...def, values: { ...parent[name]?.values, ...def.values } };\n }\n return out;\n}\n\nexport function enumerateSelections(axes: AxisDefs): Selection[] {\n let out: Record<string, string>[] = [{}];\n for (const [name, def] of Object.entries(axes)) {\n out = out.flatMap((s) => Object.keys(def.values).map((v) => ({ ...s, [name]: v })));\n }\n return out;\n}\n\n/** `mode=dark,density=compact`, axes in declaration order. */\nexport function selectionKey(axes: AxisDefs, selection: Selection): string {\n const full = fullSelection(axes, selection);\n return Object.keys(axes).map((a) => `${a}=${full[a]}`).join(',');\n}\n\nexport function pick<T>(v: Varying<T>, selection: Selection): Picked<T> {\n let cur: unknown = v;\n while (isByAxis(cur)) {\n const axis = cur.by;\n const value = selection[axis];\n if (value === undefined || value === 'by' || !(value in cur)) return { ok: false, axis, value: value ?? '' };\n cur = cur[value];\n }\n return { ok: true, value: cur as T };\n}\n\n/** Every entry of a varying record that has a value for this selection, in record order. */\nexport function pickAll<T>(record: Readonly<Record<string, Varying<T>>>, selection: Selection): Record<string, T> {\n const out: Record<string, T> = {};\n for (const [name, v] of Object.entries(record)) {\n const picked = pick(v, selection);\n if (picked.ok) out[name] = picked.value;\n }\n return out;\n}\n","import type { TokenValue } from './types';\n\n/**\n * Quote family names containing whitespace; leave everything else bare.\n * Generic keywords (`sans-serif`) and hyphen-prefixed identifiers\n * (`-apple-system`) break if quoted, and neither contains a space.\n */\nfunction fontStack(value: readonly (string | number)[]): string {\n return value.map((f) => (typeof f === 'string' && /\\s/.test(f) ? `'${f}'` : String(f))).join(', ');\n}\n\n/**\n * A token's value as CSS renders it. A DTCG value is not always a string: a\n * `fontFamily` is a list of names and a `cubicBezier` is four numbers, and both\n * have a spelling that belongs in a stylesheet rather than in JSON.\n */\nexport function serializeTokenValue(type: string, value: TokenValue): string {\n if (Array.isArray(value)) {\n if (type === 'cubicBezier') return `cubic-bezier(${value.join(', ')})`;\n if (type === 'fontFamily') return fontStack(value);\n return value.join(', ');\n }\n return String(value);\n}\n\nconst BEZIER = /^cubic-bezier\\(\\s*([^)]*)\\)$/i;\n\n/**\n * The inverse of {@link serializeTokenValue}: text a person edited, back in the\n * shape a definition stores. Text that does not parse for its type is kept as\n * text rather than thrown away, so a half-typed value stays editable.\n */\nexport function parseTokenValue(type: string, text: string): TokenValue {\n const raw = text.trim();\n if (type === 'cubicBezier') {\n const inner = BEZIER.exec(raw)?.[1] ?? raw;\n const parts = inner.split(',').map((p) => Number(p.trim()));\n return parts.length === 4 && parts.every((n) => Number.isFinite(n)) ? parts : raw;\n }\n if (type === 'fontFamily') {\n const families = raw\n .split(',')\n .map((f) => f.trim().replace(/^['\"]|['\"]$/g, '').trim())\n .filter((f) => f !== '');\n return families.length > 0 ? families : raw;\n }\n return raw;\n}\n","/**\n * A resolved color at `alpha`, multiplied into any alpha it already carries. The\n * JS side of the alpha extension; the CSS side emits `color-mix()` instead so DOM\n * chrome keeps tracking a downstream override of the referenced token.\n *\n * Hex and `rgb()`/`rgba()` become an `rgba()` literal. Anything else — a named\n * color, `hsl()`, `oklch()`, a `var()` — becomes the same `color-mix()` the CSS\n * side writes, which the browser resolves.\n */\nexport function withAlpha(color: string, alpha: number): string {\n const rgba = parseRgba(color.trim());\n if (!rgba) return `color-mix(in srgb, ${color.trim()} ${round(alpha * 100, 4)}%, transparent)`;\n const [r, g, b, a] = rgba;\n return `rgba(${r}, ${g}, ${b}, ${round(a * alpha, 3)})`;\n}\n\ntype Rgba = [number, number, number, number];\n\nfunction round(n: number, places: number): number {\n return Number(n.toFixed(places));\n}\n\nfunction parseRgba(s: string): Rgba | null {\n if (s.toLowerCase() === 'transparent') return [0, 0, 0, 0];\n return parseHex(s) ?? parseRgbFn(s);\n}\n\nfunction parseHex(s: string): Rgba | null {\n const m = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.exec(s);\n if (!m) return null;\n const body = m[1];\n const full = body.length <= 4 ? body.replace(/./g, (c) => c + c) : body;\n const byte = (i: number) => Number.parseInt(full.slice(i, i + 2), 16);\n return [byte(0), byte(2), byte(4), full.length === 8 ? byte(6) / 255 : 1];\n}\n\nfunction parseRgbFn(s: string): Rgba | null {\n const m = /^rgba?\\(([^()]*)\\)$/i.exec(s);\n if (!m) return null;\n const [channels, alphaPart, extra] = m[1].split('/');\n if (extra !== undefined) return null;\n const parts = channels.trim().split(/\\s*,\\s*|\\s+/);\n if (alphaPart !== undefined) parts.push(alphaPart.trim());\n if (parts.length !== 3 && parts.length !== 4) return null;\n\n const channel = (p: string) => (p.endsWith('%') ? (Number.parseFloat(p) / 100) * 255 : Number(p));\n const alpha = (p: string) => (p.endsWith('%') ? Number.parseFloat(p) / 100 : Number(p));\n const [r, g, b] = parts.slice(0, 3).map(channel);\n const a = parts[3] === undefined ? 1 : alpha(parts[3]);\n if (![r, g, b, a].every(Number.isFinite)) return null;\n return [Math.round(r), Math.round(g), Math.round(b), a];\n}\n","import { withAlpha } from './color';\nimport type { FlatTokens, ResolvedTokenMap, TokenValue } from './types';\nimport { serializeTokenValue } from './value';\n\n/** `{color.gray-100}` → `gray-100`. The type group is dropped, per the naming rule. */\nconst REF = /^\\{([^}]+)\\}$/;\n\nfunction refTarget(value: TokenValue): string | null {\n if (typeof value !== 'string') return null;\n const m = REF.exec(value.trim());\n if (!m) return null;\n const path = m[1];\n const dot = path.indexOf('.');\n return dot === -1 ? path : path.slice(dot + 1);\n}\n\n/**\n * Resolve flat tokens to final CSS-ready strings.\n *\n * Merge modes before calling: this function has no notion of modes, only of a\n * complete token set.\n */\nexport function resolveTokens(tokens: FlatTokens): ResolvedTokenMap {\n const out: ResolvedTokenMap = {};\n const inProgress = new Set<string>();\n\n const resolveOne = (name: string): string => {\n const cached = out[name];\n if (cached !== undefined) return cached;\n\n const token = tokens[name];\n if (!token) throw new Error(`Unknown token \"${name}\"`);\n\n if (inProgress.has(name)) {\n throw new Error(`Reference cycle at token \"${name}\" (${[...inProgress].join(' → ')})`);\n }\n inProgress.add(name);\n\n const target = refTarget(token.value);\n let value: string;\n if (target === null) {\n value = serializeTokenValue(token.type, token.value);\n } else if (!tokens[target]) {\n throw new Error(`Token \"${name}\" references \"${target}\", which is not defined`);\n } else {\n value = resolveOne(target);\n }\n\n if (token.alpha !== undefined) value = withAlpha(value, token.alpha);\n\n inProgress.delete(name);\n out[name] = value;\n return value;\n };\n\n for (const name of Object.keys(tokens)) resolveOne(name);\n return out;\n}\n\n/** Merge a mode's tokens over the mode-invariant set. Later wins. */\nexport function mergeTokens(base: FlatTokens, mode: FlatTokens): FlatTokens {\n return { ...base, ...mode };\n}\n","import { fullSelection, mergeAxes, pickAll, type AxisDefs, type Selection } from './axes';\nimport { resolveTokens } from './dtcg/resolve';\nimport type { FlatTokens } from './dtcg/types';\nimport type { TokenName } from './generated/themes';\nimport type { Theme } from './theme';\n\n/** The output of `resolveTheme`: every token of a theme, for one selection, keyed\n * by CSS custom-property name and flattened to a final CSS value. */\nexport type ResolvedTheme = Readonly<Record<TokenName, string>>;\n\n/** Root-first, so the leaf theme's tokens land last. */\nexport function themeChain(theme: Theme): Theme[] {\n const out: Theme[] = [];\n for (let t: Theme | null = theme; t; t = t.extends) out.unshift(t);\n return out;\n}\n\n/** Every axis the chain declares. An axis declared more than once keeps every value; a descendant's value entries and default win. */\nexport function themeAxes(theme: Theme): AxisDefs {\n return themeChain(theme).reduce<AxisDefs>((axes, t) => mergeAxes(axes, t.axes), {});\n}\n\n/**\n * Merge the extends chain at a selection, resolve every alias, and key the\n * result by CSS custom-property name. A missing or unknown axis value takes the\n * axis default.\n *\n * Pure — no DOM. An unresolvable reference throws rather than falling back.\n */\nexport function resolveTheme(theme: Theme, selection: Selection = {}): ResolvedTheme {\n const sel = fullSelection(themeAxes(theme), selection);\n let merged: FlatTokens = {};\n for (const t of themeChain(theme)) merged = { ...merged, ...pickAll(t.tokens, sel) };\n const out: Record<string, string> = {};\n for (const [name, value] of Object.entries(resolveTokens(merged))) out[`--wzl-${name}`] = value;\n return out as ResolvedTheme;\n}\n"]}
@@ -1,6 +0,0 @@
1
- // src/dtcg/types.ts
2
- var ALPHA_EXT = "com.weasel.alpha";
3
-
4
- export { ALPHA_EXT };
5
- //# sourceMappingURL=chunk-PJMTWM34.js.map
6
- //# sourceMappingURL=chunk-PJMTWM34.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/dtcg/types.ts"],"names":[],"mappings":";AACO,IAAM,SAAA,GAAY","file":"chunk-PJMTWM34.js","sourcesContent":["/** The one `$extensions` key this kit defines. */\nexport const ALPHA_EXT = 'com.weasel.alpha';\n\nexport type TokenValue = string | number | readonly (string | number)[];\n\n/**\n * A single design token as authored, before aliases are resolved: a DTCG-shaped\n * `{ type, value }` pair where `value` may still be a `{ref}` to another token.\n */\nexport interface RawToken {\n readonly type: string;\n readonly value: TokenValue;\n /** Render the referenced color at this alpha, 0–1. */\n readonly alpha?: number | undefined;\n readonly description?: string | undefined;\n}\n\n/** A token graph flattened to one level, keyed by token name (no `--wzl-`\n * prefix). Still unresolved — see `ResolvedTokenMap` for the output side. */\nexport type FlatTokens = Record<string, RawToken>;\n\n/** A resolved theme: every token name mapped to its final CSS-ready string.\n * Named ...Map, not ...Tokens, to stay distinct from hud's public `ResolvedTokens`. */\nexport type ResolvedTokenMap = Record<string, string>;\n"]}