@weasel-js/theme 1.6.1 → 1.7.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/engine.d.ts CHANGED
@@ -1,17 +1,21 @@
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-DLdTdFWs.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-DLdTdFWs.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-ChUj0lSz.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-ChUj0lSz.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. */
8
9
  declare function hexToRgb(hex: string): [number, number, number];
10
+ /** OKLCH (lightness 0–1, chroma, hue in degrees) to `#rrggbb`. Chroma past the gamut is clipped at constant lightness. */
9
11
  declare const toHex: typeof oklchDegToHex;
12
+ /** `#rrggbb` to OKLCH, hue in 0–360. */
10
13
  declare const toLch: (hex: string) => Lch;
11
14
  /** The most chroma this hue can carry at this lightness, inside sRGB. */
12
15
  declare function chromaCap(L: number, H: number): number;
13
16
  /** WCAG relative luminance. */
14
17
  declare function luminance(hex: string): number;
18
+ /** WCAG contrast ratio between two hex colors, 1–21, in either order. */
15
19
  declare function contrast(a: string, b: string): number;
16
20
  /** Shortest angular distance between two hues, in degrees. */
17
21
  declare function hueGap(a: number, b: number): number;
@@ -36,6 +40,7 @@ declare function toLab(hex: string): [number, number, number];
36
40
  * 0.25 is a real color, 0.5 is unmistakable.
37
41
  */
38
42
  declare const CHROMA_WEIGHT = 3;
43
+ /** Perceptual distance between two hex colors: OKLab with chroma weighted by {@link CHROMA_WEIGHT}. */
39
44
  declare function deltaE(a: string, b: string): number;
40
45
  /** The most chroma this hue can carry at this lightness, as a hex. */
41
46
  declare function vividAt(L: number, H: number): string;
@@ -98,13 +103,17 @@ interface Constraints {
98
103
  readonly anchors: readonly Anchor[];
99
104
  readonly order: 'hue' | 'farthest';
100
105
  }
106
+ /** One color of a generated {@link Palette}. */
101
107
  interface Swatch {
102
108
  readonly name: string;
103
109
  readonly hex: string;
104
110
  readonly lch: Lch;
111
+ /** Came from one of the constraints' anchors. */
105
112
  readonly anchored: boolean;
113
+ /** WCAG contrast against the constraints' `surface`. */
106
114
  readonly contrast: number;
107
115
  }
116
+ /** Measurements of a generated palette as a whole: the minimums are over every swatch, or every pair. */
108
117
  interface Stats {
109
118
  readonly meanChroma: number;
110
119
  readonly chromaSpread: number;
@@ -116,6 +125,7 @@ interface Stats {
116
125
  readonly minSurfaceDistance: number;
117
126
  readonly minDistance: number;
118
127
  }
128
+ /** What {@link generate} returns. */
119
129
  interface Palette {
120
130
  readonly swatches: readonly Swatch[];
121
131
  readonly stats: Stats;
@@ -123,6 +133,7 @@ interface Palette {
123
133
  * best unconstrained attempt, so the lab still has something to draw. */
124
134
  readonly feasible: boolean;
125
135
  }
136
+ /** A plain color name for a hue in degrees: `red`, `teal`, `violet`. */
126
137
  declare function hueName(H: number): string;
127
138
  /**
128
139
  * Search hue positions that maximize mean chroma subject to the gates.
@@ -133,28 +144,36 @@ declare function hueName(H: number): string;
133
144
  */
134
145
  /** The share-of-even floor, in degrees, for a set of this size. */
135
146
  declare function floorDegrees(c: Pick<Constraints, 'hueFloor' | 'count'>): number;
147
+ /**
148
+ * A categorical palette of `count` swatches, anchors included, satisfying the gates. When no hue arrangement
149
+ * satisfies them the result is still a full palette, with `feasible` false.
150
+ */
136
151
  declare function generate(c: Constraints): Palette;
137
152
  /** What the lab opens with: the set this palette work landed on. */
138
153
  declare const DEFAULT_CONSTRAINTS: Constraints;
154
+ /** The color an anchor will actually contribute, for a swatch beside its controls. */
155
+ declare function toHexPreview(a: Pick<Anchor, 'hue' | 'lightness' | 'chroma'>): string;
139
156
  /**
140
157
  * An anchor taken from an existing color — a brand hex, or a color lifted from
141
158
  * somewhere else in the theme. Lightness comes along with the hue, which is the
142
159
  * point: the reason to pin a color is usually that the lightness law would not
143
- * have chosen its lightness.
160
+ * have chosen its lightness. `name` defaults to the hue's {@link hueName}.
144
161
  */
145
- /** The color an anchor will actually contribute, for a swatch beside its controls. */
146
- declare function toHexPreview(a: Pick<Anchor, 'hue' | 'lightness' | 'chroma'>): string;
147
162
  declare function anchorFromHex(hex: string, name?: string): Anchor;
148
163
 
164
+ /** The axes one token's value can change with. */
149
165
  interface AxisDependency {
150
166
  /** Axes this token's own entry varies on. */
151
167
  readonly own: readonly string[];
152
168
  /** `own` plus everything reachable through references and rule inputs. */
153
169
  readonly all: readonly string[];
154
170
  }
171
+ /** Every token of the definition, `extends` chain included, mapped to the axes it depends on, in axis declaration order. */
155
172
  declare function axisDependencies(definition: ThemeDefinition, lookup?: Lookup): Record<string, AxisDependency>;
156
173
 
174
+ /** The definition layer that produced a token. */
157
175
  type Layer = 'ramps' | 'scales' | 'semantics' | 'components' | 'pins';
176
+ /** Where one derived token came from. */
158
177
  interface Provenance {
159
178
  readonly layer: Layer;
160
179
  /** `lightness`, `categorical`, `linear`, `geometric`, `step`, `offset`, `contrast`, `ref`, `value`. */
@@ -164,6 +183,7 @@ interface Provenance {
164
183
  /** What the rule alone produced, when `pinned`. */
165
184
  readonly generated?: RawToken;
166
185
  }
186
+ /** A problem `derive` found. Every one is reported, never thrown; the tokens still come back without what failed. */
167
187
  type Issue = {
168
188
  readonly kind: 'missing-axis-value';
169
189
  readonly path: string;
@@ -194,6 +214,7 @@ type Issue = {
194
214
  readonly path: string;
195
215
  readonly message: string;
196
216
  };
217
+ /** What `derive` produces for one selection. */
197
218
  interface DeriveResult {
198
219
  /** In layer order, then definition order within a layer. */
199
220
  readonly tokens: FlatTokens;
@@ -204,6 +225,7 @@ interface DeriveResult {
204
225
  /** Derive every token of `definition` for one selection. Unmet rules are reported in `issues`; cycles and dangling references throw. */
205
226
  declare function derive(definition: ThemeDefinition, selection?: Selection, lookup?: Lookup): DeriveResult;
206
227
 
228
+ /** A lightness ramp with every `by` and seed already settled. See {@link lightnessRamp}. */
207
229
  interface LightnessParams {
208
230
  readonly steps: readonly string[];
209
231
  readonly lightness: readonly [number, number];
@@ -224,19 +246,29 @@ interface LightnessParams {
224
246
  * consecutive anchors, hue along the shorter arc; steps before the first anchor or after the last take that anchor's.
225
247
  */
226
248
  declare function lightnessRamp(p: LightnessParams): Record<string, string>;
249
+ /**
250
+ * Step name → hex from the palette generator, one swatch per step in step order. `feasible` is false when no palette
251
+ * met the gates; the colors are then its best unconstrained attempt.
252
+ */
227
253
  declare function categoricalRamp(steps: readonly string[], gates: Partial<Constraints>, anchors: readonly Anchor[]): {
228
254
  colors: Record<string, string>;
229
255
  feasible: boolean;
230
256
  };
231
257
 
258
+ /** A scale's base and exactly one of `step`, `ratio` or `factors`. */
232
259
  interface ScaleParams {
233
260
  readonly base: number;
234
261
  readonly step?: number;
235
262
  readonly ratio?: number;
236
263
  readonly factors?: readonly number[];
237
264
  }
265
+ /**
266
+ * Step name → `<n>px`, rounded to whole pixels. Throws unless exactly one rule is given, or when `factors` has a
267
+ * length other than `steps`'.
268
+ */
238
269
  declare function scale(steps: readonly string[], p: ScaleParams): Record<string, string>;
239
270
 
271
+ /** One theme to write as CSS: its baked tokens and the axes each token depends on. */
240
272
  interface EmitInput {
241
273
  readonly baked: BakedTheme;
242
274
  readonly deps: Readonly<Record<string, AxisDependency>>;
@@ -245,6 +277,10 @@ interface EmitInput {
245
277
  }
246
278
  /** A reference becomes `var()` (or `color-mix()` with an alpha); a literal is resolved. */
247
279
  declare function cssValue(name: string, token: RawToken): string;
280
+ /**
281
+ * The `tokens.css` text for a set of themes. Each non-default theme is written as its difference from the default,
282
+ * scoped to `[data-wzl-theme]`. Throws unless exactly one theme is the default.
283
+ */
248
284
  declare function emitCss(themes: readonly EmitInput[]): string;
249
285
 
250
286
  /** The `$extensions` key on a DTCG export's root that carries every axis besides mode. */
@@ -272,6 +308,7 @@ interface DtcgAxesExtension {
272
308
  type Group = Record<string, unknown> & {
273
309
  $type: string;
274
310
  };
311
+ /** A DTCG document as {@link toDTCG} writes it. */
275
312
  interface DtcgExport {
276
313
  readonly name: string;
277
314
  readonly defaultMode?: string;
@@ -295,17 +332,21 @@ interface DtcgExport {
295
332
  */
296
333
  declare function toDTCG(theme: Theme): DtcgExport;
297
334
 
335
+ /** The `manifest.ts` source: `TOKEN_MANIFEST` for this theme at its default selection, then every override hook. */
298
336
  declare function emitManifest({ baked }: EmitInput): string;
299
337
 
338
+ /** One theme to write into `themes.ts`: its definition and what it bakes to. */
300
339
  interface ThemesInput {
301
340
  readonly definition: ThemeDefinition;
302
341
  readonly baked: BakedTheme;
303
342
  }
343
+ /** The `themes.ts` source: every theme's resolved tokens at every selection, plus the definitions and baked themes. */
304
344
  declare function emitThemes(themes: readonly ThemesInput[]): string;
305
345
 
306
346
  /** Every step name a ramp or scale entry declares, across every `by` branch of the entry and of its `steps`, first seen first. */
307
347
  declare function declaredSteps(entry: unknown): string[];
308
348
 
349
+ /** The files {@link generateTokens} produces, or every derive issue that stopped it. */
309
350
  type GeneratedTokens = {
310
351
  readonly ok: true;
311
352
  readonly files: {
@@ -329,10 +370,15 @@ interface StoredTheme {
329
370
  readonly emits: boolean;
330
371
  readonly definition: ThemeDefinition;
331
372
  }
373
+ /** A derive issue and the selection it occurred at. */
332
374
  interface IssueReport {
333
375
  readonly selection: Selection;
334
376
  readonly issue: Issue;
335
377
  }
378
+ /**
379
+ * The outcome of a save. `conflict` means the file changed since `baseHash`, and carries its current hash (null when
380
+ * it does not exist); `invalid` means the definition was refused and nothing was written.
381
+ */
336
382
  type PutResult = {
337
383
  readonly status: 'saved';
338
384
  readonly hash: string;
@@ -349,6 +395,7 @@ type PutResult = {
349
395
  };
350
396
  /** Record order is emission order, so keys are never sorted. */
351
397
  declare const serializeDefinition: (definition: ThemeDefinition) => string;
398
+ /** Reads and writes theme definition files. `put` sends the hash it last read, or null to create a new file. */
352
399
  interface ThemeApi {
353
400
  list(): Promise<StoredTheme[]>;
354
401
  get(name: string): Promise<StoredTheme>;
package/dist/engine.js CHANGED
@@ -1,6 +1,6 @@
1
- import { overrideKey, AXES_EXT, ALPHA_EXT } from './chunk-EINHFDWI.js';
2
- import { mergeAxes, toLch, toHex, generate, DEFAULT_CONSTRAINTS, fullSelection, pick, enumerateSelections, resolveTokens, pickAll, themeAxes, selectionKey, isByAxis, contrast } from './chunk-C3S4A65R.js';
3
- export { CHROMA_WEIGHT, DEFAULT_CONSTRAINTS, anchorFromHex, chromaCap, contrast, deltaE, floorDegrees, generate, hexToRgb, hueGap, hueName, luminance, toHex, toHexPreview, toLab, toLch, vividAt } from './chunk-C3S4A65R.js';
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-AN5JVL2S.js';
3
+ export { CHROMA_WEIGHT, DEFAULT_CONSTRAINTS, anchorFromHex, chromaCap, contrast, deltaE, floorDegrees, generate, hexToRgb, hueGap, hueName, luminance, toHex, toHexPreview, toLab, toLch, vividAt } from './chunk-AN5JVL2S.js';
4
4
 
5
5
  // src/engine/steps.ts
6
6
  var stepList = (x) => Array.isArray(x) ? [...new Set(x.filter((s) => typeof s === "string"))] : [];
@@ -1249,6 +1249,12 @@ function toDTCG(theme) {
1249
1249
 
1250
1250
  // src/hooks.ts
1251
1251
  var TOKEN_HOOKS = [
1252
+ {
1253
+ name: "detail-figure-min-width",
1254
+ type: "dimension",
1255
+ value: "8ch",
1256
+ description: 'Least width of a value cell in a `values="figures"` DetailList.'
1257
+ },
1252
1258
  {
1253
1259
  name: "disclosure-gap",
1254
1260
  type: "dimension",
@@ -1271,7 +1277,7 @@ var TOKEN_HOOKS = [
1271
1277
  name: "input-surface",
1272
1278
  type: "color",
1273
1279
  value: "var(--wzl-surface-sunken)",
1274
- 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."
1280
+ description: "Surface a field\u2019s frame sits on \u2014 Input, NumberField, ComboBox, Select, MenuButton, ListEditor and the property rows. 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."
1275
1281
  },
1276
1282
  {
1277
1283
  name: "number-field-width",