@weasel-js/theme 1.5.2 → 1.6.1

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/faces.css ADDED
@@ -0,0 +1,19 @@
1
+ /* The kit's two faces, declared and nothing else. `fonts.css` pairs them with a
2
+ * document font; `@weasel-js/labkit` carries them in its stylesheet.
3
+ * Licenses: OFL-Oswald.txt and OFL-Inter.txt in @weasel-js/theme's fonts/. */
4
+
5
+ @font-face {
6
+ font-family: 'Oswald';
7
+ font-style: normal;
8
+ font-weight: 200 700;
9
+ font-display: swap;
10
+ src: url('../fonts/oswald-latin-variable.woff2') format('woff2');
11
+ }
12
+
13
+ @font-face {
14
+ font-family: 'Inter';
15
+ font-style: normal;
16
+ font-weight: 400;
17
+ font-display: swap;
18
+ src: url('../fonts/inter-latin.woff2') format('woff2');
19
+ }
package/dist/fonts.css CHANGED
@@ -1,26 +1,12 @@
1
1
  /* Opt-in typography: the kit's intended faces, and the document set in them.
2
2
  * Import this only if you want both — the token font stacks fall back to
3
3
  * system-ui without the faces, and `tokens.css` sets no font of its own, so an
4
- * app with its own typography can import the tokens and skip this file.
5
- * Licenses: ../fonts/OFL-Oswald.txt, ../fonts/OFL-Inter.txt */
4
+ * app with its own typography can import the tokens and skip this file, or
5
+ * take `faces.css` for the faces alone. */
6
+
7
+ @import './faces.css';
6
8
 
7
9
  :root {
8
10
  font-family: var(--wzl-font-ui);
9
11
  font-weight: var(--wzl-font-weight-normal);
10
12
  }
11
-
12
- @font-face {
13
- font-family: 'Oswald';
14
- font-style: normal;
15
- font-weight: 200 700;
16
- font-display: swap;
17
- src: url('../fonts/oswald-latin-variable.woff2') format('woff2');
18
- }
19
-
20
- @font-face {
21
- font-family: 'Inter';
22
- font-style: normal;
23
- font-weight: 400;
24
- font-display: swap;
25
- src: url('../fonts/inter-latin.woff2') format('woff2');
26
- }
package/dist/index.d.ts CHANGED
@@ -1,7 +1,6 @@
1
- import { T as TokenName, R as ResolvedTheme } from './resolveTheme-CF8i5IHy.js';
2
- export { B as BAKED_THEMES, G as GeneratedTheme, a as THEMES, b as THEME_SOURCES, r as resolveTheme, t as themeAxes } from './resolveTheme-CF8i5IHy.js';
3
- import { T as Theme, S as Selection, a as TokenValue } from './theme-DAZcQi_L.js';
4
- export { A as AxisDef, b as AxisDefs, c as AxisValue, B as BakedTheme, d as ByAxis, F as FlatTokens, P as PinObject, e as PinValue, R as RawToken, f as ThemeDefinition, g as ThemeInput, V as Varying, h as defineTheme, i as enumerateSelections, j as fullSelection, k as isByAxis, s as selectionKey, w as weaselTheme } from './theme-DAZcQi_L.js';
1
+ import { n as TokenName, o as ResolvedTheme, a as Theme, S as Selection, p as TokenValue } from './definition-DLdTdFWs.js';
2
+ export { q as AxisDef, A as AxisDefs, r as AxisValue, s as BAKED_THEMES, B as BakedTheme, t as ByAxis, u as ColorContext, v as ColorList, F as FlatTokens, G as GeneratedColors, w as GeneratedTheme, P as PinObject, e as PinValue, x as RampColors, R as RawToken, y as SerializableColorList, z as THEMES, D as THEME_SOURCES, T as ThemeDefinition, E as ThemeInput, V as Varying, H as colorAt, I as colorCount, J as colorCssAt, K as defineTheme, M as enumerateSelections, Q as fullSelection, U as isByAxis, W as rampSteps, X as resolveTheme, Y as selectionKey, Z as themeAxes, _ as themeTones, $ as weaselTheme } from './definition-DLdTdFWs.js';
3
+ export { C as ColorMode, a as ColorModePreference, i as isColorModePreference } from './colorMode-CoklZomJ.js';
5
4
 
6
5
  /** One row of `TOKEN_MANIFEST`: a token, its DTCG type, the name-prefix
7
6
  * group it belongs to, its value in the default theme and selection, and
@@ -52,11 +51,14 @@ interface DtcgDocument {
52
51
  extends?: Theme | null;
53
52
  primitives?: Record<string, unknown>;
54
53
  modes?: Record<string, Record<string, unknown>>;
54
+ $extensions?: Record<string, unknown>;
55
55
  }
56
56
  /**
57
57
  * Build a `Theme` from a DTCG document — the interchange path, for tokens
58
58
  * exported by a design tool rather than authored in TS. A token a mode leaves
59
59
  * out takes the document's primitive of the same name, or else the base theme's.
60
+ * Axes besides mode come from `$extensions["com.weasel.axes"]`, the encoding
61
+ * `toDTCG` writes; a document without it loads with mode as its only axis.
60
62
  */
61
63
  declare function loadDTCG(doc: DtcgDocument): Theme;
62
64
 
@@ -73,4 +75,46 @@ declare function serializeTokenValue(type: string, value: TokenValue): string;
73
75
  */
74
76
  declare function parseTokenValue(type: string, text: string): TokenValue;
75
77
 
76
- export { ResolvedTheme, Selection, TOKEN_MANIFEST, Theme, type TokenManifestEntry, TokenName, TokenValue, applyTheme, loadDTCG, parseTokenValue, serializeTokenValue, tokenPx };
78
+ /**
79
+ * The vocabulary of stances, and the slots a theme styles a stanced surface with.
80
+ *
81
+ * A stance looks the same on every surface that takes one. A surface reads
82
+ * `--wzl-stance-<stance>-<slot>` first — a nested panel
83
+ * `--wzl-stance-<stance>-nested-<slot>` before that — and falls back to its
84
+ * own base look, so a theme declares only the slots where a stance differs and
85
+ * every other name here is read, with its fallback, and declared by nothing.
86
+ * A panel's base look is itself theme slots, `--wzl-panel-<slot>`.
87
+ */
88
+ /** What kind of content a surface holds — a class of content, never a position. */
89
+ declare const STANCES: readonly ["scope", "aside", "advanced", "debug", "danger", "notice", "important", "preview"];
90
+ type Stance = (typeof STANCES)[number];
91
+ /** One styleable property of a stanced surface. */
92
+ interface StanceSlot {
93
+ readonly name: string;
94
+ /** What it drives, for tooling. */
95
+ readonly drives: string;
96
+ }
97
+ declare const STANCE_SLOTS: readonly StanceSlot[];
98
+ /** Every stance-slot name, `--wzl-`-prefixed, nested variants included. */
99
+ declare function stanceSlotNames(): string[];
100
+ /** What `resolveStanceSlots` resolves a surface against, besides its tokens. */
101
+ interface StanceLookup<S extends string> {
102
+ readonly stance?: Stance;
103
+ /** The surface sits inside one of its own kind, and reads `-nested-<slot>` first. */
104
+ readonly nested?: boolean;
105
+ /** A stanced surface's fallback, where it differs from `base`. */
106
+ readonly stanced?: Partial<Readonly<Record<S, string>>>;
107
+ }
108
+ /**
109
+ * A stanced surface's look, for one drawn without the cascade — a canvas
110
+ * surface reading a resolved theme. The same lookup the generated CSS makes:
111
+ * `--wzl-stance-<stance>-<slot>`, then the stanced fallback, then `base`.
112
+ * `base` holds final values, one per slot the surface draws.
113
+ *
114
+ * The tone is the caller's: a surface that names one mixes it into
115
+ * `surface` at `tone-mix`; one that names none takes the `tone` slot, which
116
+ * falls back to `surface` so mixing it changes nothing.
117
+ */
118
+ declare function resolveStanceSlots<S extends string>(tokens: Readonly<Record<string, string>>, base: Readonly<Record<S, string>>, { stance, nested, stanced }?: StanceLookup<S>): Record<S, string>;
119
+
120
+ export { ResolvedTheme, STANCES, STANCE_SLOTS, Selection, type Stance, type StanceLookup, type StanceSlot, TOKEN_MANIFEST, Theme, type TokenManifestEntry, TokenName, TokenValue, applyTheme, loadDTCG, parseTokenValue, resolveStanceSlots, serializeTokenValue, stanceSlotNames, tokenPx };
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import { weaselTheme } from './chunk-XFCWYN2L.js';
2
- export { BAKED_THEMES, THEMES, THEME_SOURCES, applyTheme, defineTheme, weaselTheme } from './chunk-XFCWYN2L.js';
3
- import { ALPHA_EXT } from './chunk-PJMTWM34.js';
4
- import { themeAxes } from './chunk-LL2ERJPZ.js';
5
- export { enumerateSelections, fullSelection, isByAxis, parseTokenValue, resolveTheme, selectionKey, serializeTokenValue, themeAxes } from './chunk-LL2ERJPZ.js';
1
+ import { weaselTheme } from './chunk-4EIPTWJA.js';
2
+ export { BAKED_THEMES, THEMES, THEME_SOURCES, applyTheme, colorAt, colorCount, colorCssAt, defineTheme, isColorModePreference, rampSteps, themeTones, weaselTheme } from './chunk-4EIPTWJA.js';
3
+ import { AXES_EXT, overrideKey, ALPHA_EXT } from './chunk-EINHFDWI.js';
4
+ import { themeAxes, mergeAxes } from './chunk-C3S4A65R.js';
5
+ export { enumerateSelections, fullSelection, isByAxis, parseTokenValue, resolveTheme, selectionKey, serializeTokenValue, themeAxes } from './chunk-C3S4A65R.js';
6
6
 
7
7
  // src/generated/manifest.ts
8
8
  var TOKEN_MANIFEST = [
@@ -19,6 +19,9 @@ var TOKEN_MANIFEST = [
19
19
  { name: "--wzl-accent-soft", type: "color", group: "accent", defaultValue: "#1d1454", description: "", hook: false },
20
20
  { name: "--wzl-accent-base", type: "color", group: "accent", defaultValue: "#2e1f7a", description: "Midnight blue-violet. Deep and saturated; anchors primary actions on light and dark surfaces alike.", hook: false },
21
21
  { name: "--wzl-accent-strong", type: "color", group: "accent", defaultValue: "#5841b8", description: "", hook: false },
22
+ { name: "--wzl-secondary-soft", type: "color", group: "secondary", defaultValue: "#704e09", description: "", hook: false },
23
+ { name: "--wzl-secondary-base", type: "color", group: "secondary", defaultValue: "#dc9d15", description: "", hook: false },
24
+ { name: "--wzl-secondary-strong", type: "color", group: "secondary", defaultValue: "#f1cb8d", description: "", hook: false },
22
25
  { name: "--wzl-swatch-fuchsia", type: "color", group: "swatch", defaultValue: "#f641f7", description: "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\xB0 apart, all ten 32\xB0). Mode-invariant on purpose \u2014 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.", hook: false },
23
26
  { name: "--wzl-swatch-green", type: "color", group: "swatch", defaultValue: "#48e628", description: "", hook: false },
24
27
  { name: "--wzl-swatch-sky", type: "color", group: "swatch", defaultValue: "#36bff2", description: "", hook: false },
@@ -52,8 +55,48 @@ var TOKEN_MANIFEST = [
52
55
  { name: "--wzl-border", type: "color", group: "border", defaultValue: "#25272c", description: "", hook: false },
53
56
  { name: "--wzl-border-strong", type: "color", group: "border", defaultValue: "#6f737b", description: "The line that has to be seen: a control's edge, a raised surface's outline. Clears WCAG 1.4.11's 3:1 against every surface in both modes.", hook: false },
54
57
  { name: "--wzl-accent-fg", type: "color", group: "accent", defaultValue: "#5841b8", description: "Accent for foreground use \u2014 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.", hook: false },
58
+ { name: "--wzl-secondary-fg", type: "color", group: "secondary", defaultValue: "#dc9d15", description: "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.", hook: false },
55
59
  { name: "--wzl-fg-inverse", type: "color", group: "fg", defaultValue: "#0e0f12", description: "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.", hook: false },
56
60
  { name: "--wzl-shadow", type: "color", group: "shadow", defaultValue: "rgba(0, 0, 0, 0.6)", description: "Elevation. Always darker than any surface \u2014 never derived from fg, which is near-white on dark.", hook: false },
61
+ { name: "--wzl-panel-surface", type: "color", group: "panel", defaultValue: "#25272c", description: "Fill of a PropertyPanel.", hook: false },
62
+ { name: "--wzl-panel-border-color", type: "color", group: "panel", defaultValue: "#25272c", description: "", hook: false },
63
+ { name: "--wzl-panel-border-style", type: "string", group: "panel", defaultValue: "solid", description: "", hook: false },
64
+ { name: "--wzl-panel-border-width", type: "dimension", group: "panel", defaultValue: "1px", description: "", hook: false },
65
+ { name: "--wzl-panel-radius", type: "dimension", group: "panel", defaultValue: "14px", description: "", hook: false },
66
+ { name: "--wzl-panel-pad", type: "dimension", group: "panel", defaultValue: "14px 16px", description: "A panel\u2019s padding when no density sets one.", hook: false },
67
+ { name: "--wzl-panel-blur", type: "dimension", group: "panel", defaultValue: "3px", description: "", hook: false },
68
+ { name: "--wzl-panel-tone-mix", type: "number", group: "panel", defaultValue: "14%", description: "How much of a panel\u2019s tone mixes into its surface.", hook: false },
69
+ { name: "--wzl-panel-title-font", type: "fontFamily", group: "panel", defaultValue: "Oswald, 'Helvetica Neue Condensed', 'Arial Narrow', system-ui, sans-serif", description: "", hook: false },
70
+ { name: "--wzl-panel-title-weight", type: "fontWeight", group: "panel", defaultValue: "200", description: "", hook: false },
71
+ { name: "--wzl-panel-title-size", type: "dimension", group: "panel", defaultValue: "16px", description: "", hook: false },
72
+ { name: "--wzl-panel-title-case", type: "string", group: "panel", defaultValue: "none", description: "", hook: false },
73
+ { name: "--wzl-panel-title-tracking", type: "dimension", group: "panel", defaultValue: "0.01em", description: "", hook: false },
74
+ { name: "--wzl-panel-title-color", type: "color", group: "panel", defaultValue: "#e6e7e9", description: "", hook: false },
75
+ { name: "--wzl-panel-title-inset", type: "dimension", group: "panel", defaultValue: "0", description: "", hook: false },
76
+ { name: "--wzl-stance-scope-border-width", type: "dimension", group: "stance", defaultValue: "0", description: "", hook: false },
77
+ { name: "--wzl-stance-scope-radius", type: "dimension", group: "stance", defaultValue: "8px", description: "", hook: false },
78
+ { name: "--wzl-stance-scope-tone-mix", type: "number", group: "stance", defaultValue: "22%", description: "", hook: false },
79
+ { name: "--wzl-stance-scope-nested-radius", type: "dimension", group: "stance", defaultValue: "6px", description: "", hook: false },
80
+ { name: "--wzl-stance-scope-nested-surface", type: "color", group: "stance", defaultValue: "#181a1e", description: "A scope panel inside another sits back into it.", hook: false },
81
+ { name: "--wzl-stance-aside-surface", type: "color", group: "stance", defaultValue: "transparent", description: "", hook: false },
82
+ { name: "--wzl-stance-aside-border-color", type: "color", group: "stance", defaultValue: "rgba(230, 231, 233, 0.1)", description: "", hook: false },
83
+ { name: "--wzl-stance-aside-blur", type: "dimension", group: "stance", defaultValue: "0px", description: "", hook: false },
84
+ { name: "--wzl-stance-aside-title-color", type: "color", group: "stance", defaultValue: "#6f737b", description: "", hook: false },
85
+ { name: "--wzl-stance-advanced-title-color", type: "color", group: "stance", defaultValue: "#6f737b", description: "", hook: false },
86
+ { name: "--wzl-stance-debug-border-style", type: "string", group: "stance", defaultValue: "dashed", description: "", hook: false },
87
+ { name: "--wzl-stance-debug-title-font", type: "fontFamily", group: "stance", defaultValue: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace", description: "", hook: false },
88
+ { name: "--wzl-stance-debug-title-case", type: "string", group: "stance", defaultValue: "none", description: "", hook: false },
89
+ { name: "--wzl-stance-danger-tone", type: "color", group: "stance", defaultValue: "#d94a3f", description: "", hook: false },
90
+ { name: "--wzl-stance-danger-border-color", type: "color", group: "stance", defaultValue: "#d94a3f", description: "", hook: false },
91
+ { name: "--wzl-stance-danger-title-color", type: "color", group: "stance", defaultValue: "#d94a3f", description: "", hook: false },
92
+ { name: "--wzl-stance-notice-tone", type: "color", group: "stance", defaultValue: "#2e1f7a", description: "", hook: false },
93
+ { name: "--wzl-stance-notice-tone-mix", type: "number", group: "stance", defaultValue: "8%", description: "", hook: false },
94
+ { name: "--wzl-stance-important-border-color", type: "color", group: "stance", defaultValue: "#5841b8", description: "", hook: false },
95
+ { name: "--wzl-stance-important-title-color", type: "color", group: "stance", defaultValue: "#5841b8", description: "", hook: false },
96
+ { name: "--wzl-stance-preview-pad", type: "dimension", group: "stance", defaultValue: "0", description: "", hook: false },
97
+ { name: "--wzl-stance-preview-title-size", type: "dimension", group: "stance", defaultValue: "10px", description: "", hook: false },
98
+ { name: "--wzl-stance-preview-title-case", type: "string", group: "stance", defaultValue: "none", description: "", hook: false },
99
+ { name: "--wzl-stance-preview-title-inset", type: "dimension", group: "stance", defaultValue: "6px 10px 0", description: "", hook: false },
57
100
  { name: "--wzl-danger-base", type: "color", group: "status", defaultValue: "#d94a3f", description: "", hook: false },
58
101
  { name: "--wzl-warning-base", type: "color", group: "status", defaultValue: "#d99a3f", description: "", hook: false },
59
102
  { name: "--wzl-success-base", type: "color", group: "status", defaultValue: "#2ec27e", description: "", hook: false },
@@ -64,6 +107,7 @@ var TOKEN_MANIFEST = [
64
107
  { name: "--wzl-curve-color", type: "color", group: "curve", defaultValue: "#5841b8", description: "Drawn data curves. Routes through the bright accent because accent-base is too dim on sunken surfaces.", hook: false },
65
108
  { name: "--wzl-accent", type: "color", group: "accent", defaultValue: "#2e1f7a", description: "", hook: false },
66
109
  { name: "--wzl-accent-hover", type: "color", group: "accent", defaultValue: "#5841b8", description: "", hook: false },
110
+ { name: "--wzl-secondary", type: "color", group: "secondary", defaultValue: "#dc9d15", description: "Honey amber in dark mode and teal in light, where a darkened amber reads as brown. A fill; use secondary-fg for text.", hook: false },
67
111
  { name: "--wzl-danger", type: "color", group: "status", defaultValue: "#d94a3f", description: "", hook: false },
68
112
  { name: "--wzl-warning", type: "color", group: "status", defaultValue: "#d99a3f", description: "", hook: false },
69
113
  { name: "--wzl-success", type: "color", group: "status", defaultValue: "#2ec27e", description: "", hook: false },
@@ -78,7 +122,7 @@ var TOKEN_MANIFEST = [
78
122
  { name: "--wzl-border-w", type: "dimension", group: "border", defaultValue: "1px", description: "", hook: false },
79
123
  { name: "--wzl-line-width", type: "dimension", group: "line", defaultValue: "2px", description: "Structural lines \u2014 gridlines, dividers, axes.", hook: false },
80
124
  { name: "--wzl-curve-width", type: "dimension", group: "curve", defaultValue: "3px", description: "Drawn data curves. Heavier than structural lines so data reads as primary content.", hook: false },
81
- { name: "--wzl-tb-height", type: "dimension", group: "tb", defaultValue: "28px", description: "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.", hook: false },
125
+ { name: "--wzl-tb-height", type: "dimension", group: "tb", defaultValue: "28px", description: "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.", hook: false },
82
126
  { name: "--wzl-control-h-xs", type: "dimension", group: "control", defaultValue: "18px", description: "Height of the smallest interactive control -- a stepper, a keycap, a swatch button in a dense row. The rank below control-h-sm.", hook: false },
83
127
  { name: "--wzl-control-h-sm", type: "dimension", group: "control", defaultValue: "20px", description: "Height of a control in a dense inspector -- a Properties field, a small Button. The rank below control-h, which sizes a standalone control.", hook: false },
84
128
  { name: "--wzl-control-h", type: "dimension", group: "control", defaultValue: "24px", description: "Height of an interactive control \u2014 button, input, select, segmented control. Distinct from tb-height, which sizes the strip a row of them sits in.", hook: false },
@@ -90,6 +134,11 @@ var TOKEN_MANIFEST = [
90
134
  { name: "--wzl-handle-size", type: "dimension", group: "handle", defaultValue: "9px", description: "Edge of a draggable handle on a plot or timeline \u2014 a keyframe diamond, a timeline key, an event mark. The default rank; -sm and -lg are the two deliberate departures from it.", hook: false },
91
135
  { name: "--wzl-handle-size-sm", type: "dimension", group: "handle", defaultValue: "7px", description: "A handle that is drawn but not draggable \u2014 a locked or pinned point. Smaller so it reads as inert next to a live one.", hook: false },
92
136
  { name: "--wzl-handle-size-lg", type: "dimension", group: "handle", defaultValue: "10px", description: "A handle that is a category of its own rather than one of a row \u2014 a curve's endpoint. Larger so it separates from the handles it sits in line with.", hook: false },
137
+ { name: "--wzl-checker-a", type: "color", group: "checker", defaultValue: "#25272c", description: "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).", hook: false },
138
+ { name: "--wzl-checker-b", type: "color", group: "checker", defaultValue: "#181a1e", description: "The other square of the transparency checker.", hook: false },
139
+ { name: "--wzl-checker-size", type: "dimension", group: "checker", defaultValue: "8px", description: "Edge of one repeat of the transparency checker: two squares by two.", hook: false },
140
+ { name: "--wzl-workspace-surface", type: "color", group: "workspace", defaultValue: "#0e0f12", description: "Ground of a canvas app's workspace \u2014 the area around the document page.", hook: false },
141
+ { name: "--wzl-workspace-line", type: "color", group: "workspace", defaultValue: "rgba(230, 231, 233, 0.1)", description: "Marks drawn over workspace-surface, such as its diagonal stripes, so the page reads as the thing on top.", hook: false },
93
142
  { name: "--wzl-field-pad-x", type: "dimension", group: "field", defaultValue: "8px", description: "Horizontal padding inside a boxed field. Pairs with --wzl-field-h, which is a container override and has no :root default.", hook: false },
94
143
  { name: "--wzl-glass-blur", type: "dimension", group: "glass", defaultValue: "3px", description: "Backdrop blur radius for frosted surfaces. Pairs with glass-tint.", hook: false },
95
144
  { name: "--wzl-font-size", type: "dimension", group: "font", defaultValue: "13px", description: "Controls and body text.", hook: false },
@@ -121,17 +170,27 @@ var TOKEN_MANIFEST = [
121
170
  { name: "--wzl-space-sm", type: "dimension", group: "space", defaultValue: "8px", description: "Alias for space-4. The t-shirt names name every other rung of the ladder.", hook: false },
122
171
  { name: "--wzl-space-md", type: "dimension", group: "space", defaultValue: "12px", description: "Alias for space-6. The t-shirt names name every other rung of the ladder.", hook: false },
123
172
  { name: "--wzl-space-lg", type: "dimension", group: "space", defaultValue: "16px", description: "Alias for space-8. The t-shirt names name every other rung of the ladder.", hook: false },
173
+ { name: "--wzl-disclosure-fill", type: "color", group: "disclosure", defaultValue: "var(--wzl-accent-fg)", description: "Fill of a Disclosure\u2019s fold mark.", hook: true },
124
174
  { name: "--wzl-disclosure-gap", type: "dimension", group: "disclosure", defaultValue: "4px", description: "Gap between a Disclosure\u2019s twisty and its label.", hook: true },
125
- { name: "--wzl-disclosure-target", type: "dimension", group: "disclosure", defaultValue: "20px", description: "Hit-target square of a Disclosure twisty, and of a labkit LayerList row\u2019s.", hook: true },
175
+ { name: "--wzl-disclosure-target", type: "dimension", group: "disclosure", defaultValue: "20px", description: "Hit-target square of a Disclosure twisty, and the twisty column of a LayerList row.", hook: true },
176
+ { name: "--wzl-input-surface", type: "color", group: "input", defaultValue: "var(--wzl-surface-sunken)", description: "Surface a text Input\u2019s frame sits on. Set it on any container whose own background is the default \u2014 a sunken rail or panel \u2014 where an unset field is the same color as what is behind it.", hook: true },
126
177
  { name: "--wzl-number-field-width", type: "dimension", group: "number", defaultValue: "9ch", description: "Width of a NumberField\u2019s input.", hook: true },
178
+ { name: "--wzl-params-label-align", type: "string", group: "params", defaultValue: "start", description: "Text alignment of row labels in PropertyPanel, Prefs and labkit\u2019s ControlPanel.", hook: true },
179
+ { name: "--wzl-params-label-case", type: "string", group: "params", defaultValue: "uppercase", description: "text-transform of every label and title in PropertyPanel, Prefs and labkit\u2019s ControlPanel.", hook: true },
180
+ { name: "--wzl-params-label-tracking", type: "dimension", group: "params", defaultValue: "var(--wzl-tracking-wide)", description: "Letter spacing of every label and title in PropertyPanel, Prefs and labkit\u2019s ControlPanel. Unset, rows take --wzl-tracking-wide and titles --wzl-tracking-wider.", hook: true },
181
+ { name: "--wzl-params-label-width", type: "dimension", group: "params", defaultValue: "auto", description: "Inline size of row labels in PropertyPanel, Prefs and labkit\u2019s ControlPanel.", hook: true },
127
182
  { name: "--wzl-prefs-column-width", type: "dimension", group: "prefs", defaultValue: "300px", description: "Width of the Prefs category column.", hook: true },
183
+ { name: "--wzl-prefs-rail-width", type: "dimension", group: "prefs", defaultValue: "216px", description: "Width of the Prefs navigation rail.", hook: true },
128
184
  { name: "--wzl-prop-number-width", type: "dimension", group: "prop", defaultValue: "9ch", description: "Width of a numeric field in the Properties panel.", hook: true },
129
185
  { name: "--wzl-prop-row-h", type: "dimension", group: "prop", defaultValue: "20px", description: "Floor under every Properties row, whatever control it holds. Unset, it is the panel\u2019s own field height, so it follows density \u2014 20px at the default one.", hook: true },
130
186
  { name: "--wzl-prop-text-width", type: "dimension", group: "prop", defaultValue: "16ch", description: "Width of a text field in the Properties panel.", hook: true },
131
- { name: "--wzl-property-readout-w", type: "dimension", group: "property", defaultValue: "2.8em", description: "Minimum width of a Properties row\u2019s value readout.", hook: true },
187
+ { name: "--wzl-property-readout-w", type: "dimension", group: "property", defaultValue: "calc(4.5ch + 2px)", description: "Width of a Properties row\u2019s value readout \u2014 four digits, so the controls beside a column of readouts end on one line. A range whose widest value needs more widens its own readout.", hook: true },
188
+ { name: "--wzl-select-border", type: "border", group: "select", defaultValue: "1px solid var(--wzl-border)", description: "Border of a Select\u2019s trigger. Unset, a boxed trigger draws --wzl-border and a bare one a transparent border of the same width.", hook: true },
189
+ { name: "--wzl-select-fg", type: "color", group: "select", defaultValue: "var(--wzl-fg)", description: "Text color of a Select\u2019s trigger.", hook: true },
132
190
  { name: "--wzl-swatch-size", type: "dimension", group: "swatch", defaultValue: "28px", description: "Minimum cell of a swatch grid \u2014 PatternPicker, and any panel laying swatches out the same way.", hook: true },
133
191
  { name: "--wzl-timeline-label-w", type: "dimension", group: "timeline", defaultValue: "120px", description: "Width of the Timeline\u2019s track-label gutter.", hook: true },
134
- { name: "--wzl-timeline-value-axis-w", type: "dimension", group: "timeline", defaultValue: "32px", description: "Width reserved for the Timeline\u2019s value axis.", hook: true }
192
+ { name: "--wzl-timeline-value-axis-w", type: "dimension", group: "timeline", defaultValue: "32px", description: "Width reserved for the Timeline\u2019s value axis.", hook: true },
193
+ { name: "--wzl-tree-indent", type: "dimension", group: "tree", defaultValue: "calc(var(--wzl-control-h-xs) + var(--wzl-space-2))", 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.", hook: true }
135
194
  ];
136
195
 
137
196
  // src/tokenPx.ts
@@ -176,29 +235,122 @@ function flattenTokens(doc) {
176
235
  }
177
236
 
178
237
  // src/loadDTCG.ts
238
+ var isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
239
+ function readLayer(src) {
240
+ const modes = isRecord(src.modes) ? src.modes : {};
241
+ return {
242
+ primitives: flattenTokens(isRecord(src.primitives) ? src.primitives : {}),
243
+ modes: Object.fromEntries(Object.entries(modes).map(([m, g]) => [m, flattenTokens(isRecord(g) ? g : {})]))
244
+ };
245
+ }
246
+ function readAxesExtension(raw) {
247
+ if (raw === void 0) return void 0;
248
+ if (!isRecord(raw) || !isRecord(raw.axes)) throw new Error(`DTCG "$extensions.${AXES_EXT}" needs an "axes" object`);
249
+ return {
250
+ axes: raw.axes,
251
+ varies: isRecord(raw.varies) ? raw.varies : {},
252
+ overrides: isRecord(raw.overrides) ? raw.overrides : {}
253
+ };
254
+ }
179
255
  function loadDTCG(doc) {
180
256
  if (typeof doc.name !== "string" || doc.name === "") {
181
257
  throw new Error('DTCG document needs a string "name"');
182
258
  }
183
259
  const base = doc.extends === void 0 ? weaselTheme : doc.extends;
184
- const primitives = flattenTokens(doc.primitives ?? {});
185
- const modeNames = Object.keys(doc.modes ?? {});
186
- const modes = Object.fromEntries(modeNames.map((m) => [m, flattenTokens(doc.modes[m])]));
187
- const tokens = { ...primitives };
188
- for (const name of new Set(modeNames.flatMap((m) => Object.keys(modes[m])))) {
260
+ const ext = readAxesExtension(doc.$extensions?.[AXES_EXT]);
261
+ const plain = readLayer(doc);
262
+ const overrides = Object.fromEntries(Object.entries(ext?.overrides ?? {}).map(([k, l]) => [k, readLayer(l)]));
263
+ const modeNames = [...new Set([plain, ...Object.values(overrides)].flatMap((l) => Object.keys(l.modes)))];
264
+ const tokenIn = (layer, name) => {
265
+ if (!modeNames.some((m) => layer.modes[m]?.[name])) return layer.primitives[name];
189
266
  const branch = { by: "mode" };
190
267
  for (const m of modeNames) {
191
- const t = modes[m][name] ?? primitives[name];
268
+ const t = layer.modes[m]?.[name] ?? layer.primitives[name];
192
269
  if (t) branch[m] = t;
193
270
  }
194
- tokens[name] = branch;
195
- }
271
+ return branch;
272
+ };
196
273
  const inherited = base ? themeAxes(base).mode?.default : void 0;
197
- const defaultMode = typeof doc.defaultMode === "string" ? doc.defaultMode : inherited ?? "dark";
198
- const axes = modeNames.length > 0 ? { mode: { default: defaultMode, values: Object.fromEntries(modeNames.map((m) => [m, {}])) } } : {};
274
+ const defaultMode = typeof doc.defaultMode === "string" ? doc.defaultMode : ext?.axes.mode?.default ?? inherited ?? "dark";
275
+ const modeAxis = {
276
+ default: defaultMode,
277
+ values: Object.fromEntries(modeNames.map((m) => [m, ext?.axes.mode?.values[m] ?? {}]))
278
+ };
279
+ const axes = {};
280
+ for (const [name, def] of Object.entries(ext?.axes ?? { mode: modeAxis })) {
281
+ if (name !== "mode") axes[name] = def;
282
+ else if (modeNames.length > 0) axes.mode = modeAxis;
283
+ }
284
+ if (modeNames.length > 0) axes.mode ??= modeAxis;
285
+ const all = mergeAxes(base ? themeAxes(base) : {}, axes);
286
+ const nest = (name, vary, combo) => {
287
+ if (vary.length === 0) {
288
+ const key = overrideKey(all, combo);
289
+ const layer = key === "" ? plain : overrides[key];
290
+ return layer && tokenIn(layer, name);
291
+ }
292
+ const [axis, ...rest] = vary;
293
+ const out = { by: axis };
294
+ let any = false;
295
+ for (const value of Object.keys(all[axis].values)) {
296
+ const v = nest(name, rest, { ...combo, [axis]: value });
297
+ if (v !== void 0) {
298
+ out[value] = v;
299
+ any = true;
300
+ }
301
+ }
302
+ return any ? out : void 0;
303
+ };
304
+ const tokens = {};
305
+ const names = /* @__PURE__ */ new Set([...Object.keys(plain.primitives), ...modeNames.flatMap((m) => Object.keys(plain.modes[m] ?? {}))]);
306
+ for (const name of Object.keys(ext?.varies ?? {})) names.add(name);
307
+ for (const name of names) {
308
+ const vary = (ext?.varies[name] ?? []).filter((a) => a in all);
309
+ const v = vary.length > 0 ? nest(name, vary, {}) : tokenIn(plain, name);
310
+ if (v !== void 0) tokens[name] = v;
311
+ }
199
312
  return { name: doc.name, extends: base, axes, tokens };
200
313
  }
201
314
 
202
- export { TOKEN_MANIFEST, loadDTCG, tokenPx };
315
+ // src/panel.ts
316
+ var STANCES = ["scope", "aside", "advanced", "debug", "danger", "notice", "important", "preview"];
317
+ var STANCE_SLOTS = [
318
+ { name: "surface", drives: "background" },
319
+ { name: "border-color", drives: "border-color" },
320
+ { name: "border-style", drives: "border-style" },
321
+ { name: "border-width", drives: "border-width" },
322
+ { name: "radius", drives: "border-radius" },
323
+ { name: "pad", drives: "padding" },
324
+ { name: "blur", drives: "backdrop-filter" },
325
+ { name: "tone-mix", drives: "how much of the tone mixes into the surface" },
326
+ { name: "tone", drives: "the tone a surface takes when it names none" },
327
+ // Only a surface that names its own tone recolors its controls.
328
+ { name: "accent", drives: "the accent the controls inside a surface with a tone take; unset, the tone" },
329
+ { name: "title-font", drives: "font-family" },
330
+ { name: "title-weight", drives: "font-weight" },
331
+ { name: "title-size", drives: "font-size" },
332
+ { name: "title-case", drives: "text-transform" },
333
+ { name: "title-tracking", drives: "letter-spacing" },
334
+ { name: "title-color", drives: "color" },
335
+ { name: "title-inset", drives: "the title\u2019s padding" }
336
+ ];
337
+ function stanceSlotNames() {
338
+ return STANCES.flatMap(
339
+ (stance) => STANCE_SLOTS.flatMap((slot) => [`--wzl-stance-${stance}-${slot.name}`, `--wzl-stance-${stance}-nested-${slot.name}`])
340
+ );
341
+ }
342
+ function resolveStanceSlots(tokens, base, { stance, nested, stanced } = {}) {
343
+ const out = { ...base };
344
+ if (stance === void 0) return out;
345
+ for (const slot of Object.keys(base)) {
346
+ const own = tokens[`--wzl-stance-${stance}-${slot}`];
347
+ const inner = nested ? tokens[`--wzl-stance-${stance}-nested-${slot}`] : void 0;
348
+ const fallback = slot === "tone" ? base.surface ?? base[slot] : stanced?.[slot] ?? base[slot];
349
+ out[slot] = inner ?? own ?? fallback;
350
+ }
351
+ return out;
352
+ }
353
+
354
+ export { STANCES, STANCE_SLOTS, TOKEN_MANIFEST, loadDTCG, resolveStanceSlots, stanceSlotNames, tokenPx };
203
355
  //# sourceMappingURL=index.js.map
204
356
  //# sourceMappingURL=index.js.map