@tenphi/glaze 0.15.0 → 0.15.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/index.d.cts CHANGED
@@ -217,6 +217,13 @@ interface RegularColorDef {
217
217
  * should not be combined (a console.warn is emitted).
218
218
  */
219
219
  opacity?: number;
220
+ /**
221
+ * Per-color override for the hue-independent "safe" chroma limit used in
222
+ * OKHSL↔sRGB conversions (luminance, contrast solving, output formatting).
223
+ * Falls through to the global / per-theme `pastel` config when omitted.
224
+ * @see GlazeConfig.pastel
225
+ */
226
+ pastel?: boolean;
220
227
  /**
221
228
  * Whether this color is inherited by child themes created via `extend()`.
222
229
  * Default: true. Set to false to make this color local to the current theme.
@@ -266,6 +273,13 @@ interface ShadowColorDef {
266
273
  intensity: HCPair<number>;
267
274
  /** Override default tuning. Merged field-by-field with global `shadowTuning`. */
268
275
  tuning?: ShadowTuning;
276
+ /**
277
+ * Per-color override for the hue-independent "safe" chroma limit used in
278
+ * OKHSL↔sRGB conversions (luminance, contrast solving, output formatting).
279
+ * Falls through to the global / per-theme `pastel` config when omitted.
280
+ * @see GlazeConfig.pastel
281
+ */
282
+ pastel?: boolean;
269
283
  /**
270
284
  * Whether this color is inherited by child themes created via `extend()`.
271
285
  * Default: true. Set to false to make this color local to the current theme.
@@ -306,6 +320,13 @@ interface MixColorDef {
306
320
  * metric. Supports [normal, highContrast] pair.
307
321
  */
308
322
  contrast?: HCPair<ContrastSpec>;
323
+ /**
324
+ * Per-color override for the hue-independent "safe" chroma limit used in
325
+ * OKHSL↔sRGB conversions (luminance, contrast solving, output formatting).
326
+ * Falls through to the global / per-theme `pastel` config when omitted.
327
+ * @see GlazeConfig.pastel
328
+ */
329
+ pastel?: boolean;
309
330
  /**
310
331
  * Whether this color is inherited by child themes created via `extend()`.
311
332
  * Default: true. Set to false to make this color local to the current theme.
@@ -330,6 +351,12 @@ interface ResolvedColorVariant {
330
351
  t: number;
331
352
  /** Opacity (0–1). Default: 1. */
332
353
  alpha: number;
354
+ /**
355
+ * Effective `pastel` flag used while resolving this variant (author def or
356
+ * config fallback). Carried on the variant so output formatting matches the
357
+ * gamut mapping applied during resolution.
358
+ */
359
+ pastel?: boolean;
333
360
  }
334
361
  /** Fully resolved color across all scheme variants. */
335
362
  interface ResolvedColor {
@@ -493,6 +520,13 @@ interface GlazeColorInput {
493
520
  * used). Does not affect output keys.
494
521
  */
495
522
  name?: string;
523
+ /**
524
+ * Per-color override for the hue-independent "safe" chroma limit used in
525
+ * OKHSL↔sRGB conversions (luminance, contrast solving, output formatting).
526
+ * Falls through to the global / per-theme `pastel` config when omitted.
527
+ * @see GlazeConfig.pastel
528
+ */
529
+ pastel?: boolean;
496
530
  }
497
531
  /**
498
532
  * Any single-color input form accepted by the value-shorthand
@@ -593,6 +627,13 @@ interface GlazeColorOverrides {
593
627
  * used). Does not affect output keys.
594
628
  */
595
629
  name?: string;
630
+ /**
631
+ * Per-color override for the hue-independent "safe" chroma limit used in
632
+ * OKHSL↔sRGB conversions (luminance, contrast solving, output formatting).
633
+ * Falls through to the global / per-theme `pastel` config when omitted.
634
+ * @see GlazeConfig.pastel
635
+ */
636
+ pastel?: boolean;
596
637
  }
597
638
  /**
598
639
  * Object input for `glaze.color()` that carries a raw color value plus
@@ -689,6 +730,7 @@ interface GlazeColorInputExport {
689
730
  base?: GlazeColorTokenExport | GlazeColorValue;
690
731
  contrast?: HCPair<ContrastSpec>;
691
732
  name?: string;
733
+ pastel?: boolean;
692
734
  }
693
735
  /**
694
736
  * Serializable shape of `GlazeColorOverrides`. `base` is replaced by
@@ -705,6 +747,7 @@ interface GlazeColorOverridesExport {
705
747
  base?: GlazeColorTokenExport | GlazeColorValue;
706
748
  opacity?: number;
707
749
  name?: string;
750
+ pastel?: boolean;
708
751
  }
709
752
  interface GlazeTheme {
710
753
  /** The hue seed (0–360). */
package/dist/index.d.mts CHANGED
@@ -217,6 +217,13 @@ interface RegularColorDef {
217
217
  * should not be combined (a console.warn is emitted).
218
218
  */
219
219
  opacity?: number;
220
+ /**
221
+ * Per-color override for the hue-independent "safe" chroma limit used in
222
+ * OKHSL↔sRGB conversions (luminance, contrast solving, output formatting).
223
+ * Falls through to the global / per-theme `pastel` config when omitted.
224
+ * @see GlazeConfig.pastel
225
+ */
226
+ pastel?: boolean;
220
227
  /**
221
228
  * Whether this color is inherited by child themes created via `extend()`.
222
229
  * Default: true. Set to false to make this color local to the current theme.
@@ -266,6 +273,13 @@ interface ShadowColorDef {
266
273
  intensity: HCPair<number>;
267
274
  /** Override default tuning. Merged field-by-field with global `shadowTuning`. */
268
275
  tuning?: ShadowTuning;
276
+ /**
277
+ * Per-color override for the hue-independent "safe" chroma limit used in
278
+ * OKHSL↔sRGB conversions (luminance, contrast solving, output formatting).
279
+ * Falls through to the global / per-theme `pastel` config when omitted.
280
+ * @see GlazeConfig.pastel
281
+ */
282
+ pastel?: boolean;
269
283
  /**
270
284
  * Whether this color is inherited by child themes created via `extend()`.
271
285
  * Default: true. Set to false to make this color local to the current theme.
@@ -306,6 +320,13 @@ interface MixColorDef {
306
320
  * metric. Supports [normal, highContrast] pair.
307
321
  */
308
322
  contrast?: HCPair<ContrastSpec>;
323
+ /**
324
+ * Per-color override for the hue-independent "safe" chroma limit used in
325
+ * OKHSL↔sRGB conversions (luminance, contrast solving, output formatting).
326
+ * Falls through to the global / per-theme `pastel` config when omitted.
327
+ * @see GlazeConfig.pastel
328
+ */
329
+ pastel?: boolean;
309
330
  /**
310
331
  * Whether this color is inherited by child themes created via `extend()`.
311
332
  * Default: true. Set to false to make this color local to the current theme.
@@ -330,6 +351,12 @@ interface ResolvedColorVariant {
330
351
  t: number;
331
352
  /** Opacity (0–1). Default: 1. */
332
353
  alpha: number;
354
+ /**
355
+ * Effective `pastel` flag used while resolving this variant (author def or
356
+ * config fallback). Carried on the variant so output formatting matches the
357
+ * gamut mapping applied during resolution.
358
+ */
359
+ pastel?: boolean;
333
360
  }
334
361
  /** Fully resolved color across all scheme variants. */
335
362
  interface ResolvedColor {
@@ -493,6 +520,13 @@ interface GlazeColorInput {
493
520
  * used). Does not affect output keys.
494
521
  */
495
522
  name?: string;
523
+ /**
524
+ * Per-color override for the hue-independent "safe" chroma limit used in
525
+ * OKHSL↔sRGB conversions (luminance, contrast solving, output formatting).
526
+ * Falls through to the global / per-theme `pastel` config when omitted.
527
+ * @see GlazeConfig.pastel
528
+ */
529
+ pastel?: boolean;
496
530
  }
497
531
  /**
498
532
  * Any single-color input form accepted by the value-shorthand
@@ -593,6 +627,13 @@ interface GlazeColorOverrides {
593
627
  * used). Does not affect output keys.
594
628
  */
595
629
  name?: string;
630
+ /**
631
+ * Per-color override for the hue-independent "safe" chroma limit used in
632
+ * OKHSL↔sRGB conversions (luminance, contrast solving, output formatting).
633
+ * Falls through to the global / per-theme `pastel` config when omitted.
634
+ * @see GlazeConfig.pastel
635
+ */
636
+ pastel?: boolean;
596
637
  }
597
638
  /**
598
639
  * Object input for `glaze.color()` that carries a raw color value plus
@@ -689,6 +730,7 @@ interface GlazeColorInputExport {
689
730
  base?: GlazeColorTokenExport | GlazeColorValue;
690
731
  contrast?: HCPair<ContrastSpec>;
691
732
  name?: string;
733
+ pastel?: boolean;
692
734
  }
693
735
  /**
694
736
  * Serializable shape of `GlazeColorOverrides`. `base` is replaced by
@@ -705,6 +747,7 @@ interface GlazeColorOverridesExport {
705
747
  base?: GlazeColorTokenExport | GlazeColorValue;
706
748
  opacity?: number;
707
749
  name?: string;
750
+ pastel?: boolean;
708
751
  }
709
752
  interface GlazeTheme {
710
753
  /** The hue seed (0–360). */
package/dist/index.mjs CHANGED
@@ -1539,7 +1539,8 @@ function toOkhslVariant(v) {
1539
1539
  h: c.h,
1540
1540
  s: c.s,
1541
1541
  l: c.l,
1542
- alpha: v.alpha
1542
+ alpha: v.alpha,
1543
+ pastel: v.pastel
1543
1544
  };
1544
1545
  }
1545
1546
  /** Edge adapter: OKHSL-lightness variant → resolved variant (`t`). */
@@ -1586,6 +1587,7 @@ function resolveDependentColor(name, def, ctx, isHighContrast, isDark, effective
1586
1587
  const mode = def.mode ?? "auto";
1587
1588
  const satFactor = clamp(def.saturation ?? 1, 0, 1);
1588
1589
  const flip = def.flip ?? ctx.config.autoFlip;
1590
+ const pastel = def.pastel ?? ctx.config.pastel;
1589
1591
  const baseVariant = getSchemeVariant(baseResolved, isDark, isHighContrast);
1590
1592
  const baseTone = baseVariant.t * 100;
1591
1593
  let preferredTone;
@@ -1604,7 +1606,7 @@ function resolveDependentColor(name, def, ctx, isHighContrast, isDark, effective
1604
1606
  const resolvedContrast = resolveContrastSpec(rawContrast, isHighContrast);
1605
1607
  const effectiveSat = isDark ? mapSaturationDark(satFactor * ctx.saturation / 100, mode, ctx.config) : satFactor * ctx.saturation / 100;
1606
1608
  const baseOkhsl = toOkhslVariant(baseVariant);
1607
- const baseLinearRgb = okhslToLinearSrgb(baseOkhsl.h, baseOkhsl.s, baseOkhsl.l, ctx.config.pastel);
1609
+ const baseLinearRgb = okhslToLinearSrgb(baseOkhsl.h, baseOkhsl.s, baseOkhsl.l, baseVariant.pastel ?? ctx.config.pastel);
1608
1610
  const toneRange = schemeToneRange(isDark, mode, isHighContrast, ctx.config);
1609
1611
  let initialDirection;
1610
1612
  if (preferredTone < baseTone) initialDirection = "darker";
@@ -1618,7 +1620,7 @@ function resolveDependentColor(name, def, ctx, isHighContrast, isDark, effective
1618
1620
  toneRange: [0, 1],
1619
1621
  initialDirection,
1620
1622
  flip,
1621
- pastel: ctx.config.pastel
1623
+ pastel
1622
1624
  });
1623
1625
  if (!result.met) warnContrastUnmet(name, isDark, isHighContrast, resolvedContrast, result.contrast);
1624
1626
  return {
@@ -1638,6 +1640,7 @@ function resolveColorForScheme(name, def, ctx, isDark, isHighContrast) {
1638
1640
  const mode = regDef.mode ?? "auto";
1639
1641
  const isRoot = isAbsoluteTone(regDef.tone) && !regDef.base;
1640
1642
  const effectiveHue = resolveEffectiveHue(ctx.hue, regDef.hue);
1643
+ const pastel = regDef.pastel ?? ctx.config.pastel;
1641
1644
  let finalTone;
1642
1645
  let satFactor;
1643
1646
  if (isRoot) {
@@ -1656,7 +1659,8 @@ function resolveColorForScheme(name, def, ctx, isDark, isHighContrast) {
1656
1659
  h: effectiveHue,
1657
1660
  s: clamp(finalSat, 0, 1),
1658
1661
  t: toneFraction,
1659
- alpha: regDef.opacity ?? 1
1662
+ alpha: regDef.opacity ?? 1,
1663
+ pastel
1660
1664
  };
1661
1665
  }
1662
1666
  function resolveShadowForScheme(def, ctx, isDark, isHighContrast) {
@@ -1665,7 +1669,10 @@ function resolveShadowForScheme(def, ctx, isDark, isHighContrast) {
1665
1669
  if (def.fg) fgVariant = toOkhslVariant(getSchemeVariant(ctx.resolved.get(def.fg), isDark, isHighContrast));
1666
1670
  const intensity = isHighContrast ? pairHC(def.intensity) : pairNormal(def.intensity);
1667
1671
  const tuning = resolveShadowTuning(def.tuning, ctx.config.shadowTuning);
1668
- return toToneVariant(computeShadow(bgVariant, fgVariant, intensity, tuning));
1672
+ return {
1673
+ ...toToneVariant(computeShadow(bgVariant, fgVariant, intensity, tuning)),
1674
+ pastel: def.pastel ?? ctx.config.pastel
1675
+ };
1669
1676
  }
1670
1677
  function okhslVariantToLinearRgb(v, pastel) {
1671
1678
  return okhslToLinearSrgb(v.h, v.s, v.l, pastel);
@@ -1712,15 +1719,16 @@ function resolveMixForScheme(def, ctx, isDark, isHighContrast) {
1712
1719
  let t = clamp(isHighContrast ? pairHC(def.value) : pairNormal(def.value), 0, 100) / 100;
1713
1720
  const blend = def.blend ?? "opaque";
1714
1721
  const space = def.space ?? "okhsl";
1715
- const baseLinear = okhslVariantToLinearRgb(baseVariant, ctx.config.pastel);
1716
- const targetLinear = okhslVariantToLinearRgb(targetVariant, ctx.config.pastel);
1722
+ const pastel = def.pastel ?? ctx.config.pastel;
1723
+ const baseLinear = okhslVariantToLinearRgb(baseVariant, baseVariant.pastel ?? ctx.config.pastel);
1724
+ const targetLinear = okhslVariantToLinearRgb(targetVariant, targetVariant.pastel ?? ctx.config.pastel);
1717
1725
  if (def.contrast !== void 0) {
1718
1726
  const resolvedContrast = resolveContrastSpec(def.contrast, isHighContrast);
1719
1727
  const metric = resolvedContrast.metric;
1720
1728
  let luminanceAt;
1721
1729
  if (blend === "transparent" || space === "srgb") luminanceAt = (v) => metricLuminance(metric, linearSrgbLerp(baseLinear, targetLinear, v));
1722
1730
  else luminanceAt = (v) => {
1723
- return metricLuminance(metric, okhslToLinearSrgb(mixHue(baseVariant, targetVariant, v), baseVariant.s + (targetVariant.s - baseVariant.s) * v, baseVariant.l + (targetVariant.l - baseVariant.l) * v, ctx.config.pastel));
1731
+ return metricLuminance(metric, okhslToLinearSrgb(mixHue(baseVariant, targetVariant, v), baseVariant.s + (targetVariant.s - baseVariant.s) * v, baseVariant.l + (targetVariant.l - baseVariant.l) * v, pastel));
1724
1732
  };
1725
1733
  t = findValueForMixContrast({
1726
1734
  preferredValue: t,
@@ -1731,19 +1739,28 @@ function resolveMixForScheme(def, ctx, isDark, isHighContrast) {
1731
1739
  flip: ctx.config.autoFlip
1732
1740
  }).value;
1733
1741
  }
1734
- if (blend === "transparent") return toToneVariant({
1735
- h: targetVariant.h,
1736
- s: targetVariant.s,
1737
- l: targetVariant.l,
1738
- alpha: clamp(t, 0, 1)
1739
- });
1740
- if (space === "srgb") return linearRgbToToneVariant(linearSrgbLerp(baseLinear, targetLinear, t), ctx.config.pastel);
1741
- return toToneVariant({
1742
- h: mixHue(baseVariant, targetVariant, t),
1743
- s: clamp(baseVariant.s + (targetVariant.s - baseVariant.s) * t, 0, 1),
1744
- l: clamp(baseVariant.l + (targetVariant.l - baseVariant.l) * t, 0, 1),
1745
- alpha: 1
1746
- });
1742
+ if (blend === "transparent") return {
1743
+ ...toToneVariant({
1744
+ h: targetVariant.h,
1745
+ s: targetVariant.s,
1746
+ l: targetVariant.l,
1747
+ alpha: clamp(t, 0, 1)
1748
+ }),
1749
+ pastel
1750
+ };
1751
+ if (space === "srgb") return {
1752
+ ...linearRgbToToneVariant(linearSrgbLerp(baseLinear, targetLinear, t), pastel),
1753
+ pastel
1754
+ };
1755
+ return {
1756
+ ...toToneVariant({
1757
+ h: mixHue(baseVariant, targetVariant, t),
1758
+ s: clamp(baseVariant.s + (targetVariant.s - baseVariant.s) * t, 0, 1),
1759
+ l: clamp(baseVariant.l + (targetVariant.l - baseVariant.l) * t, 0, 1),
1760
+ alpha: 1
1761
+ }),
1762
+ pastel
1763
+ };
1747
1764
  }
1748
1765
  function defMode(def) {
1749
1766
  if (isShadowDef(def) || isMixDef(def)) return void 0;
@@ -1794,7 +1811,7 @@ function seedField(order, ctx, field, source) {
1794
1811
  * resolved with a `base` + `contrast` may land slightly under the contrast
1795
1812
  * its tone implies because chromatic luminance drifts from the gray tone.
1796
1813
  */
1797
- function verifyContrastDrift(order, defs, result) {
1814
+ function verifyContrastDrift(order, defs, result, config) {
1798
1815
  for (const name of order) {
1799
1816
  const def = defs[name];
1800
1817
  if (isShadowDef(def) || isMixDef(def)) continue;
@@ -1830,8 +1847,10 @@ function verifyContrastDrift(order, defs, result) {
1830
1847
  const bVariant = base[s.field];
1831
1848
  const cOkhsl = toOkhslVariant(cVariant);
1832
1849
  const bOkhsl = toOkhslVariant(bVariant);
1833
- const yC = metricLuminance(spec.metric, okhslToLinearSrgb(cOkhsl.h, cOkhsl.s, cOkhsl.l));
1834
- const yB = metricLuminance(spec.metric, okhslToLinearSrgb(bOkhsl.h, bOkhsl.s, bOkhsl.l));
1850
+ const cPastel = cVariant.pastel ?? config.pastel;
1851
+ const bPastel = bVariant.pastel ?? config.pastel;
1852
+ const yC = metricLuminance(spec.metric, okhslToLinearSrgb(cOkhsl.h, cOkhsl.s, cOkhsl.l, cPastel));
1853
+ const yB = metricLuminance(spec.metric, okhslToLinearSrgb(bOkhsl.h, bOkhsl.s, bOkhsl.l, bPastel));
1835
1854
  warnContrastDrift(name, s.isDark, s.isHighContrast, spec, yC, yB);
1836
1855
  }
1837
1856
  }
@@ -1864,7 +1883,7 @@ function resolveAllColors(hue, saturation, defs, config, externalBases) {
1864
1883
  darkContrast: darkHCMap.get(name),
1865
1884
  mode: defMode(defs[name])
1866
1885
  });
1867
- verifyContrastDrift(order, defs, result);
1886
+ verifyContrastDrift(order, defs, result, config);
1868
1887
  return result;
1869
1888
  }
1870
1889
 
@@ -1890,8 +1909,9 @@ function fmt(value, decimals) {
1890
1909
  return parseFloat(value.toFixed(decimals)).toString();
1891
1910
  }
1892
1911
  function formatVariant(v, format = "okhsl", pastel = false) {
1912
+ const effectivePastel = v.pastel ?? pastel;
1893
1913
  const { l } = variantToOkhsl(v);
1894
- const base = formatters[format](v.h, v.s * 100, l * 100, pastel);
1914
+ const base = formatters[format](v.h, v.s * 100, l * 100, effectivePastel);
1895
1915
  if (v.alpha >= 1) return base;
1896
1916
  const closing = base.lastIndexOf(")");
1897
1917
  return `${base.slice(0, closing)} / ${fmt(v.alpha, 4)})`;
@@ -2304,6 +2324,7 @@ function buildStandaloneValueDefs(main, options) {
2304
2324
  mode: options?.mode ?? "auto",
2305
2325
  flip: options?.flip,
2306
2326
  opacity: options?.opacity,
2327
+ pastel: options?.pastel,
2307
2328
  base: hasExternalBase ? STANDALONE_BASE : needsSeedAnchor ? STANDALONE_SEED : void 0
2308
2329
  };
2309
2330
  const defs = { [primary]: valueDef };
@@ -2404,6 +2425,7 @@ function createColorToken(input, configOverride) {
2404
2425
  flip: input.flip,
2405
2426
  contrast: input.contrast,
2406
2427
  opacity: input.opacity,
2428
+ pastel: input.pastel,
2407
2429
  base: hasExternalBase ? STANDALONE_BASE : needsSeedAnchor ? STANDALONE_SEED : void 0
2408
2430
  } };
2409
2431
  if (needsSeedAnchor) {
@@ -2453,6 +2475,7 @@ function buildOverridesExport(options) {
2453
2475
  if (options.contrast !== void 0) out.contrast = options.contrast;
2454
2476
  if (options.opacity !== void 0) out.opacity = options.opacity;
2455
2477
  if (options.name !== void 0) out.name = options.name;
2478
+ if (options.pastel !== void 0) out.pastel = options.pastel;
2456
2479
  if (options.base !== void 0) out.base = isGlazeColorToken(options.base) ? options.base.export() : options.base;
2457
2480
  return out;
2458
2481
  }
@@ -2468,6 +2491,7 @@ function buildStructuredInputExport(input) {
2468
2491
  if (input.opacity !== void 0) out.opacity = input.opacity;
2469
2492
  if (input.contrast !== void 0) out.contrast = input.contrast;
2470
2493
  if (input.name !== void 0) out.name = input.name;
2494
+ if (input.pastel !== void 0) out.pastel = input.pastel;
2471
2495
  if (input.base !== void 0) out.base = isGlazeColorToken(input.base) ? input.base.export() : input.base;
2472
2496
  return out;
2473
2497
  }
@@ -2488,6 +2512,7 @@ function rehydrateOverrides(data) {
2488
2512
  if (data.contrast !== void 0) out.contrast = data.contrast;
2489
2513
  if (data.opacity !== void 0) out.opacity = data.opacity;
2490
2514
  if (data.name !== void 0) out.name = data.name;
2515
+ if (data.pastel !== void 0) out.pastel = data.pastel;
2491
2516
  if (data.base !== void 0) out.base = isExportedToken(data.base) ? colorFromExport(data.base) : data.base;
2492
2517
  return out;
2493
2518
  }
@@ -2503,6 +2528,7 @@ function rehydrateStructuredInput(data) {
2503
2528
  if (data.opacity !== void 0) out.opacity = data.opacity;
2504
2529
  if (data.contrast !== void 0) out.contrast = data.contrast;
2505
2530
  if (data.name !== void 0) out.name = data.name;
2531
+ if (data.pastel !== void 0) out.pastel = data.pastel;
2506
2532
  if (data.base !== void 0) out.base = isExportedToken(data.base) ? colorFromExport(data.base) : data.base;
2507
2533
  return out;
2508
2534
  }