@motion-proto/live-tokens 0.50.0 → 0.52.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.
Files changed (57) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist-plugin/adjust/index.d.cts +1 -1
  3. package/dist-plugin/adjust/index.d.ts +1 -1
  4. package/dist-plugin/{chunk-76TFDTJO.js → chunk-JIGIIE5P.js} +60 -132
  5. package/dist-plugin/{chunk-44RSTAII.js → chunk-TKZBVIW5.js} +33 -5
  6. package/dist-plugin/chunk-YR6GPXW2.js +129 -0
  7. package/dist-plugin/generateColorsAndType/index.cjs +87 -31
  8. package/dist-plugin/generateColorsAndType/index.d.cts +1 -1
  9. package/dist-plugin/generateColorsAndType/index.d.ts +1 -1
  10. package/dist-plugin/generateColorsAndType/index.js +22 -12
  11. package/dist-plugin/index.cjs +95 -55
  12. package/dist-plugin/index.js +5 -3
  13. package/dist-plugin/{themeTypes-DSwKq-bj.d.cts → themeTypes-Dky03HL9.d.cts} +18 -5
  14. package/dist-plugin/{themeTypes-DSwKq-bj.d.ts → themeTypes-Dky03HL9.d.ts} +18 -5
  15. package/dist-plugin/tokensCssMigrations/index.cjs +71 -5
  16. package/dist-plugin/tokensCssMigrations/index.d.cts +20 -9
  17. package/dist-plugin/tokensCssMigrations/index.d.ts +20 -9
  18. package/dist-plugin/tokensCssMigrations/index.js +4 -1
  19. package/package.json +4 -2
  20. package/src/editor/component-editor/NotificationEditor.svelte +6 -0
  21. package/src/editor/core/palettes/oklch.ts +3 -137
  22. package/src/editor/core/palettes/paletteDerivation.ts +79 -37
  23. package/src/editor/core/themes/generateColorsAndType.ts +18 -8
  24. package/src/editor/core/themes/themeTypes.ts +18 -6
  25. package/src/editor/docs/content/editing-tokens.md +6 -2
  26. package/src/editor/docs/content.generated.ts +1 -1
  27. package/src/editor/ui/BezierCurveEditor.svelte +90 -67
  28. package/src/editor/ui/PaletteEditor.svelte +150 -44
  29. package/src/editor/ui/Toggle.svelte +14 -2
  30. package/src/editor/ui/colors/ColorStory.svelte +12 -8
  31. package/src/editor/ui/curveEngine.ts +101 -21
  32. package/src/editor/ui/palette/OverridesPanel.svelte +19 -5
  33. package/src/editor/ui/palette/PaletteBase.svelte +17 -78
  34. package/src/editor/ui/palette/ScaleCurveEditor.svelte +109 -20
  35. package/src/editor/ui/palette/curveSummary.ts +20 -0
  36. package/src/editor/ui/palette/dockMagnify.ts +5 -13
  37. package/src/editor/ui/palette/paletteMath.ts +7 -4
  38. package/src/live-tokens/data/colors-and-type/autumn.json +528 -528
  39. package/src/live-tokens/data/colors-and-type/default.json +247 -247
  40. package/src/live-tokens/data/colors-and-type/halloween.json +532 -532
  41. package/src/live-tokens/data/colors-and-type/midnight-study.json +538 -538
  42. package/src/live-tokens/data/colors-and-type/ocean.json +521 -521
  43. package/src/live-tokens/data/colors-and-type/royal-velvet.json +532 -532
  44. package/src/live-tokens/data/colors-and-type/spring-meadow.json +504 -504
  45. package/src/live-tokens/data/colors-and-type/sunset.json +531 -531
  46. package/src/live-tokens/data/themes/autumn.json +527 -527
  47. package/src/live-tokens/data/themes/halloween.json +531 -531
  48. package/src/live-tokens/data/themes/midnight-study.json +537 -537
  49. package/src/live-tokens/data/themes/ocean.json +520 -520
  50. package/src/live-tokens/data/themes/royal-velvet.json +531 -531
  51. package/src/live-tokens/data/themes/spring-meadow.json +504 -504
  52. package/src/live-tokens/data/themes/sunset.json +531 -531
  53. package/src/live-tokens/data/tokens.generated.css +282 -282
  54. package/src/system/components/FloatingTokenTags.css +0 -1
  55. package/src/system/internal/backgroundContrast.ts +7 -0
  56. package/src/system/internal/oklch.ts +189 -0
  57. package/src/system/styles/tokens.css +283 -283
@@ -37,7 +37,7 @@ __export(generateColorsAndType_exports, {
37
37
  });
38
38
  module.exports = __toCommonJS(generateColorsAndType_exports);
39
39
 
40
- // src/editor/core/palettes/oklch.ts
40
+ // src/system/internal/oklch.ts
41
41
  function srgbToLinear(c) {
42
42
  return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
43
43
  }
@@ -131,6 +131,31 @@ function gamutClamp(l, c, h) {
131
131
  }
132
132
  return { l, c: lo, h };
133
133
  }
134
+ function trim(value, decimals) {
135
+ return Number(value.toFixed(decimals)).toString();
136
+ }
137
+ function oklchToCss(l, c, h) {
138
+ const cs = trim(c, 4);
139
+ return `oklch(${trim(l, 4)} ${cs} ${cs === "0" ? "0" : trim(h, 2)})`;
140
+ }
141
+ function oklchToCssClamped(l, c, h) {
142
+ const g = gamutClamp(l, c, h);
143
+ return oklchToCss(g.l, g.c, g.h);
144
+ }
145
+ var OKLCH_RE = /^oklch\(\s*([\d.]+)(%?)\s+([\d.]+)(%?)\s+([\d.]+)(?:deg)?\s*\)$/i;
146
+ var HEX6_RE = /^#[0-9a-f]{6}$/i;
147
+ function parseOklchCss(value) {
148
+ const m = OKLCH_RE.exec(value.trim());
149
+ if (!m) return null;
150
+ const l = Number.parseFloat(m[1]) / (m[2] === "%" ? 100 : 1);
151
+ const c = Number.parseFloat(m[3]) * (m[4] === "%" ? 4e-3 : 1);
152
+ return { l, c, h: Number.parseFloat(m[5]) };
153
+ }
154
+ function cssColorToOklch(value) {
155
+ const raw = value.trim();
156
+ if (HEX6_RE.test(raw)) return hexToOklch(raw);
157
+ return parseOklchCss(raw);
158
+ }
134
159
 
135
160
  // src/editor/ui/curveEngine.ts
136
161
  function makeAnchor(x, y, tangentLen = 15) {
@@ -155,6 +180,15 @@ function tangentAnchor(x, y, prev, next) {
155
180
  const outDx = next ? (next.x - x) * HANDLE_SPAN : 0;
156
181
  return { x, y, inDx, inDy: m * inDx, outDx, outDy: m * outDx };
157
182
  }
183
+ function isCornerAnchor(a) {
184
+ return a.inDx === 0 && a.inDy === 0 && a.outDx === 0 && a.outDy === 0;
185
+ }
186
+ function resmoothAutoCurve(anchors) {
187
+ if (anchors.length < 2) return anchors;
188
+ return anchors.map(
189
+ (a, i) => isCornerAnchor(a) ? a : tangentAnchor(a.x, a.y, anchors[i - 1] ?? null, anchors[i + 1] ?? null)
190
+ );
191
+ }
158
192
  function evalBezier(p0x, p0y, c0x, c0y, c1x, c1y, p1x, p1y, t) {
159
193
  const u = 1 - t, u2 = u * u, u3 = u2 * u;
160
194
  const t2 = t * t, t3 = t2 * t;
@@ -250,37 +284,39 @@ var SCALES = [
250
284
  ];
251
285
  var BW_GUARD_MIN_L = 0.17;
252
286
  var BW_GUARD_MAX_L = 0.93;
253
- var DEFAULT_PALETTE_LIGHTNESS = () => [makeAnchor(0, 95, 5), makeAnchor(100, 8, 5)];
254
- var DEFAULT_PALETTE_SATURATION = () => [makeAnchor(0, 100, 30), makeAnchor(100, 100, 30)];
287
+ var autoCurve = (...anchors) => resmoothAutoCurve(anchors);
288
+ var DEFAULT_PALETTE_LIGHTNESS = () => autoCurve(makeAnchor(0, 95), makeAnchor(100, 8));
289
+ var DEFAULT_PALETTE_SATURATION = () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 100));
290
+ var wrapHue = (h) => (h % 360 + 360) % 360;
255
291
  function scaleCurveDefaults(scheme = "dark") {
256
292
  if (scheme === "light") {
257
293
  return {
258
294
  Surfaces: {
259
- lightness: () => [makeAnchor(0, 98, 5), makeAnchor(100, 82, 5)],
260
- saturation: () => [makeAnchor(0, 100, 30), makeAnchor(100, 100, 30)]
295
+ lightness: () => autoCurve(makeAnchor(0, 98), makeAnchor(100, 82)),
296
+ saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 100))
261
297
  },
262
298
  Borders: {
263
- lightness: () => [makeAnchor(0, 92, 5), makeAnchor(100, 45, 5)],
264
- saturation: () => [makeAnchor(0, 100, 30), makeAnchor(100, 100, 30)]
299
+ lightness: () => autoCurve(makeAnchor(0, 92), makeAnchor(100, 45)),
300
+ saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 100))
265
301
  },
266
302
  Text: {
267
- lightness: () => [makeAnchor(0, 30, 30), makeAnchor(100, 120, 30)],
268
- saturation: () => [makeAnchor(0, 100, 30), makeAnchor(100, 15, 30)]
303
+ lightness: () => autoCurve(makeAnchor(0, 30), makeAnchor(100, 120)),
304
+ saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 15))
269
305
  }
270
306
  };
271
307
  }
272
308
  return {
273
309
  Surfaces: {
274
- lightness: () => [makeAnchor(0, 15, 5), makeAnchor(100, 47, 5)],
275
- saturation: () => [makeAnchor(0, 100, 30), makeAnchor(100, 100, 30)]
310
+ lightness: () => autoCurve(makeAnchor(0, 15), makeAnchor(100, 47)),
311
+ saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 100))
276
312
  },
277
313
  Borders: {
278
- lightness: () => [makeAnchor(0, 25, 5), makeAnchor(100, 80, 5)],
279
- saturation: () => [makeAnchor(0, 100, 30), makeAnchor(100, 100, 30)]
314
+ lightness: () => autoCurve(makeAnchor(0, 25), makeAnchor(100, 80)),
315
+ saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 100))
280
316
  },
281
317
  Text: {
282
- lightness: () => [makeAnchor(0, 120, 30), makeAnchor(100, 55, 30)],
283
- saturation: () => [makeAnchor(0, 100, 30), makeAnchor(100, 15, 30)]
318
+ lightness: () => autoCurve(makeAnchor(0, 120), makeAnchor(100, 55)),
319
+ saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 15))
284
320
  }
285
321
  };
286
322
  }
@@ -299,14 +335,16 @@ function scaleStepToX(step, scale) {
299
335
  return scale.steps.length > 1 ? idx / (scale.steps.length - 1) * 100 : 50;
300
336
  }
301
337
  function serializeDerivedValue(value) {
302
- return value.kind === "raw" ? value.css : oklchToHexClamped(value.l, value.c, value.h);
338
+ return value.kind === "raw" ? value.css : oklchToCssClamped(value.l, value.c, value.h);
303
339
  }
304
- function computePaletteOklch(index, base, lightnessCurve, saturationCurve, curveOffset) {
305
- const { c: baseC, h } = base;
340
+ function computePaletteOklch(index, base, lightnessCurve, saturationCurve, curveOffset, hueCurve) {
341
+ const { c: baseC } = base;
306
342
  const xPos = stepIndexToX(index);
307
343
  const targetL = Math.max(0, Math.min(100, sampleCurve(lightnessCurve, xPos) + (curveOffset.lightness ?? 0))) / 100;
308
344
  const satMul = Math.max(0, Math.min(2, (sampleCurve(saturationCurve, xPos) + (curveOffset.saturation ?? 0)) / 100));
309
345
  const targetC = baseC * satMul;
346
+ const hueDelta = (hueCurve ? sampleCurve(hueCurve, xPos) : 0) + (curveOffset.hue ?? 0);
347
+ const h = hueDelta === 0 ? base.h : wrapHue(base.h + hueDelta);
310
348
  return gamutClamp(targetL, targetC, h);
311
349
  }
312
350
  function nearestPaletteStep(lightnessCurve, baseL) {
@@ -402,10 +440,12 @@ function syncBaseAnchor(cfg) {
402
440
  const fresh = prev === void 0;
403
441
  let lCurve = cfg.lightnessCurve;
404
442
  let sCurve = cfg.saturationCurve;
443
+ let hCurve = cfg.hueCurve;
405
444
  if (prev) {
406
445
  const prevX = stepIndexToX(prev.step);
407
446
  lCurve = liftCurveAnchor(lCurve, prevX, prev.displacedL);
408
447
  sCurve = liftCurveAnchor(sCurve, prevX, prev.displacedS);
448
+ if (hCurve) hCurve = liftCurveAnchor(hCurve, prevX, prev.displacedH);
409
449
  }
410
450
  const step = nearestPaletteStep(lCurve, cfg.baseColor.l);
411
451
  const x = stepIndexToX(step);
@@ -413,12 +453,19 @@ function syncBaseAnchor(cfg) {
413
453
  const s = setCurveAnchor(sCurve, x, 100, fresh);
414
454
  cfg.lightnessCurve = l.curve;
415
455
  cfg.saturationCurve = s.curve;
456
+ const h = hCurve ? setCurveAnchor(hCurve, x, 0, fresh) : void 0;
457
+ if (h) cfg.hueCurve = h.curve;
416
458
  cfg.anchorPlacement = {
417
459
  step,
418
460
  displacedL: l.displacedY,
419
461
  displacedS: s.displacedY,
462
+ displacedH: h?.displacedY,
420
463
  priorLightnessEndpoints: prev?.priorLightnessEndpoints ?? l.priorEndpoints,
421
- priorSaturationEndpoints: prev?.priorSaturationEndpoints ?? s.priorEndpoints
464
+ priorSaturationEndpoints: prev?.priorSaturationEndpoints ?? s.priorEndpoints,
465
+ // No else-branch reading `prev?.priorHueEndpoints`: that could only fire
466
+ // if a placed hue curve later went absent, which RJC 7 (reset never
467
+ // deletes) never lets happen.
468
+ priorHueEndpoints: h ? prev?.priorHueEndpoints ?? h.priorEndpoints : void 0
422
469
  };
423
470
  }
424
471
  function computeDerivedOklch(step, base, scaleTitle, scaleCurves, curveOffset) {
@@ -427,8 +474,10 @@ function computeDerivedOklch(step, base, scaleTitle, scaleCurves, curveOffset) {
427
474
  const defs = defaultScaleCurves[scaleTitle];
428
475
  const lCurve = scaleCurves[scaleTitle]?.lightness ?? defs.lightness();
429
476
  const sCurve = scaleCurves[scaleTitle]?.saturation ?? defs.saturation();
477
+ const hCurve = scaleCurves[scaleTitle]?.hue;
430
478
  const lOff = curveOffset[`${scaleTitle}-lightness`] ?? 0;
431
479
  const sOff = curveOffset[`${scaleTitle}-saturation`] ?? 0;
480
+ const hOff = curveOffset[`${scaleTitle}-hue`] ?? 0;
432
481
  const { l: baseL, c: baseC, h: baseH } = base;
433
482
  let targetL;
434
483
  if (scale.isText) {
@@ -439,7 +488,9 @@ function computeDerivedOklch(step, base, scaleTitle, scaleCurves, curveOffset) {
439
488
  }
440
489
  const satMul = Math.max(0, Math.min(2, (sampleCurve(sCurve, xPos) + sOff) / 100));
441
490
  const targetC = baseC * satMul;
442
- return gamutClamp(targetL, targetC, baseH);
491
+ const hueDelta = (hCurve ? sampleCurve(hCurve, xPos) : 0) + hOff;
492
+ const targetH = hueDelta === 0 ? baseH : wrapHue(baseH + hueDelta);
493
+ return gamutClamp(targetL, targetC, targetH);
443
494
  }
444
495
  function scaleToCssVar(scaleTitle, stepName, cssNamespace) {
445
496
  if (cssNamespace === null) return null;
@@ -468,7 +519,7 @@ function derivePaletteValues(spec, config) {
468
519
  const saturationCurve = config.saturationCurve ?? DEFAULT_PALETTE_SATURATION();
469
520
  PALETTE_STEPS.forEach((ps, index) => {
470
521
  const k = paletteStepKey(ps.label);
471
- const value = k in overrides ? { kind: "color", ...overrides[k] } : { kind: "color", ...computePaletteOklch(index, baseColor, lightnessCurve, saturationCurve, curveOffset) };
522
+ const value = k in overrides ? { kind: "color", ...overrides[k] } : { kind: "color", ...computePaletteOklch(index, baseColor, lightnessCurve, saturationCurve, curveOffset, config.hueCurve) };
472
523
  out[`--color-${spec.cssNamespace}-${ps.label}`] = value;
473
524
  });
474
525
  for (const scale of SCALES) {
@@ -503,8 +554,8 @@ function derivePaletteValues(spec, config) {
503
554
  );
504
555
  const stopsCss = sortedStops.map((s) => {
505
556
  const stopValue = out[`--color-${spec.cssNamespace}-${s.paletteLabel}`];
506
- const hex = stopValue ? serializeDerivedValue(stopValue) : "#000000";
507
- return `${hex} ${s.position}%`;
557
+ const css = stopValue ? serializeDerivedValue(stopValue) : "oklch(0 0 0)";
558
+ return `${css} ${s.position}%`;
508
559
  }).join(", ");
509
560
  let gradient;
510
561
  switch (gradientStyle) {
@@ -705,7 +756,7 @@ function findLForContrast(opts) {
705
756
  }
706
757
 
707
758
  // src/editor/ui/palette/paletteMath.ts
708
- var DEFAULT_NEUTRAL_LIGHTNESS = () => [makeAnchor(0, 92, 5), makeAnchor(100, 3, 5)];
759
+ var DEFAULT_NEUTRAL_LIGHTNESS = () => resmoothAutoCurve([makeAnchor(0, 92), makeAnchor(100, 3)]);
709
760
  function defaultPaletteConfig(opts) {
710
761
  const cfg = {
711
762
  baseColor: opts.baseColor,
@@ -1577,12 +1628,16 @@ function surfaceVars() {
1577
1628
  "--page-bg"
1578
1629
  ];
1579
1630
  }
1631
+ function varToHex(value) {
1632
+ const parsed = value ? cssColorToOklch(value) : null;
1633
+ return parsed ? oklchToHexClamped(parsed.l, parsed.c, parsed.h) : null;
1634
+ }
1580
1635
  function worstSurface(textHex, vars) {
1581
1636
  let against = "";
1582
1637
  let ratio = Infinity;
1583
1638
  for (const surfVar of surfaceVars()) {
1584
- const surfHex = vars[surfVar];
1585
- if (!surfHex || !HEX_RE.test(surfHex)) continue;
1639
+ const surfHex = varToHex(vars[surfVar]);
1640
+ if (!surfHex) continue;
1586
1641
  const r = contrastRatio(textHex, surfHex);
1587
1642
  if (r < ratio) {
1588
1643
  ratio = r;
@@ -1610,17 +1665,18 @@ function runContrastGate(configs, scheme) {
1610
1665
  const vars = palettesToVars(configs);
1611
1666
  let anyFixed = false;
1612
1667
  for (const def of defs) {
1613
- const textHex = vars[def.textVar];
1614
- if (!textHex) continue;
1668
+ const text = cssColorToOklch(vars[def.textVar] ?? "");
1669
+ if (!text) continue;
1670
+ const textHex = oklchToHexClamped(text.l, text.c, text.h);
1615
1671
  const worst = worstSurface(textHex, vars);
1616
1672
  if (worst.ratio >= def.floor) continue;
1617
1673
  const cfg = configs[def.paletteLabel];
1618
1674
  const seed = cfg.baseColor;
1619
1675
  const solved = findLForContrast({
1620
- against: vars[worst.against],
1676
+ against: varToHex(vars[worst.against]) ?? "#000000",
1621
1677
  ratio: def.target,
1622
1678
  direction,
1623
- c: hexToOklch(textHex).c,
1679
+ c: text.c,
1624
1680
  h: seed.h,
1625
1681
  lMax: Math.min(1, 2 * seed.l)
1626
1682
  });
@@ -1632,7 +1688,7 @@ function runContrastGate(configs, scheme) {
1632
1688
  }
1633
1689
  const finalVars = palettesToVars(configs);
1634
1690
  const checks = defs.map((def) => {
1635
- const worst = worstSurface(finalVars[def.textVar] ?? "#000000", finalVars);
1691
+ const worst = worstSurface(varToHex(finalVars[def.textVar]) ?? "#000000", finalVars);
1636
1692
  return {
1637
1693
  textVar: def.textVar,
1638
1694
  floor: def.floor,
@@ -1,4 +1,4 @@
1
- import { F as FontSource, b as FontStack, G as GradientDiskToken, O as Oklch, H as HarmonyMode, C as ColorsAndType } from '../themeTypes-DSwKq-bj.cjs';
1
+ import { F as FontSource, b as FontStack, G as GradientDiskToken, O as Oklch, H as HarmonyMode, C as ColorsAndType } from '../themeTypes-Dky03HL9.cjs';
2
2
  export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-DBN0RPuT.cjs';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { F as FontSource, b as FontStack, G as GradientDiskToken, O as Oklch, H as HarmonyMode, C as ColorsAndType } from '../themeTypes-DSwKq-bj.js';
1
+ import { F as FontSource, b as FontStack, G as GradientDiskToken, O as Oklch, H as HarmonyMode, C as ColorsAndType } from '../themeTypes-Dky03HL9.js';
2
2
  export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-DBN0RPuT.js';
3
3
 
4
4
  /**
@@ -4,18 +4,23 @@ import {
4
4
  PALETTE_SPECS,
5
5
  PALETTE_STEPS,
6
6
  SCALES,
7
- gamutClamp,
8
- hexToOklch,
9
7
  makeAnchor,
10
- oklchToHex,
11
8
  palettesToVars,
9
+ resmoothAutoCurve,
12
10
  sanitizeFileName,
13
11
  scaleCurveDefaults,
14
12
  scaleStepToX,
15
13
  scaleToCssVar,
16
14
  setCurveAnchor,
17
15
  syncBaseAnchor
18
- } from "../chunk-76TFDTJO.js";
16
+ } from "../chunk-JIGIIE5P.js";
17
+ import {
18
+ cssColorToOklch,
19
+ gamutClamp,
20
+ hexToOklch,
21
+ oklchToHex,
22
+ oklchToHexClamped
23
+ } from "../chunk-YR6GPXW2.js";
19
24
  import {
20
25
  readLiveTokensConfig,
21
26
  resolveDataDirs
@@ -188,7 +193,7 @@ function findLForContrast(opts) {
188
193
  }
189
194
 
190
195
  // src/editor/ui/palette/paletteMath.ts
191
- var DEFAULT_NEUTRAL_LIGHTNESS = () => [makeAnchor(0, 92, 5), makeAnchor(100, 3, 5)];
196
+ var DEFAULT_NEUTRAL_LIGHTNESS = () => resmoothAutoCurve([makeAnchor(0, 92), makeAnchor(100, 3)]);
192
197
  function defaultPaletteConfig(opts) {
193
198
  const cfg = {
194
199
  baseColor: opts.baseColor,
@@ -1055,12 +1060,16 @@ function surfaceVars() {
1055
1060
  "--page-bg"
1056
1061
  ];
1057
1062
  }
1063
+ function varToHex(value) {
1064
+ const parsed = value ? cssColorToOklch(value) : null;
1065
+ return parsed ? oklchToHexClamped(parsed.l, parsed.c, parsed.h) : null;
1066
+ }
1058
1067
  function worstSurface(textHex, vars) {
1059
1068
  let against = "";
1060
1069
  let ratio = Infinity;
1061
1070
  for (const surfVar of surfaceVars()) {
1062
- const surfHex = vars[surfVar];
1063
- if (!surfHex || !HEX_RE.test(surfHex)) continue;
1071
+ const surfHex = varToHex(vars[surfVar]);
1072
+ if (!surfHex) continue;
1064
1073
  const r = contrastRatio(textHex, surfHex);
1065
1074
  if (r < ratio) {
1066
1075
  ratio = r;
@@ -1088,17 +1097,18 @@ function runContrastGate(configs, scheme) {
1088
1097
  const vars = palettesToVars(configs);
1089
1098
  let anyFixed = false;
1090
1099
  for (const def of defs) {
1091
- const textHex = vars[def.textVar];
1092
- if (!textHex) continue;
1100
+ const text = cssColorToOklch(vars[def.textVar] ?? "");
1101
+ if (!text) continue;
1102
+ const textHex = oklchToHexClamped(text.l, text.c, text.h);
1093
1103
  const worst = worstSurface(textHex, vars);
1094
1104
  if (worst.ratio >= def.floor) continue;
1095
1105
  const cfg = configs[def.paletteLabel];
1096
1106
  const seed = cfg.baseColor;
1097
1107
  const solved = findLForContrast({
1098
- against: vars[worst.against],
1108
+ against: varToHex(vars[worst.against]) ?? "#000000",
1099
1109
  ratio: def.target,
1100
1110
  direction,
1101
- c: hexToOklch(textHex).c,
1111
+ c: text.c,
1102
1112
  h: seed.h,
1103
1113
  lMax: Math.min(1, 2 * seed.l)
1104
1114
  });
@@ -1110,7 +1120,7 @@ function runContrastGate(configs, scheme) {
1110
1120
  }
1111
1121
  const finalVars = palettesToVars(configs);
1112
1122
  const checks = defs.map((def) => {
1113
- const worst = worstSurface(finalVars[def.textVar] ?? "#000000", finalVars);
1123
+ const worst = worstSurface(varToHex(finalVars[def.textVar]) ?? "#000000", finalVars);
1114
1124
  return {
1115
1125
  textVar: def.textVar,
1116
1126
  floor: def.floor,