@weasel-js/theme 1.9.2 → 1.9.4

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.
@@ -72,7 +72,7 @@ declare function bakeChain(definition: ThemeDefinition, lookup?: Lookup): BakedT
72
72
 
73
73
  /** Every design token the built-in themes declare, spelled as the CSS
74
74
  * custom property it becomes. */
75
- type TokenName = '--wzl-accent' | '--wzl-accent-base' | '--wzl-accent-fg' | '--wzl-accent-hover' | '--wzl-accent-soft' | '--wzl-accent-strong' | '--wzl-backdrop' | '--wzl-border' | '--wzl-border-strong' | '--wzl-border-w' | '--wzl-checker-a' | '--wzl-checker-b' | '--wzl-checker-size' | '--wzl-control-h' | '--wzl-control-h-sm' | '--wzl-control-h-xs' | '--wzl-curve-color' | '--wzl-curve-width' | '--wzl-danger' | '--wzl-danger-base' | '--wzl-ease-in-cubic' | '--wzl-ease-in-out-cubic' | '--wzl-ease-out-back' | '--wzl-ease-out-cubic' | '--wzl-fg' | '--wzl-fg-inverse' | '--wzl-fg-muted' | '--wzl-fg-muted-on-accent' | '--wzl-fg-on-accent' | '--wzl-fg-subtle' | '--wzl-fg-subtle-on-accent' | '--wzl-field-pad-x' | '--wzl-focus-ring' | '--wzl-font-body' | '--wzl-font-display' | '--wzl-font-mono' | '--wzl-font-numeric' | '--wzl-font-size' | '--wzl-font-size-2xs' | '--wzl-font-size-lg' | '--wzl-font-size-md' | '--wzl-font-size-sm' | '--wzl-font-size-xl' | '--wzl-font-size-xs' | '--wzl-font-ui' | '--wzl-font-weight-bold' | '--wzl-font-weight-light' | '--wzl-font-weight-medium' | '--wzl-font-weight-normal' | '--wzl-glass-blur' | '--wzl-glass-tint' | '--wzl-gray-100' | '--wzl-gray-200' | '--wzl-gray-300' | '--wzl-gray-400' | '--wzl-gray-50' | '--wzl-gray-500' | '--wzl-gray-600' | '--wzl-gray-700' | '--wzl-gray-800' | '--wzl-gray-900' | '--wzl-handle-size' | '--wzl-handle-size-lg' | '--wzl-handle-size-sm' | '--wzl-icon-button-size' | '--wzl-leading' | '--wzl-leading-snug' | '--wzl-leading-tight' | '--wzl-line' | '--wzl-line-strong' | '--wzl-line-subtle' | '--wzl-line-width' | '--wzl-motion-fast' | '--wzl-motion-medium' | '--wzl-panel-blur' | '--wzl-panel-border-color' | '--wzl-panel-border-style' | '--wzl-panel-border-width' | '--wzl-panel-pad' | '--wzl-panel-radius' | '--wzl-panel-surface' | '--wzl-panel-title-case' | '--wzl-panel-title-color' | '--wzl-panel-title-font' | '--wzl-panel-title-inset' | '--wzl-panel-title-size' | '--wzl-panel-title-tracking' | '--wzl-panel-title-weight' | '--wzl-panel-tone-mix' | '--wzl-radius-lg' | '--wzl-radius-md' | '--wzl-radius-pill' | '--wzl-radius-sm' | '--wzl-secondary' | '--wzl-secondary-base' | '--wzl-secondary-fg' | '--wzl-secondary-soft' | '--wzl-secondary-strong' | '--wzl-shadow' | '--wzl-slider-thumb-mix' | '--wzl-slider-thumb-size' | '--wzl-slider-thumb-slop' | '--wzl-slider-track-h' | '--wzl-slider-track-mix' | '--wzl-slider-track-slop' | '--wzl-space-1' | '--wzl-space-2' | '--wzl-space-3' | '--wzl-space-4' | '--wzl-space-5' | '--wzl-space-6' | '--wzl-space-7' | '--wzl-space-8' | '--wzl-space-lg' | '--wzl-space-md' | '--wzl-space-sm' | '--wzl-space-xs' | '--wzl-stance-advanced-title-color' | '--wzl-stance-aside-blur' | '--wzl-stance-aside-border-color' | '--wzl-stance-aside-surface' | '--wzl-stance-aside-title-color' | '--wzl-stance-danger-border-color' | '--wzl-stance-danger-title-color' | '--wzl-stance-danger-tone' | '--wzl-stance-debug-border-style' | '--wzl-stance-debug-title-case' | '--wzl-stance-debug-title-font' | '--wzl-stance-important-border-color' | '--wzl-stance-important-title-color' | '--wzl-stance-notice-tone' | '--wzl-stance-notice-tone-mix' | '--wzl-stance-preview-pad' | '--wzl-stance-preview-title-case' | '--wzl-stance-preview-title-inset' | '--wzl-stance-preview-title-size' | '--wzl-stance-scope-border-width' | '--wzl-stance-scope-nested-radius' | '--wzl-stance-scope-nested-surface' | '--wzl-stance-scope-radius' | '--wzl-stance-scope-tone-mix' | '--wzl-success' | '--wzl-success-base' | '--wzl-surface' | '--wzl-surface-hover' | '--wzl-surface-popover' | '--wzl-surface-pressed' | '--wzl-surface-raised' | '--wzl-surface-sunken' | '--wzl-swatch-amber' | '--wzl-swatch-blue' | '--wzl-swatch-citron' | '--wzl-swatch-fuchsia' | '--wzl-swatch-green' | '--wzl-swatch-red' | '--wzl-swatch-rose' | '--wzl-swatch-sky' | '--wzl-swatch-teal' | '--wzl-swatch-violet' | '--wzl-tb-height' | '--wzl-tracking-none' | '--wzl-tracking-wide' | '--wzl-tracking-wider' | '--wzl-warning' | '--wzl-warning-base' | '--wzl-workspace-line' | '--wzl-workspace-surface' | '--wzl-z-modal' | '--wzl-z-overlay' | '--wzl-z-toolbar';
75
+ type TokenName = '--wzl-accent' | '--wzl-accent-base' | '--wzl-accent-fg' | '--wzl-accent-hover' | '--wzl-accent-soft' | '--wzl-accent-strong' | '--wzl-backdrop' | '--wzl-border' | '--wzl-border-strong' | '--wzl-border-w' | '--wzl-checker-a' | '--wzl-checker-b' | '--wzl-checker-size' | '--wzl-code-constant' | '--wzl-code-keyword' | '--wzl-code-name' | '--wzl-code-number' | '--wzl-code-property' | '--wzl-code-string' | '--wzl-control-h' | '--wzl-control-h-sm' | '--wzl-control-h-xs' | '--wzl-curve-color' | '--wzl-curve-width' | '--wzl-danger' | '--wzl-danger-base' | '--wzl-ease-in-cubic' | '--wzl-ease-in-out-cubic' | '--wzl-ease-out-back' | '--wzl-ease-out-cubic' | '--wzl-fg' | '--wzl-fg-inverse' | '--wzl-fg-muted' | '--wzl-fg-muted-on-accent' | '--wzl-fg-on-accent' | '--wzl-fg-subtle' | '--wzl-fg-subtle-on-accent' | '--wzl-field-pad-x' | '--wzl-focus-ring' | '--wzl-font-body' | '--wzl-font-display' | '--wzl-font-mono' | '--wzl-font-numeric' | '--wzl-font-size' | '--wzl-font-size-2xs' | '--wzl-font-size-lg' | '--wzl-font-size-md' | '--wzl-font-size-sm' | '--wzl-font-size-xl' | '--wzl-font-size-xs' | '--wzl-font-ui' | '--wzl-font-weight-bold' | '--wzl-font-weight-light' | '--wzl-font-weight-medium' | '--wzl-font-weight-normal' | '--wzl-glass-blur' | '--wzl-glass-tint' | '--wzl-gray-100' | '--wzl-gray-200' | '--wzl-gray-300' | '--wzl-gray-400' | '--wzl-gray-50' | '--wzl-gray-500' | '--wzl-gray-600' | '--wzl-gray-700' | '--wzl-gray-800' | '--wzl-gray-900' | '--wzl-handle-size' | '--wzl-handle-size-lg' | '--wzl-handle-size-sm' | '--wzl-icon-button-size' | '--wzl-leading' | '--wzl-leading-snug' | '--wzl-leading-tight' | '--wzl-line' | '--wzl-line-strong' | '--wzl-line-subtle' | '--wzl-line-width' | '--wzl-motion-fast' | '--wzl-motion-medium' | '--wzl-panel-blur' | '--wzl-panel-border-color' | '--wzl-panel-border-style' | '--wzl-panel-border-width' | '--wzl-panel-pad' | '--wzl-panel-radius' | '--wzl-panel-surface' | '--wzl-panel-title-case' | '--wzl-panel-title-color' | '--wzl-panel-title-font' | '--wzl-panel-title-inset' | '--wzl-panel-title-size' | '--wzl-panel-title-tracking' | '--wzl-panel-title-weight' | '--wzl-panel-tone-mix' | '--wzl-radius-lg' | '--wzl-radius-md' | '--wzl-radius-pill' | '--wzl-radius-sm' | '--wzl-secondary' | '--wzl-secondary-base' | '--wzl-secondary-fg' | '--wzl-secondary-soft' | '--wzl-secondary-strong' | '--wzl-shadow' | '--wzl-slider-thumb-mix' | '--wzl-slider-thumb-size' | '--wzl-slider-thumb-slop' | '--wzl-slider-track-h' | '--wzl-slider-track-mix' | '--wzl-slider-track-slop' | '--wzl-space-1' | '--wzl-space-2' | '--wzl-space-3' | '--wzl-space-4' | '--wzl-space-5' | '--wzl-space-6' | '--wzl-space-7' | '--wzl-space-8' | '--wzl-space-lg' | '--wzl-space-md' | '--wzl-space-sm' | '--wzl-space-xs' | '--wzl-stance-advanced-title-color' | '--wzl-stance-aside-blur' | '--wzl-stance-aside-border-color' | '--wzl-stance-aside-surface' | '--wzl-stance-aside-title-color' | '--wzl-stance-danger-border-color' | '--wzl-stance-danger-title-color' | '--wzl-stance-danger-tone' | '--wzl-stance-debug-border-style' | '--wzl-stance-debug-title-case' | '--wzl-stance-debug-title-font' | '--wzl-stance-important-border-color' | '--wzl-stance-important-title-color' | '--wzl-stance-notice-tone' | '--wzl-stance-notice-tone-mix' | '--wzl-stance-preview-pad' | '--wzl-stance-preview-title-case' | '--wzl-stance-preview-title-inset' | '--wzl-stance-preview-title-size' | '--wzl-stance-scope-border-width' | '--wzl-stance-scope-nested-radius' | '--wzl-stance-scope-nested-surface' | '--wzl-stance-scope-radius' | '--wzl-stance-scope-tone-mix' | '--wzl-success' | '--wzl-success-base' | '--wzl-surface' | '--wzl-surface-hover' | '--wzl-surface-popover' | '--wzl-surface-pressed' | '--wzl-surface-raised' | '--wzl-surface-sunken' | '--wzl-swatch-amber' | '--wzl-swatch-blue' | '--wzl-swatch-citron' | '--wzl-swatch-fuchsia' | '--wzl-swatch-green' | '--wzl-swatch-red' | '--wzl-swatch-rose' | '--wzl-swatch-sky' | '--wzl-swatch-teal' | '--wzl-swatch-violet' | '--wzl-tb-height' | '--wzl-tracking-none' | '--wzl-tracking-wide' | '--wzl-tracking-wider' | '--wzl-warning' | '--wzl-warning-base' | '--wzl-workspace-line' | '--wzl-workspace-surface' | '--wzl-z-modal' | '--wzl-z-overlay' | '--wzl-z-toolbar';
76
76
  /** A built-in theme with its aliases already collapsed: every selection
77
77
  * (keyed `mode=dark`, axes in declaration order) maps every token name to
78
78
  * a final CSS value. */
@@ -164,6 +164,12 @@ declare const THEMES: {
164
164
  readonly '--wzl-secondary-fg': "#dc9d15";
165
165
  readonly '--wzl-fg-inverse': "#0e0f12";
166
166
  readonly '--wzl-shadow': "rgba(0, 0, 0, 0.6)";
167
+ readonly '--wzl-code-keyword': "#955cf9";
168
+ readonly '--wzl-code-string': "#48e628";
169
+ readonly '--wzl-code-number': "#e69628";
170
+ readonly '--wzl-code-constant': "#3ee1cb";
171
+ readonly '--wzl-code-property': "#36bff2";
172
+ readonly '--wzl-code-name': "#fa4590";
167
173
  readonly '--wzl-panel-surface': "#25272c";
168
174
  readonly '--wzl-panel-border-color': "#25272c";
169
175
  readonly '--wzl-panel-border-style': "solid";
@@ -241,8 +247,8 @@ declare const THEMES: {
241
247
  readonly '--wzl-slider-thumb-size': "8px";
242
248
  readonly '--wzl-slider-track-slop': "6px";
243
249
  readonly '--wzl-slider-thumb-slop': "6px";
244
- readonly '--wzl-slider-track-mix': "18%";
245
- readonly '--wzl-slider-thumb-mix': "70%";
250
+ readonly '--wzl-slider-track-mix': "40%";
251
+ readonly '--wzl-slider-thumb-mix': "100%";
246
252
  readonly '--wzl-handle-size': "9px";
247
253
  readonly '--wzl-handle-size-sm': "7px";
248
254
  readonly '--wzl-handle-size-lg': "10px";
@@ -336,6 +342,12 @@ declare const THEMES: {
336
342
  readonly '--wzl-secondary-fg': "#dc9d15";
337
343
  readonly '--wzl-fg-inverse': "#0e0f12";
338
344
  readonly '--wzl-shadow': "rgba(0, 0, 0, 0.6)";
345
+ readonly '--wzl-code-keyword': "#955cf9";
346
+ readonly '--wzl-code-string': "#48e628";
347
+ readonly '--wzl-code-number': "#e69628";
348
+ readonly '--wzl-code-constant': "#3ee1cb";
349
+ readonly '--wzl-code-property': "#36bff2";
350
+ readonly '--wzl-code-name': "#fa4590";
339
351
  readonly '--wzl-panel-surface': "#25272c";
340
352
  readonly '--wzl-panel-border-color': "#25272c";
341
353
  readonly '--wzl-panel-border-style': "solid";
@@ -413,8 +425,8 @@ declare const THEMES: {
413
425
  readonly '--wzl-slider-thumb-size': "8px";
414
426
  readonly '--wzl-slider-track-slop': "6px";
415
427
  readonly '--wzl-slider-thumb-slop': "6px";
416
- readonly '--wzl-slider-track-mix': "18%";
417
- readonly '--wzl-slider-thumb-mix': "70%";
428
+ readonly '--wzl-slider-track-mix': "40%";
429
+ readonly '--wzl-slider-thumb-mix': "100%";
418
430
  readonly '--wzl-handle-size': "9px";
419
431
  readonly '--wzl-handle-size-sm': "7px";
420
432
  readonly '--wzl-handle-size-lg': "10px";
@@ -508,6 +520,12 @@ declare const THEMES: {
508
520
  readonly '--wzl-secondary-fg': "#dc9d15";
509
521
  readonly '--wzl-fg-inverse': "#0e0f12";
510
522
  readonly '--wzl-shadow': "rgba(0, 0, 0, 0.6)";
523
+ readonly '--wzl-code-keyword': "#955cf9";
524
+ readonly '--wzl-code-string': "#48e628";
525
+ readonly '--wzl-code-number': "#e69628";
526
+ readonly '--wzl-code-constant': "#3ee1cb";
527
+ readonly '--wzl-code-property': "#36bff2";
528
+ readonly '--wzl-code-name': "#fa4590";
511
529
  readonly '--wzl-panel-surface': "#25272c";
512
530
  readonly '--wzl-panel-border-color': "#25272c";
513
531
  readonly '--wzl-panel-border-style': "solid";
@@ -585,8 +603,8 @@ declare const THEMES: {
585
603
  readonly '--wzl-slider-thumb-size': "8px";
586
604
  readonly '--wzl-slider-track-slop': "6px";
587
605
  readonly '--wzl-slider-thumb-slop': "6px";
588
- readonly '--wzl-slider-track-mix': "18%";
589
- readonly '--wzl-slider-thumb-mix': "70%";
606
+ readonly '--wzl-slider-track-mix': "40%";
607
+ readonly '--wzl-slider-thumb-mix': "100%";
590
608
  readonly '--wzl-handle-size': "9px";
591
609
  readonly '--wzl-handle-size-sm': "7px";
592
610
  readonly '--wzl-handle-size-lg': "10px";
@@ -680,6 +698,12 @@ declare const THEMES: {
680
698
  readonly '--wzl-secondary-fg': "#016458";
681
699
  readonly '--wzl-fg-inverse': "#f5f5f6";
682
700
  readonly '--wzl-shadow': "rgba(0, 0, 0, 0.18)";
701
+ readonly '--wzl-code-keyword': "#6d28d9";
702
+ readonly '--wzl-code-string': "#15803d";
703
+ readonly '--wzl-code-number': "#b45309";
704
+ readonly '--wzl-code-constant': "#0f766e";
705
+ readonly '--wzl-code-property': "#0369a1";
706
+ readonly '--wzl-code-name': "#be123c";
683
707
  readonly '--wzl-panel-surface': "#e6e7e9";
684
708
  readonly '--wzl-panel-border-color': "#c9cbcf";
685
709
  readonly '--wzl-panel-border-style': "solid";
@@ -852,6 +876,12 @@ declare const THEMES: {
852
876
  readonly '--wzl-secondary-fg': "#016458";
853
877
  readonly '--wzl-fg-inverse': "#f5f5f6";
854
878
  readonly '--wzl-shadow': "rgba(0, 0, 0, 0.18)";
879
+ readonly '--wzl-code-keyword': "#6d28d9";
880
+ readonly '--wzl-code-string': "#15803d";
881
+ readonly '--wzl-code-number': "#b45309";
882
+ readonly '--wzl-code-constant': "#0f766e";
883
+ readonly '--wzl-code-property': "#0369a1";
884
+ readonly '--wzl-code-name': "#be123c";
855
885
  readonly '--wzl-panel-surface': "#e6e7e9";
856
886
  readonly '--wzl-panel-border-color': "#c9cbcf";
857
887
  readonly '--wzl-panel-border-style': "solid";
@@ -1024,6 +1054,12 @@ declare const THEMES: {
1024
1054
  readonly '--wzl-secondary-fg': "#016458";
1025
1055
  readonly '--wzl-fg-inverse': "#f5f5f6";
1026
1056
  readonly '--wzl-shadow': "rgba(0, 0, 0, 0.18)";
1057
+ readonly '--wzl-code-keyword': "#6d28d9";
1058
+ readonly '--wzl-code-string': "#15803d";
1059
+ readonly '--wzl-code-number': "#b45309";
1060
+ readonly '--wzl-code-constant': "#0f766e";
1061
+ readonly '--wzl-code-property': "#0369a1";
1062
+ readonly '--wzl-code-name': "#be123c";
1027
1063
  readonly '--wzl-panel-surface': "#e6e7e9";
1028
1064
  readonly '--wzl-panel-border-color': "#c9cbcf";
1029
1065
  readonly '--wzl-panel-border-style': "solid";
@@ -1185,7 +1221,8 @@ declare function themeAxes(theme: Theme): AxisDefs;
1185
1221
  /**
1186
1222
  * Merge the extends chain at a selection, resolve every alias, and key the
1187
1223
  * result by CSS custom-property name. A missing or unknown axis value takes the
1188
- * axis default.
1224
+ * axis default, and a theme in the chain reads a value it never declared at its
1225
+ * own default for that axis.
1189
1226
  *
1190
1227
  * Pure — no DOM. An unresolvable reference throws rather than falling back.
1191
1228
  */
package/dist/engine.d.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  import { OklchDeg, oklchDegToHex } from '@weasel-js/paint';
2
- import { T as ThemeDefinition, L as Lookup, F as FlatTokens, R as RawToken, S as Selection, B as BakedTheme, A as AxisDefs, a as Theme } from './definition-DLgEuUUG.js';
3
- export { C as CategoricalRampDef, b as ContrastRule, c as LightnessRampDef, d as LiteralRule, N as NumberParam, O as OffsetRule, P as PinObject, e as PinValue, f as RampDef, g as RefRule, h as ScaleDef, i as SemanticRule, j as StepRule, k as bake, l as bakeChain, m as mergeChain } from './definition-DLgEuUUG.js';
2
+ import { T as ThemeDefinition, L as Lookup, F as FlatTokens, R as RawToken, S as Selection, B as BakedTheme, A as AxisDefs, a as Theme } from './definition-GS7_Kz9D.js';
3
+ export { C as CategoricalRampDef, b as ContrastRule, c as LightnessRampDef, d as LiteralRule, N as NumberParam, O as OffsetRule, P as PinObject, e as PinValue, f as RampDef, g as RefRule, h as ScaleDef, i as SemanticRule, j as StepRule, k as bake, l as bakeChain, m as mergeChain } from './definition-GS7_Kz9D.js';
4
4
 
5
5
  /** A color in OKLCH: lightness 0–1, chroma, hue in degrees. paint's own type,
6
6
  * under the name this engine has always called it. */
7
7
  type Lch = OklchDeg;
8
- /** `#rrggbb` to 0–255 channels. */
9
- declare function hexToRgb(hex: string): [number, number, number];
8
+ /** A hex color to 0–255 channels, its alpha dropped. Throws on anything else. */
9
+ declare const hexToRgb: (hex: string) => [number, number, number];
10
10
  /** OKLCH (lightness 0–1, chroma, hue in degrees) to `#rrggbb`. Chroma past the gamut is clipped at constant lightness. */
11
11
  declare const toHex: typeof oklchDegToHex;
12
12
  /** `#rrggbb` to OKLCH, hue in 0–360. */
package/dist/engine.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { overrideKey, AXES_EXT, ALPHA_EXT } from './chunk-Z675UQ26.js';
2
- import { mergeAxes, toLch, toHex, generate, DEFAULT_CONSTRAINTS, fullSelection, pick, enumerateSelections, resolveTokens, pickAll, themeAxes, selectionKey, isByAxis, contrast } from './chunk-NUILKH2Z.js';
3
- export { CHROMA_WEIGHT, DEFAULT_CONSTRAINTS, anchorFromHex, chromaCap, contrast, deltaE, floorDegrees, generate, hexToRgb, hueGap, hueName, luminance, toHex, toHexPreview, toLab, toLch, vividAt } from './chunk-NUILKH2Z.js';
2
+ import { mergeAxes, toLch, toHex, generate, DEFAULT_CONSTRAINTS, fullSelection, pick, enumerateSelections, resolveTokens, mixAlpha, pickAll, themeAxes, tokensAt, selectionKey, isByAxis, contrast, tokenAt } from './chunk-7LCRXZDY.js';
3
+ export { CHROMA_WEIGHT, DEFAULT_CONSTRAINTS, anchorFromHex, chromaCap, contrast, deltaE, floorDegrees, generate, hexToRgb, hueGap, hueName, luminance, toHex, toHexPreview, toLab, toLch, vividAt } from './chunk-7LCRXZDY.js';
4
+ import { isPlainObject } from '@weasel-js/registry';
4
5
 
5
6
  // src/engine/steps.ts
6
7
  var stepList = (x) => Array.isArray(x) ? [...new Set(x.filter((s) => typeof s === "string"))] : [];
@@ -217,6 +218,20 @@ function axisDependencies(definition, lookup) {
217
218
  return result;
218
219
  }
219
220
 
221
+ // src/engine/axisIssues.ts
222
+ function axisIssues(axes) {
223
+ const issues = [];
224
+ for (const [name, def] of Object.entries(axes)) {
225
+ const values = Object.keys(def.values ?? {});
226
+ if (values.length === 0) {
227
+ issues.push({ kind: "invalid", path: `axes.${name}`, message: `axis "${name}" has no values` });
228
+ } else if (!values.includes(def.default)) {
229
+ issues.push({ kind: "invalid", path: `axes.${name}`, message: `axis "${name}" defaults to "${def.default}", which is not one of its values (${values.join(", ")})` });
230
+ }
231
+ }
232
+ return issues;
233
+ }
234
+
220
235
  // src/engine/ramps.ts
221
236
  var MAX_CHROMA = 0.4;
222
237
  var smoothstep = (t) => t * t * (3 - 2 * t);
@@ -290,12 +305,10 @@ function scale(steps, p) {
290
305
  });
291
306
  return out;
292
307
  }
293
-
294
- // src/engine/semantics.ts
295
308
  var TOKEN_REF2 = /^\{([^}.]+)\}$/;
296
309
  var HEX = /^#[0-9a-f]{6}$/i;
297
310
  var MAX_DEPTH = 32;
298
- var isRecord = (x) => typeof x === "object" && x !== null && !Array.isArray(x);
311
+ var isRecord = isPlainObject;
299
312
  var refTarget = (value) => typeof value === "string" ? TOKEN_REF2.exec(value.trim())?.[1] : void 0;
300
313
  function deriveSemantics(rules, ctx) {
301
314
  const done = /* @__PURE__ */ new Map();
@@ -577,12 +590,12 @@ var Reader = class {
577
590
  }
578
591
  record(x, path) {
579
592
  if (x === void 0) return {};
580
- if (typeof x === "object" && x !== null && !Array.isArray(x)) return x;
593
+ if (isPlainObject(x)) return x;
581
594
  this.fail(path, "expected an object");
582
595
  return {};
583
596
  }
584
597
  };
585
- var isRecord2 = (x) => typeof x === "object" && x !== null && !Array.isArray(x);
598
+ var isRecord2 = isPlainObject;
586
599
  var stepNames = (x) => Array.isArray(x) && x.every((s) => typeof s === "string") ? x : void 0;
587
600
  function rampColors(name, r, steps, ctx) {
588
601
  const path = `ramps.${name}`;
@@ -726,7 +739,7 @@ function inferTypes(tokens, provenance, failed, issues) {
726
739
  issues.push({ kind: "untyped-pin", token: name });
727
740
  }
728
741
  }
729
- var isPinObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v) && "value" in v;
742
+ var isPinObject = (v) => isPlainObject(v) && "value" in v;
730
743
  var NAMED_LAYERS = ["ramps", "scales", "semantics", "components", "pins"];
731
744
  var SAFE_NAME = /^[A-Za-z0-9_-]+$/;
732
745
  var isSafeName = (name) => SAFE_NAME.test(name);
@@ -746,6 +759,7 @@ function withoutUnsafeNames(def, issues) {
746
759
  function derive(definition, selection = {}, lookup) {
747
760
  const issues = [];
748
761
  const def = withoutUnsafeNames(mergeChain(definition, lookup), issues);
762
+ issues.push(...axisIssues(def.axes ?? {}));
749
763
  const sel = fullSelection(def.axes ?? {}, selection);
750
764
  const seeds = {};
751
765
  for (const [k, v] of Object.entries(def.seeds ?? {})) {
@@ -937,23 +951,14 @@ function bakeOver(definition, merged, above, lookup) {
937
951
  const axes = merged.axes ?? {};
938
952
  const own = table(definition, axes, lookup);
939
953
  const at = (sel, name) => own.get(selectionKey(axes, sel))?.[name];
940
- const inherited = (sel, name) => {
941
- const full = fullSelection(axes, sel);
942
- for (let i = above.length - 1; i >= 0; i--) {
943
- const tokens2 = above[i].tokens;
944
- if (!Object.hasOwn(tokens2, name)) continue;
945
- const picked = pick(tokens2[name], full);
946
- if (picked.ok) return picked.value;
947
- }
948
- return void 0;
949
- };
954
+ const inherited = (sel, name) => tokenAt(above, name, fullSelection(axes, sel));
950
955
  const produced = new Set([...own.values()].flatMap((t) => Object.keys(t)));
951
956
  const ordered = definitionOrder(merged).filter((n) => produced.has(n));
952
957
  const names = [...ordered, ...[...produced].filter((n) => !ordered.includes(n))];
953
958
  const selections = enumerateSelections(axes);
954
959
  const tokens = {};
955
960
  for (const name of names) {
956
- if (selections.every((sel) => same(at(sel, name), inherited(sel, name)))) continue;
961
+ if (selections.every((sel) => at(sel, name) === void 0 || same(at(sel, name), inherited(sel, name)))) continue;
957
962
  const varying = Object.keys(axes).filter(
958
963
  (axis) => selections.some((sel) => Object.keys(axes[axis].values).some((v) => !same(at(sel, name), at({ ...sel, [axis]: v }, name))))
959
964
  );
@@ -998,7 +1003,7 @@ function cssValue(name, token) {
998
1003
  const target = refTarget2(token);
999
1004
  if (target === null) return resolveTokens({ [name]: token })[name];
1000
1005
  if (token.alpha === void 0) return `var(--wzl-${target})`;
1001
- return `color-mix(in srgb, var(--wzl-${target}) ${Math.round(token.alpha * 100)}%, transparent)`;
1006
+ return mixAlpha(`var(--wzl-${target})`, token.alpha);
1002
1007
  }
1003
1008
  function axisSets(axes) {
1004
1009
  const names = Object.keys(axes);
@@ -1030,21 +1035,16 @@ function combineAxes(own, other) {
1030
1035
  var Resolved = class {
1031
1036
  axes;
1032
1037
  names;
1038
+ /** Root first. */
1033
1039
  chain;
1034
1040
  memo = /* @__PURE__ */ new Map();
1035
1041
  constructor(axes, chain) {
1036
1042
  this.axes = axes;
1037
1043
  this.chain = chain;
1038
- this.names = [...new Set([...chain].reverse().flatMap((t) => Object.keys(t.tokens)))];
1044
+ this.names = [...new Set(chain.flatMap((t) => Object.keys(t.tokens)))];
1039
1045
  }
1040
1046
  token(name, sel) {
1041
- const full = fullSelection(this.axes, sel);
1042
- for (const t of this.chain) {
1043
- if (!Object.hasOwn(t.tokens, name)) continue;
1044
- const picked = pick(t.tokens[name], full);
1045
- if (picked.ok) return picked.value;
1046
- }
1047
- return void 0;
1047
+ return tokenAt(this.chain, name, fullSelection(this.axes, sel));
1048
1048
  }
1049
1049
  /** What a browser computes: every `var()` substituted, down to literals. */
1050
1050
  expanded(name, sel, stack = []) {
@@ -1064,7 +1064,7 @@ function chainOf(baked, byName) {
1064
1064
  if (!baked.extends) return [baked];
1065
1065
  const parent = byName.get(baked.extends);
1066
1066
  if (!parent) throw new Error(`Theme "${baked.name}" extends "${baked.extends}", which is not being emitted`);
1067
- return [baked, ...chainOf(parent, byName)];
1067
+ return [...chainOf(parent, byName), baked];
1068
1068
  }
1069
1069
  var union = (axes, ...sets) => {
1070
1070
  const all = new Set(sets.flatMap((s) => s ?? []));
@@ -1380,6 +1380,48 @@ var TOKEN_HOOKS = [
1380
1380
  type: "dimension",
1381
1381
  value: "calc(var(--wzl-control-h-xs) + var(--wzl-space-2))",
1382
1382
  description: "Indent of each Tree level. Unset, it is one twisty and one gap, so a child\u2019s twisty sits under its parent\u2019s label."
1383
+ },
1384
+ {
1385
+ name: "tree-font-size",
1386
+ type: "dimension",
1387
+ value: "var(--wzl-font-size-sm)",
1388
+ description: "Size of a Tree row\u2019s text."
1389
+ },
1390
+ {
1391
+ name: "tree-fold-size",
1392
+ type: "dimension",
1393
+ value: "16px",
1394
+ description: "Size of the leading glyph a Tree folds a branch by, where its branches fold by their glyphs."
1395
+ },
1396
+ {
1397
+ name: "tree-guide",
1398
+ type: "color",
1399
+ value: "var(--wzl-fg-subtle)",
1400
+ description: "Color of the bracket a Tree draws down a branch."
1401
+ },
1402
+ {
1403
+ name: "dialog-max-width",
1404
+ type: "dimension",
1405
+ value: "900px",
1406
+ description: "Widest a Dialog grows, modal or inline, before its contents wrap or scroll."
1407
+ },
1408
+ {
1409
+ name: "prefs-across-gap",
1410
+ type: "dimension",
1411
+ value: "28px",
1412
+ description: "Gap between the two columns of rows a PrefsForm pane sets side by side."
1413
+ },
1414
+ {
1415
+ name: "prefs-control-min",
1416
+ type: "dimension",
1417
+ value: "80px",
1418
+ description: "Narrowest a PrefsForm row\u2019s control gets in a two-across pane before the row wraps it under its label."
1419
+ },
1420
+ {
1421
+ name: "prop-panel-actions-basis",
1422
+ type: "dimension",
1423
+ value: "auto",
1424
+ description: "Width a PropertyPanel\u2019s title row gives its actions. Set, it holds that width whatever the actions are."
1383
1425
  }
1384
1426
  ];
1385
1427
 
@@ -1434,9 +1476,6 @@ function chainOf2(baked, byName) {
1434
1476
  if (baked.extends && !parent) throw new Error(`Theme "${baked.name}" extends "${baked.extends}", which is not in themes/`);
1435
1477
  return [...parent ? chainOf2(parent, byName) : [], baked];
1436
1478
  }
1437
- function tokensAt(chain, sel) {
1438
- return Object.assign({}, ...chain.map((t) => pickAll(t.tokens, sel)));
1439
- }
1440
1479
  function emitThemes(themes) {
1441
1480
  const byName = new Map(themes.map((t) => [t.baked.name, t.baked]));
1442
1481
  const names = /* @__PURE__ */ new Set();
@@ -1506,11 +1545,12 @@ function generateTokens(definitions) {
1506
1545
  const roots = definitions.filter((d) => !d.extends);
1507
1546
  if (roots.length !== 1) throw new Error(`themes/ needs exactly one theme that extends nothing; found ${roots.length}`);
1508
1547
  const ordered = [roots[0], ...definitions.filter((d) => d.extends)];
1509
- const problems = ordered.flatMap(
1510
- (def) => enumerateSelections(mergeChain(def, lookup).axes ?? {}).flatMap(
1548
+ const problems = ordered.flatMap((def) => {
1549
+ const selections = enumerateSelections(mergeChain(def, lookup).axes ?? {});
1550
+ return (selections.length > 0 ? selections : [{}]).flatMap(
1511
1551
  (sel) => derive(def, sel, lookup).issues.map((issue) => `${def.name} ${JSON.stringify(sel)}: ${JSON.stringify(issue)}`)
1512
- )
1513
- );
1552
+ );
1553
+ });
1514
1554
  if (problems.length > 0) return { ok: false, problems };
1515
1555
  const themes = ordered.map((definition) => ({
1516
1556
  definition,