@tenphi/glaze 0.11.1 → 0.13.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/index.d.cts CHANGED
@@ -26,6 +26,30 @@ interface FindLightnessForContrastOptions {
26
26
  epsilon?: number;
27
27
  /** Maximum binary-search iterations per branch. Default: 14. */
28
28
  maxIterations?: number;
29
+ /**
30
+ * Preferred search direction before auto-flip is considered.
31
+ *
32
+ * Theme resolution sets this from the requested lightness relative to
33
+ * the base color so `autoFlip: false` preserves the authored direction.
34
+ * When omitted, the solver falls back to the side whose extreme has
35
+ * higher contrast against the base.
36
+ */
37
+ initialDirection?: 'lighter' | 'darker';
38
+ /**
39
+ * Auto-flip lightness direction when contrast can't be met.
40
+ *
41
+ * When `true`, the solver searches the initial direction first. If that side
42
+ * doesn't reach the target, it tries the opposite direction and
43
+ * uses it when it passes. If neither side passes, it returns the
44
+ * extreme lightness of the initial direction.
45
+ *
46
+ * When `false`, only the initial direction is considered. If it
47
+ * doesn't reach the target, the result is pinned to the initial
48
+ * direction's extreme — never to the original preferred lightness.
49
+ *
50
+ * Default: false.
51
+ */
52
+ flip?: boolean;
29
53
  }
30
54
  interface FindLightnessForContrastResult {
31
55
  /** Chosen lightness in 0–1. */
@@ -36,6 +60,12 @@ interface FindLightnessForContrastResult {
36
60
  met: boolean;
37
61
  /** Which branch was selected. */
38
62
  branch: 'lighter' | 'darker' | 'preferred';
63
+ /**
64
+ * Whether the result was auto-flipped to the opposite direction.
65
+ * Only set when the initial direction failed and the opposite
66
+ * direction satisfied the target.
67
+ */
68
+ flipped?: boolean;
39
69
  }
40
70
  declare function resolveMinContrast(value: MinContrast$1): number;
41
71
  /**
@@ -62,6 +92,22 @@ interface FindValueForMixContrastOptions {
62
92
  epsilon?: number;
63
93
  /** Maximum binary-search iterations per branch. Default: 20. */
64
94
  maxIterations?: number;
95
+ /**
96
+ * Auto-flip mix direction when contrast can't be met.
97
+ *
98
+ * When `true`, the solver searches the initial direction first
99
+ * (the side whose extreme has higher contrast against the base).
100
+ * If that side doesn't reach the target, it tries the opposite
101
+ * direction and uses it when it passes. If neither side passes,
102
+ * it returns the extreme mix value of the initial direction.
103
+ *
104
+ * When `false`, only the initial direction is considered. If it
105
+ * doesn't reach the target, the result is pinned to the initial
106
+ * direction's extreme — never to the original preferred value.
107
+ *
108
+ * Default: false.
109
+ */
110
+ flip?: boolean;
65
111
  }
66
112
  interface FindValueForMixContrastResult {
67
113
  /** Chosen mix parameter (0–1). */
@@ -70,6 +116,12 @@ interface FindValueForMixContrastResult {
70
116
  contrast: number;
71
117
  /** Whether the target was reached. */
72
118
  met: boolean;
119
+ /**
120
+ * Whether the result was auto-flipped to the opposite direction.
121
+ * Only set when the initial direction failed and the opposite
122
+ * direction satisfied the target.
123
+ */
124
+ flipped?: boolean;
73
125
  }
74
126
  /**
75
127
  * Find the mix parameter (ratio or opacity) that satisfies a WCAG 2 contrast
@@ -104,6 +156,18 @@ interface OkhslColor {
104
156
  s: number;
105
157
  l: number;
106
158
  }
159
+ /** sRGB components in 0–255 (value-shorthand object form). */
160
+ interface RgbColor {
161
+ r: number;
162
+ g: number;
163
+ b: number;
164
+ }
165
+ /** OKLCh components matching CSS `oklch(L C H)` (L/C: 0–1, H: degrees). */
166
+ interface OklchColor {
167
+ l: number;
168
+ c: number;
169
+ h: number;
170
+ }
107
171
  interface RegularColorDef {
108
172
  /**
109
173
  * Lightness value (0–100).
@@ -250,11 +314,16 @@ interface ResolvedColor {
250
314
  /** Adaptation mode. Present only for regular colors, omitted for shadows. */
251
315
  mode?: AdaptationMode;
252
316
  }
317
+ /**
318
+ * Lightness window value. A `[lo, hi]` tuple (0–100) or `false` to disable
319
+ * clamping entirely (equivalent to `[0, 100]`).
320
+ */
321
+ type LightnessWindow = false | [number, number];
253
322
  interface GlazeConfig {
254
- /** Light scheme lightness window [lo, hi]. Default: [10, 100]. */
255
- lightLightness?: [number, number];
256
- /** Dark scheme lightness window [lo, hi]. Default: [15, 95]. */
257
- darkLightness?: [number, number];
323
+ /** Light scheme lightness window [lo, hi]. Default: [10, 100]. Pass `false` to disable clamping. */
324
+ lightLightness?: LightnessWindow;
325
+ /** Dark scheme lightness window [lo, hi]. Default: [15, 95]. Pass `false` to disable clamping. */
326
+ darkLightness?: LightnessWindow;
258
327
  /** Saturation reduction factor for dark scheme (0–1). Default: 0.1. */
259
328
  darkDesaturation?: number;
260
329
  /**
@@ -273,10 +342,25 @@ interface GlazeConfig {
273
342
  modes?: GlazeOutputModes;
274
343
  /** Default tuning for all shadow colors. Per-color tuning merges field-by-field. */
275
344
  shadowTuning?: ShadowTuning;
345
+ /**
346
+ * Automatically flip lightness direction when contrast can't be met.
347
+ *
348
+ * When enabled (default `true`), the solver searches the requested
349
+ * lightness direction first. If that direction can't reach the target,
350
+ * it tries the opposite direction and uses it when it passes. If neither
351
+ * side passes, the lightness is pinned to the requested-direction
352
+ * extreme and a warning is emitted.
353
+ *
354
+ * Set to `false` for strict "no flip" behavior. The opposite
355
+ * direction is never considered: if the requested direction can't
356
+ * meet the target, the lightness is pinned to its extreme (never
357
+ * falls back to the originally requested lightness).
358
+ */
359
+ autoFlip?: boolean;
276
360
  }
277
361
  interface GlazeConfigResolved {
278
- lightLightness: [number, number];
279
- darkLightness: [number, number];
362
+ lightLightness: LightnessWindow;
363
+ darkLightness: LightnessWindow;
280
364
  darkDesaturation: number;
281
365
  darkCurve: HCPair<number>;
282
366
  states: {
@@ -285,20 +369,47 @@ interface GlazeConfigResolved {
285
369
  };
286
370
  modes: Required<GlazeOutputModes>;
287
371
  shadowTuning?: ShadowTuning;
372
+ autoFlip: boolean;
373
+ }
374
+ /**
375
+ * Per-instance config override for `glaze.color()` and `glaze()` themes.
376
+ * Fields that are set take priority over the live global config. Fields
377
+ * that are omitted fall through to the live global at resolve time.
378
+ *
379
+ * `false` for a lightness window disables clamping (equivalent to `[0, 100]`).
380
+ */
381
+ interface GlazeConfigOverride {
382
+ /** Light scheme lightness window, or `false` to disable clamping. */
383
+ lightLightness?: LightnessWindow;
384
+ /** Dark scheme lightness window, or `false` to disable clamping. */
385
+ darkLightness?: LightnessWindow;
386
+ /** Saturation reduction factor for dark scheme (0–1). */
387
+ darkDesaturation?: number;
388
+ /** Möbius beta for dark auto-inversion. Accepts [normal, hc] pair. */
389
+ darkCurve?: HCPair<number>;
390
+ /** Whether to auto-flip lightness when contrast can't be met. */
391
+ autoFlip?: boolean;
392
+ /**
393
+ * Shadow tuning defaults. Only meaningful for themes; harmless on
394
+ * standalone color tokens.
395
+ */
396
+ shadowTuning?: ShadowTuning;
288
397
  }
289
398
  /** Serialized theme configuration (no resolved values). */
290
399
  interface GlazeThemeExport {
291
400
  hue: number;
292
401
  saturation: number;
293
402
  colors: ColorMap;
403
+ /** Per-theme config override, if any. */
404
+ config?: GlazeConfigOverride;
294
405
  }
295
406
  /** Input for `glaze.shadow()` standalone factory. */
296
407
  interface GlazeShadowInput {
297
408
  /**
298
409
  * Background color — accepts any `GlazeColorValue` form: hex
299
410
  * (`#rgb` / `#rrggbb` / `#rrggbbaa`), `rgb()` / `hsl()` / `okhsl()`
300
- * / `oklch()` strings, an `OkhslColor` object, or an `[r, g, b]`
301
- * (0–255) tuple. Alpha components are dropped with a warning.
411
+ * / `oklch()` strings, or literal objects (`{ r, g, b }`, `{ h, s, l }`,
412
+ * `{ l, c, h }`). Alpha components are dropped with a warning.
302
413
  */
303
414
  bg: GlazeColorValue;
304
415
  /**
@@ -349,15 +460,14 @@ interface GlazeColorInput {
349
460
  * `rgb()`, `hsl()`, `okhsl()`, `oklch()` (alpha components also dropped
350
461
  * with a warning).
351
462
  *
352
- * The OKHSL object form `{ h, s, l }` matches Glaze's native shape
353
- * (h: 0–360, s/l: 0–1). Passing 0–100 values for `s`/`l` throws with
354
- * a hint to use the structured `{ hue, saturation, lightness }` form.
355
- *
356
- * The tuple form is `[r, g, b]` in 0–255, matching `glaze.fromRgb`'s
357
- * range. Out-of-range or non-finite components throw.
463
+ * Literal object forms:
464
+ * - `{ h, s, l }` — OKHSL (h: 0–360, s/l: 0–1). Passing 0–100 for `s`/`l`
465
+ * throws with a hint to use the structured form.
466
+ * - `{ r, g, b }` — sRGB 0–255.
467
+ * - `{ l, c, h }` OKLCh (L/C: 0–1, H: degrees), same as `oklch()` strings.
358
468
  */
359
- type GlazeColorValue = string | OkhslColor | readonly [number, number, number];
360
- /** Optional overrides for `glaze.color(value, overrides?)`. */
469
+ type GlazeColorValue = string | OkhslColor | RgbColor | OklchColor;
470
+ /** Color overrides for the `from` and value-shorthand inputs. */
361
471
  interface GlazeColorOverrides {
362
472
  /**
363
473
  * Override hue. Number is absolute (0–360); `'+N'`/`'-N'` is relative
@@ -378,11 +488,11 @@ interface GlazeColorOverrides {
378
488
  /**
379
489
  * Adaptation mode. Defaults to `'auto'` for every input form, so
380
490
  * colors automatically adapt between light and dark like an ordinary
381
- * theme color. The default *scaling* snapshot differs by input form:
382
- * string inputs preserve their light lightness and extend the dark
383
- * window to `[lo, 100]` (`#000` `#fff` flip), while `OkhslColor`
384
- * and `[r, g, b]` tuple inputs snapshot the full `globalConfig.
385
- * lightLightness` / `globalConfig.darkLightness` windows.
491
+ * theme color. All value-shorthand inputs (strings and literal objects)
492
+ * preserve light lightness (`lightLightness: false`) and snapshot
493
+ * `globalConfig.darkLightness` on the dark side. Only the structured
494
+ * `{ hue, saturation, lightness }` form also snapshots
495
+ * `globalConfig.lightLightness`.
386
496
  *
387
497
  * Pass `'fixed'` explicitly to opt back into the legacy linear, non-
388
498
  * inverting mapping; pass `'static'` to pin the same lightness
@@ -398,7 +508,7 @@ interface GlazeColorOverrides {
398
508
  /**
399
509
  * Optional dependency on another color. Accepts either a
400
510
  * `GlazeColorToken` (returned by another `glaze.color()`) or a raw
401
- * `GlazeColorValue` (hex / `rgb()` / `OkhslColor` / `[r, g, b]`),
511
+ * `GlazeColorValue` (hex / CSS strings / `{ r, g, b }` / `{ h, s, l }` / …),
402
512
  * which is automatically wrapped in `glaze.color(value)`.
403
513
  *
404
514
  * When set:
@@ -408,6 +518,11 @@ interface GlazeColorOverrides {
408
518
  * lightness per-scheme (matches theme behavior for dependent colors).
409
519
  * - Relative `hue: '+N'` / `'-N'` still anchors to the seed (the
410
520
  * value passed to `glaze.color()`), not the base.
521
+ * - When the base was created via the structured form (with explicit
522
+ * `hue`/`saturation`/`lightness`), it is resolved at full range
523
+ * (`lightLightness: false`) for the linking math — ensuring the
524
+ * contrast/lightness anchor matches the input lightness, not the
525
+ * windowed output. The base's own `.resolve()` output is unaffected.
411
526
  *
412
527
  * The base token's `.resolve()` is called lazily on first resolve and
413
528
  * its result is captured by reference; later mutations to the base's
@@ -428,46 +543,17 @@ interface GlazeColorOverrides {
428
543
  name?: string;
429
544
  }
430
545
  /**
431
- * Per-call lightness-window overrides for `glaze.color()`. Mirrors
432
- * the field names from `GlazeConfig`.
433
- *
434
- * Defaults for `glaze.color()` vary by input form, and both fields are
435
- * snapshotted from `globalConfig` at color-creation time so later
436
- * `glaze.configure()` calls don't retroactively change already-created
437
- * tokens (and `token.export()` round-trips byte-for-byte):
546
+ * Object input for `glaze.color()` that carries a raw color value plus
547
+ * optional color overrides in the same object.
438
548
  *
439
- * - **String inputs** (`'#1a1a1a'`, `'rgb(...)'`, `'okhsl(...)'`, ...):
440
- * - `lightLightness: false` preserve input exactly.
441
- * - `darkLightness: [globalConfig.darkLightness[0], 100]` extended
442
- * dark window so the auto-mode dark variant can Möbius-invert all
443
- * the way up to white.
444
- *
445
- * - **`OkhslColor` / `[r, g, b]` tuple / structured inputs**:
446
- * - `lightLightness: globalConfig.lightLightness` — same light window
447
- * theme colors use, snapshotted at create time.
448
- * - `darkLightness: globalConfig.darkLightness` — same dark window
449
- * theme colors use, snapshotted at create time.
450
- *
451
- * Passing this object replaces both fields at once. To keep one
452
- * field's default while overriding the other, restate the default
453
- * explicitly.
549
+ * ```ts
550
+ * glaze.color({ from: '#1a1a2e', base: bg, contrast: 'AA' })
551
+ * glaze.color({ from: { r: 38, g: 252, b: 178 }, lightness: '+10' })
552
+ * ```
454
553
  */
455
- interface GlazeColorScaling {
456
- /**
457
- * Light-mode lightness window. Snapshotted from `globalConfig` at
458
- * create time: `false` (preserve input) for string inputs, plain
459
- * `globalConfig.lightLightness` for object / tuple / structured
460
- * inputs. Pass `false` to preserve input lightness in light mode.
461
- */
462
- lightLightness?: false | [number, number];
463
- /**
464
- * Dark-mode lightness window. Snapshotted from `globalConfig` at
465
- * create time: extended `[globalConfig.darkLightness[0], 100]` for
466
- * string inputs, plain `globalConfig.darkLightness` for object /
467
- * tuple / structured inputs. Pass `false` to preserve input
468
- * lightness in dark mode too.
469
- */
470
- darkLightness?: false | [number, number];
554
+ interface GlazeFromInput extends GlazeColorOverrides {
555
+ /** The source color value. Accepts the same forms as a bare `GlazeColorValue`. */
556
+ from: GlazeColorValue;
471
557
  }
472
558
  /** Options for `GlazeColorToken.css()`. */
473
559
  interface GlazeColorCssOptions {
@@ -503,7 +589,7 @@ interface GlazeColorToken {
503
589
  css(options: GlazeColorCssOptions): GlazeCssResult;
504
590
  /**
505
591
  * Serialize the token as a JSON-safe object. Captures the original
506
- * input value, overrides, and scaling so it can be rehydrated via
592
+ * input value, overrides, and config so it can be rehydrated via
507
593
  * `glaze.colorFrom(...)`. `base` is recursively serialized.
508
594
  */
509
595
  export(): GlazeColorTokenExport;
@@ -515,8 +601,8 @@ interface GlazeColorToken {
515
601
  interface GlazeColorTokenExport {
516
602
  /**
517
603
  * Discriminator for the source overload that created the token.
518
- * - `'value'`: created via `glaze.color(value, overrides?, scaling?)`.
519
- * - `'structured'`: created via `glaze.color({ hue, saturation, ... }, scaling?)`.
604
+ * - `'value'`: created via `glaze.color(value)` or `glaze.color({ from, ...overrides })`.
605
+ * - `'structured'`: created via `glaze.color({ hue, saturation, ... })`.
520
606
  */
521
607
  form: 'value' | 'structured';
522
608
  /** Original input. For `form: 'value'` this is the raw `GlazeColorValue`; for `form: 'structured'` this is the structured input. */
@@ -526,8 +612,14 @@ interface GlazeColorTokenExport {
526
612
  * serialized. Only present for `form: 'value'`.
527
613
  */
528
614
  overrides?: GlazeColorOverridesExport;
529
- /** Lightness scaling override, if any. */
530
- scaling?: GlazeColorScaling;
615
+ /**
616
+ * Effective config snapshot at creation time — captures the merged
617
+ * result of the global config + any per-call override at the moment
618
+ * the token was created. Only fields that differ from their
619
+ * post-merge defaults are present. Used by `glaze.colorFrom()` to
620
+ * reproduce deterministic behavior across `configure()` calls.
621
+ */
622
+ config?: GlazeConfigOverride;
531
623
  }
532
624
  /**
533
625
  * Serializable shape of a structured `glaze.color({...})` input.
@@ -610,6 +702,8 @@ interface GlazeExtendOptions {
610
702
  hue?: number;
611
703
  saturation?: number;
612
704
  colors?: ColorMap;
705
+ /** Config override for the child theme. Merged with the parent's override. */
706
+ config?: GlazeConfigOverride;
613
707
  }
614
708
  interface GlazeTokenOptions {
615
709
  /** Prefix mode. `true` uses "<themeName>-", or provide a custom map. */
@@ -708,25 +802,30 @@ type PaletteInput = Record<string, GlazeTheme>;
708
802
  /**
709
803
  * Create a single-hue glaze theme.
710
804
  *
805
+ * An optional `config` override can be supplied to customize the resolve
806
+ * behavior for this theme (lightness windows, dark curve, etc.). The
807
+ * override is **merged over the live global config at resolve time** —
808
+ * the theme still reacts to later `configure()` calls for fields it
809
+ * didn't override.
810
+ *
711
811
  * @example
712
812
  * ```ts
713
- * const primary = glaze({ hue: 280, saturation: 80 });
714
- * // or shorthand:
715
813
  * const primary = glaze(280, 80);
814
+ * // or shorthand:
815
+ * const primary = glaze({ hue: 280, saturation: 80 });
816
+ * // with config override:
817
+ * const raw = glaze(280, 80, { lightLightness: false });
716
818
  * ```
717
819
  */
718
820
  declare function glaze(hueOrOptions: number | {
719
821
  hue: number;
720
822
  saturation: number;
721
- }, saturation?: number): GlazeTheme;
823
+ }, saturation?: number, config?: GlazeConfigOverride): GlazeTheme;
722
824
  declare namespace glaze {
723
825
  var configure: (config: GlazeConfig) => void;
724
826
  var palette: (themes: PaletteInput, options?: GlazePaletteOptions) => GlazePalette;
725
827
  var from: (data: GlazeThemeExport) => GlazeTheme;
726
- var color: {
727
- (input: GlazeColorInput, scaling?: GlazeColorScaling): GlazeColorToken;
728
- (value: GlazeColorValue, overrides?: GlazeColorOverrides, scaling?: GlazeColorScaling): GlazeColorToken;
729
- };
828
+ var color: (input: GlazeFromInput | GlazeColorInput | GlazeColorValue, config?: GlazeConfigOverride) => GlazeColorToken;
730
829
  var shadow: (input: GlazeShadowInput) => ResolvedColorVariant;
731
830
  var format: (variant: ResolvedColorVariant, colorFormat?: GlazeColorFormat) => string;
732
831
  var fromHex: (hex: string) => GlazeTheme;
@@ -831,5 +930,5 @@ declare function formatHsl(h: number, s: number, l: number): string;
831
930
  */
832
931
  declare function formatOklch(h: number, s: number, l: number): string;
833
932
  //#endregion
834
- export { type AdaptationMode, type ColorDef, type ColorMap, type ContrastPreset, type FindLightnessForContrastOptions, type FindLightnessForContrastResult, type FindValueForMixContrastOptions, type FindValueForMixContrastResult, type GlazeColorCssOptions, type GlazeColorFormat, type GlazeColorInput, type GlazeColorInputExport, type GlazeColorOverrides, type GlazeColorOverridesExport, type GlazeColorScaling, type GlazeColorToken, type GlazeColorTokenExport, type GlazeColorValue, type GlazeConfig, type GlazeCssOptions, type GlazeCssResult, type GlazeExtendOptions, type GlazeJsonOptions, type GlazeOutputModes, type GlazePalette, type GlazePaletteExportOptions, type GlazePaletteOptions, type GlazeShadowInput, type GlazeTheme, type GlazeThemeExport, type GlazeTokenOptions, type HCPair, type HexColor, type MinContrast, type MixColorDef, type OkhslColor, type RegularColorDef, type RelativeValue, type ResolvedColor, type ResolvedColorVariant, type ShadowColorDef, type ShadowTuning, contrastRatioFromLuminance, findLightnessForContrast, findValueForMixContrast, formatHsl, formatOkhsl, formatOklch, formatRgb, gamutClampedLuminance, glaze, hslToSrgb, okhslToLinearSrgb, okhslToOklab, okhslToSrgb, oklabToOkhsl, parseHex, parseHexAlpha, relativeLuminanceFromLinearRgb, resolveMinContrast, srgbToOkhsl };
933
+ export { type AdaptationMode, type ColorDef, type ColorMap, type ContrastPreset, type FindLightnessForContrastOptions, type FindLightnessForContrastResult, type FindValueForMixContrastOptions, type FindValueForMixContrastResult, type GlazeColorCssOptions, type GlazeColorFormat, type GlazeColorInput, type GlazeColorInputExport, type GlazeColorOverrides, type GlazeColorOverridesExport, type GlazeColorToken, type GlazeColorTokenExport, type GlazeColorValue, type GlazeConfig, type GlazeConfigOverride, type GlazeConfigResolved, type GlazeCssOptions, type GlazeCssResult, type GlazeExtendOptions, type GlazeFromInput, type GlazeJsonOptions, type GlazeOutputModes, type GlazePalette, type GlazePaletteExportOptions, type GlazePaletteOptions, type GlazeShadowInput, type GlazeTheme, type GlazeThemeExport, type GlazeTokenOptions, type HCPair, type HexColor, type LightnessWindow, type MinContrast, type MixColorDef, type OkhslColor, type OklchColor, type RegularColorDef, type RelativeValue, type ResolvedColor, type ResolvedColorVariant, type RgbColor, type ShadowColorDef, type ShadowTuning, contrastRatioFromLuminance, findLightnessForContrast, findValueForMixContrast, formatHsl, formatOkhsl, formatOklch, formatRgb, gamutClampedLuminance, glaze, hslToSrgb, okhslToLinearSrgb, okhslToOklab, okhslToSrgb, oklabToOkhsl, parseHex, parseHexAlpha, relativeLuminanceFromLinearRgb, resolveMinContrast, srgbToOkhsl };
835
934
  //# sourceMappingURL=index.d.cts.map