@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
@@ -65,26 +65,16 @@ function sanitizeFileName(name) {
65
65
  return name.toLowerCase().trim().replace(/\s+/g, "-").replace(/[^a-z0-9\-_]/g, "").replace(/-+/g, "-").replace(/^[-_]+|-+$/g, "") || "unnamed";
66
66
  }
67
67
 
68
- // src/editor/core/palettes/oklch.ts
68
+ // src/system/internal/oklch.ts
69
69
  function srgbToLinear(c) {
70
70
  return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
71
71
  }
72
- function linearToSrgb(c) {
73
- return c <= 31308e-7 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
74
- }
75
72
  function hexToLinearRgb(hex) {
76
73
  const r = parseInt(hex.slice(1, 3), 16) / 255;
77
74
  const g = parseInt(hex.slice(3, 5), 16) / 255;
78
75
  const b = parseInt(hex.slice(5, 7), 16) / 255;
79
76
  return [srgbToLinear(r), srgbToLinear(g), srgbToLinear(b)];
80
77
  }
81
- function linearRgbToHex(r, g, b) {
82
- const toHex = (c) => {
83
- const v = Math.round(Math.max(0, Math.min(1, linearToSrgb(c))) * 255);
84
- return v.toString(16).padStart(2, "0");
85
- };
86
- return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
87
- }
88
78
  function linearRgbToOklab(r, g, b) {
89
79
  const l_ = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
90
80
  const m_ = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
@@ -126,19 +116,10 @@ function hexToOklch(hex) {
126
116
  const [L, a, bVal] = linearRgbToOklab(r, g, b);
127
117
  return oklabToOklch(L, a, bVal);
128
118
  }
129
- function oklchToHex(l, c, h) {
130
- const [L, a, b] = oklchToOklab(l, c, h);
131
- const [r, g, bVal] = oklabToLinearRgb(L, a, b);
132
- return linearRgbToHex(r, g, bVal);
133
- }
134
119
  function isInGamut(r, g, b) {
135
120
  const eps = 1e-4;
136
121
  return r >= -eps && r <= 1 + eps && g >= -eps && g <= 1 + eps && b >= -eps && b <= 1 + eps;
137
122
  }
138
- function oklchToHexClamped(l, c, h) {
139
- const g = gamutClamp(l, c, h);
140
- return oklchToHex(g.l, g.c, g.h);
141
- }
142
123
  function gamutClamp(l, c, h) {
143
124
  if (l <= 0) return { l: 0, c: 0, h };
144
125
  if (l >= 1) return { l: 1, c: 0, h };
@@ -159,6 +140,31 @@ function gamutClamp(l, c, h) {
159
140
  }
160
141
  return { l, c: lo, h };
161
142
  }
143
+ function trim(value, decimals) {
144
+ return Number(value.toFixed(decimals)).toString();
145
+ }
146
+ function oklchToCss(l, c, h) {
147
+ const cs = trim(c, 4);
148
+ return `oklch(${trim(l, 4)} ${cs} ${cs === "0" ? "0" : trim(h, 2)})`;
149
+ }
150
+ function oklchToCssClamped(l, c, h) {
151
+ const g = gamutClamp(l, c, h);
152
+ return oklchToCss(g.l, g.c, g.h);
153
+ }
154
+ var OKLCH_RE = /^oklch\(\s*([\d.]+)(%?)\s+([\d.]+)(%?)\s+([\d.]+)(?:deg)?\s*\)$/i;
155
+ var HEX6_RE = /^#[0-9a-f]{6}$/i;
156
+ function parseOklchCss(value) {
157
+ const m = OKLCH_RE.exec(value.trim());
158
+ if (!m) return null;
159
+ const l = Number.parseFloat(m[1]) / (m[2] === "%" ? 100 : 1);
160
+ const c = Number.parseFloat(m[3]) * (m[4] === "%" ? 4e-3 : 1);
161
+ return { l, c, h: Number.parseFloat(m[5]) };
162
+ }
163
+ function cssColorToOklch(value) {
164
+ const raw = value.trim();
165
+ if (HEX6_RE.test(raw)) return hexToOklch(raw);
166
+ return parseOklchCss(raw);
167
+ }
162
168
 
163
169
  // src/editor/ui/curveEngine.ts
164
170
  function makeAnchor(x, y, tangentLen = 15) {
@@ -183,6 +189,15 @@ function tangentAnchor(x, y, prev, next) {
183
189
  const outDx = next ? (next.x - x) * HANDLE_SPAN : 0;
184
190
  return { x, y, inDx, inDy: m * inDx, outDx, outDy: m * outDx };
185
191
  }
192
+ function isCornerAnchor(a) {
193
+ return a.inDx === 0 && a.inDy === 0 && a.outDx === 0 && a.outDy === 0;
194
+ }
195
+ function resmoothAutoCurve(anchors) {
196
+ if (anchors.length < 2) return anchors;
197
+ return anchors.map(
198
+ (a, i) => isCornerAnchor(a) ? a : tangentAnchor(a.x, a.y, anchors[i - 1] ?? null, anchors[i + 1] ?? null)
199
+ );
200
+ }
186
201
  function evalBezier(p0x, p0y, c0x, c0y, c1x, c1y, p1x, p1y, t) {
187
202
  const u = 1 - t, u2 = u * u, u3 = u2 * u;
188
203
  const t2 = t * t, t3 = t2 * t;
@@ -278,37 +293,39 @@ var SCALES = [
278
293
  ];
279
294
  var BW_GUARD_MIN_L = 0.17;
280
295
  var BW_GUARD_MAX_L = 0.93;
281
- var DEFAULT_PALETTE_LIGHTNESS = () => [makeAnchor(0, 95, 5), makeAnchor(100, 8, 5)];
282
- var DEFAULT_PALETTE_SATURATION = () => [makeAnchor(0, 100, 30), makeAnchor(100, 100, 30)];
296
+ var autoCurve = (...anchors) => resmoothAutoCurve(anchors);
297
+ var DEFAULT_PALETTE_LIGHTNESS = () => autoCurve(makeAnchor(0, 95), makeAnchor(100, 8));
298
+ var DEFAULT_PALETTE_SATURATION = () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 100));
299
+ var wrapHue = (h) => (h % 360 + 360) % 360;
283
300
  function scaleCurveDefaults(scheme = "dark") {
284
301
  if (scheme === "light") {
285
302
  return {
286
303
  Surfaces: {
287
- lightness: () => [makeAnchor(0, 98, 5), makeAnchor(100, 82, 5)],
288
- saturation: () => [makeAnchor(0, 100, 30), makeAnchor(100, 100, 30)]
304
+ lightness: () => autoCurve(makeAnchor(0, 98), makeAnchor(100, 82)),
305
+ saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 100))
289
306
  },
290
307
  Borders: {
291
- lightness: () => [makeAnchor(0, 92, 5), makeAnchor(100, 45, 5)],
292
- saturation: () => [makeAnchor(0, 100, 30), makeAnchor(100, 100, 30)]
308
+ lightness: () => autoCurve(makeAnchor(0, 92), makeAnchor(100, 45)),
309
+ saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 100))
293
310
  },
294
311
  Text: {
295
- lightness: () => [makeAnchor(0, 30, 30), makeAnchor(100, 120, 30)],
296
- saturation: () => [makeAnchor(0, 100, 30), makeAnchor(100, 15, 30)]
312
+ lightness: () => autoCurve(makeAnchor(0, 30), makeAnchor(100, 120)),
313
+ saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 15))
297
314
  }
298
315
  };
299
316
  }
300
317
  return {
301
318
  Surfaces: {
302
- lightness: () => [makeAnchor(0, 15, 5), makeAnchor(100, 47, 5)],
303
- saturation: () => [makeAnchor(0, 100, 30), makeAnchor(100, 100, 30)]
319
+ lightness: () => autoCurve(makeAnchor(0, 15), makeAnchor(100, 47)),
320
+ saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 100))
304
321
  },
305
322
  Borders: {
306
- lightness: () => [makeAnchor(0, 25, 5), makeAnchor(100, 80, 5)],
307
- saturation: () => [makeAnchor(0, 100, 30), makeAnchor(100, 100, 30)]
323
+ lightness: () => autoCurve(makeAnchor(0, 25), makeAnchor(100, 80)),
324
+ saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 100))
308
325
  },
309
326
  Text: {
310
- lightness: () => [makeAnchor(0, 120, 30), makeAnchor(100, 55, 30)],
311
- saturation: () => [makeAnchor(0, 100, 30), makeAnchor(100, 15, 30)]
327
+ lightness: () => autoCurve(makeAnchor(0, 120), makeAnchor(100, 55)),
328
+ saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 15))
312
329
  }
313
330
  };
314
331
  }
@@ -327,14 +344,16 @@ function scaleStepToX(step, scale) {
327
344
  return scale.steps.length > 1 ? idx / (scale.steps.length - 1) * 100 : 50;
328
345
  }
329
346
  function serializeDerivedValue(value) {
330
- return value.kind === "raw" ? value.css : oklchToHexClamped(value.l, value.c, value.h);
347
+ return value.kind === "raw" ? value.css : oklchToCssClamped(value.l, value.c, value.h);
331
348
  }
332
- function computePaletteOklch(index, base, lightnessCurve, saturationCurve, curveOffset) {
333
- const { c: baseC, h } = base;
349
+ function computePaletteOklch(index, base, lightnessCurve, saturationCurve, curveOffset, hueCurve) {
350
+ const { c: baseC } = base;
334
351
  const xPos = stepIndexToX(index);
335
352
  const targetL = Math.max(0, Math.min(100, sampleCurve(lightnessCurve, xPos) + (curveOffset.lightness ?? 0))) / 100;
336
353
  const satMul = Math.max(0, Math.min(2, (sampleCurve(saturationCurve, xPos) + (curveOffset.saturation ?? 0)) / 100));
337
354
  const targetC = baseC * satMul;
355
+ const hueDelta = (hueCurve ? sampleCurve(hueCurve, xPos) : 0) + (curveOffset.hue ?? 0);
356
+ const h = hueDelta === 0 ? base.h : wrapHue(base.h + hueDelta);
338
357
  return gamutClamp(targetL, targetC, h);
339
358
  }
340
359
  function nearestPaletteStep(lightnessCurve, baseL) {
@@ -430,10 +449,12 @@ function syncBaseAnchor(cfg) {
430
449
  const fresh = prev === void 0;
431
450
  let lCurve = cfg.lightnessCurve;
432
451
  let sCurve = cfg.saturationCurve;
452
+ let hCurve = cfg.hueCurve;
433
453
  if (prev) {
434
454
  const prevX = stepIndexToX(prev.step);
435
455
  lCurve = liftCurveAnchor(lCurve, prevX, prev.displacedL);
436
456
  sCurve = liftCurveAnchor(sCurve, prevX, prev.displacedS);
457
+ if (hCurve) hCurve = liftCurveAnchor(hCurve, prevX, prev.displacedH);
437
458
  }
438
459
  const step = nearestPaletteStep(lCurve, cfg.baseColor.l);
439
460
  const x = stepIndexToX(step);
@@ -441,12 +462,19 @@ function syncBaseAnchor(cfg) {
441
462
  const s = setCurveAnchor(sCurve, x, 100, fresh);
442
463
  cfg.lightnessCurve = l.curve;
443
464
  cfg.saturationCurve = s.curve;
465
+ const h = hCurve ? setCurveAnchor(hCurve, x, 0, fresh) : void 0;
466
+ if (h) cfg.hueCurve = h.curve;
444
467
  cfg.anchorPlacement = {
445
468
  step,
446
469
  displacedL: l.displacedY,
447
470
  displacedS: s.displacedY,
471
+ displacedH: h?.displacedY,
448
472
  priorLightnessEndpoints: prev?.priorLightnessEndpoints ?? l.priorEndpoints,
449
- priorSaturationEndpoints: prev?.priorSaturationEndpoints ?? s.priorEndpoints
473
+ priorSaturationEndpoints: prev?.priorSaturationEndpoints ?? s.priorEndpoints,
474
+ // No else-branch reading `prev?.priorHueEndpoints`: that could only fire
475
+ // if a placed hue curve later went absent, which RJC 7 (reset never
476
+ // deletes) never lets happen.
477
+ priorHueEndpoints: h ? prev?.priorHueEndpoints ?? h.priorEndpoints : void 0
450
478
  };
451
479
  }
452
480
  function computeDerivedOklch(step, base, scaleTitle, scaleCurves, curveOffset) {
@@ -455,8 +483,10 @@ function computeDerivedOklch(step, base, scaleTitle, scaleCurves, curveOffset) {
455
483
  const defs = defaultScaleCurves[scaleTitle];
456
484
  const lCurve = scaleCurves[scaleTitle]?.lightness ?? defs.lightness();
457
485
  const sCurve = scaleCurves[scaleTitle]?.saturation ?? defs.saturation();
486
+ const hCurve = scaleCurves[scaleTitle]?.hue;
458
487
  const lOff = curveOffset[`${scaleTitle}-lightness`] ?? 0;
459
488
  const sOff = curveOffset[`${scaleTitle}-saturation`] ?? 0;
489
+ const hOff = curveOffset[`${scaleTitle}-hue`] ?? 0;
460
490
  const { l: baseL, c: baseC, h: baseH } = base;
461
491
  let targetL;
462
492
  if (scale.isText) {
@@ -467,7 +497,9 @@ function computeDerivedOklch(step, base, scaleTitle, scaleCurves, curveOffset) {
467
497
  }
468
498
  const satMul = Math.max(0, Math.min(2, (sampleCurve(sCurve, xPos) + sOff) / 100));
469
499
  const targetC = baseC * satMul;
470
- return gamutClamp(targetL, targetC, baseH);
500
+ const hueDelta = (hCurve ? sampleCurve(hCurve, xPos) : 0) + hOff;
501
+ const targetH = hueDelta === 0 ? baseH : wrapHue(baseH + hueDelta);
502
+ return gamutClamp(targetL, targetC, targetH);
471
503
  }
472
504
  function scaleToCssVar(scaleTitle, stepName, cssNamespace) {
473
505
  if (cssNamespace === null) return null;
@@ -496,7 +528,7 @@ function derivePaletteValues(spec, config) {
496
528
  const saturationCurve = config.saturationCurve ?? DEFAULT_PALETTE_SATURATION();
497
529
  PALETTE_STEPS.forEach((ps, index) => {
498
530
  const k = paletteStepKey(ps.label);
499
- const value = k in overrides ? { kind: "color", ...overrides[k] } : { kind: "color", ...computePaletteOklch(index, baseColor, lightnessCurve, saturationCurve, curveOffset) };
531
+ const value = k in overrides ? { kind: "color", ...overrides[k] } : { kind: "color", ...computePaletteOklch(index, baseColor, lightnessCurve, saturationCurve, curveOffset, config.hueCurve) };
500
532
  out[`--color-${spec.cssNamespace}-${ps.label}`] = value;
501
533
  });
502
534
  for (const scale of SCALES) {
@@ -531,8 +563,8 @@ function derivePaletteValues(spec, config) {
531
563
  );
532
564
  const stopsCss = sortedStops.map((s) => {
533
565
  const stopValue = out[`--color-${spec.cssNamespace}-${s.paletteLabel}`];
534
- const hex = stopValue ? serializeDerivedValue(stopValue) : "#000000";
535
- return `${hex} ${s.position}%`;
566
+ const css = stopValue ? serializeDerivedValue(stopValue) : "oklch(0 0 0)";
567
+ return `${css} ${s.position}%`;
536
568
  }).join(", ");
537
569
  let gradient;
538
570
  switch (gradientStyle) {
@@ -551,13 +583,6 @@ function derivePaletteValues(spec, config) {
551
583
  }
552
584
  return out;
553
585
  }
554
- function derivePaletteVars(spec, config) {
555
- const out = {};
556
- for (const [k, v] of Object.entries(derivePaletteValues(spec, config))) {
557
- out[k] = serializeDerivedValue(v);
558
- }
559
- return out;
560
- }
561
586
  function palettesToValues(palettes) {
562
587
  const out = {};
563
588
  for (const spec of PALETTE_SPECS) {
@@ -572,7 +597,6 @@ function palettesToVars(palettes) {
572
597
  }
573
598
  return out;
574
599
  }
575
- var HEX_RE = /^#[0-9a-f]{6}$/i;
576
600
  function reconcilePalettesFromCssVars(palettes, cssVars) {
577
601
  const next = structuredClone(palettes);
578
602
  const consumed = /* @__PURE__ */ new Set();
@@ -581,16 +605,17 @@ function reconcilePalettesFromCssVars(palettes, cssVars) {
581
605
  const current = next[spec.label];
582
606
  if (current === void 0) continue;
583
607
  if (current._imported === true) {
584
- const anchorHex = cssVars[`--color-${spec.cssNamespace}-500`];
585
- if (anchorHex && HEX_RE.test(anchorHex.trim())) {
586
- next[spec.label] = { ...current, baseColor: hexToOklch(anchorHex.trim()), _imported: false };
608
+ const anchor = cssVars[`--color-${spec.cssNamespace}-500`];
609
+ const anchorOklch = anchor ? cssColorToOklch(anchor) : null;
610
+ if (anchorOklch) {
611
+ next[spec.label] = { ...current, baseColor: anchorOklch, _imported: false };
587
612
  syncBaseAnchor(next[spec.label]);
588
613
  snapped.add(spec.label);
589
614
  } else {
590
615
  next[spec.label] = { ...current, _imported: false };
591
616
  }
592
617
  }
593
- for (const k of Object.keys(derivePaletteVars(spec, next[spec.label]))) {
618
+ for (const k of Object.keys(derivePaletteValues(spec, next[spec.label]))) {
594
619
  consumed.add(k);
595
620
  }
596
621
  }
@@ -1303,6 +1328,20 @@ var tokensCssMigration_2026_07_20_semanticTextStyles = {
1303
1328
  }
1304
1329
  };
1305
1330
 
1331
+ // vite-plugin/tokensCssMigrations/migrations/2026-08-19-oklch-color-values.ts
1332
+ var HEX_DECLARATION_RE = /(--[a-z0-9-]+:\s*)#([0-9a-f]{6})(?=\s*[;}])/gi;
1333
+ var tokensCssMigration_2026_08_19_oklchColorValues = {
1334
+ id: "2026-08-19-oklch-color-values",
1335
+ kind: "breaking",
1336
+ description: "Rewrite hex token values as oklch()",
1337
+ apply(css) {
1338
+ return css.replace(HEX_DECLARATION_RE, (_match, prefix, hex) => {
1339
+ const { l, c, h } = hexToOklch(`#${hex}`);
1340
+ return `${prefix}${oklchToCss(l, c, h)}`;
1341
+ });
1342
+ }
1343
+ };
1344
+
1306
1345
  // vite-plugin/tokensCssMigrations/index.ts
1307
1346
  var TOKENS_CSS_MIGRATIONS = [
1308
1347
  tokensCssMigration_2026_05_29_typographyScaleAdditions,
@@ -1311,7 +1350,8 @@ var TOKENS_CSS_MIGRATIONS = [
1311
1350
  tokensCssMigration_2026_06_04_removeDeadSizeIconScale,
1312
1351
  tokensCssMigration_2026_06_04_easingColorAndTypescaleAdditions,
1313
1352
  tokensCssMigration_2026_07_20_lineHeightRename,
1314
- tokensCssMigration_2026_07_20_semanticTextStyles
1353
+ tokensCssMigration_2026_07_20_semanticTextStyles,
1354
+ tokensCssMigration_2026_08_19_oklchColorValues
1315
1355
  ];
1316
1356
  function runTokensCssMigrations(css) {
1317
1357
  return foldMigrations(css, () => true);
@@ -1,9 +1,8 @@
1
1
  import {
2
- hexToOklch,
3
2
  palettesToVars,
4
3
  reconcilePalettesFromCssVars,
5
4
  sanitizeFileName
6
- } from "./chunk-76TFDTJO.js";
5
+ } from "./chunk-JIGIIE5P.js";
7
6
  import {
8
7
  THEME_SCHEMA_VERSION,
9
8
  detectLegacyLayout,
@@ -18,7 +17,10 @@ import {
18
17
  runAdditiveTokensCssMigrations,
19
18
  runTokensCssMigrations,
20
19
  validateTokensCss
21
- } from "./chunk-44RSTAII.js";
20
+ } from "./chunk-TKZBVIW5.js";
21
+ import {
22
+ hexToOklch
23
+ } from "./chunk-YR6GPXW2.js";
22
24
  import {
23
25
  resolveDataDirs
24
26
  } from "./chunk-D3ZVKOR4.js";
@@ -33,11 +33,21 @@ interface PaletteConfig {
33
33
  baseColor: Oklch;
34
34
  lightnessCurve: CurveAnchor[];
35
35
  saturationCurve: CurveAnchor[];
36
+ /** Signed hue offset in degrees per step, applied on top of the base hue.
37
+ * Absent means flat zero: the palette holds one hue, which is what every
38
+ * theme saved before this field did. */
39
+ hueCurve?: CurveAnchor[];
36
40
  scaleCurves: Record<string, {
37
41
  lightness: CurveAnchor[];
38
42
  saturation: CurveAnchor[];
43
+ hue?: CurveAnchor[];
39
44
  }>;
40
45
  curveOffset: Record<string, number>;
46
+ /** Per curve key: are the tangents derived from the points, or held by hand?
47
+ * Only an explicit switch-off is recorded. A missing key means the curve's own
48
+ * shape answers (`isAutoSmoothCurve`), which is what every theme saved before
49
+ * the flag existed relies on. */
50
+ curveAutoSmooth?: Record<string, boolean>;
41
51
  overrides: Record<string, Oklch>;
42
52
  snappedScales: string[];
43
53
  emptyMode?: 'solid' | 'gradient';
@@ -50,11 +60,12 @@ interface PaletteConfig {
50
60
  /**
51
61
  * Where the base color sits in the ramp while `anchorToBase` is on: the
52
62
  * PALETTE_STEPS index whose curve anchors are pinned to the base color
53
- * (lightness = base L, saturation = multiplier 100). `displacedL` /
54
- * `displacedS` remember the y of a pre-existing anchor (endpoint or
55
- * user-authored) the placement overwrote at that x, so moving the
56
- * placement or toggling off restores it instead of deleting it.
57
- * `priorLightnessEndpoints` / `priorSaturationEndpoints` remember the two
63
+ * (lightness = base L, saturation = multiplier 100, hue delta = 0 when a
64
+ * hue curve exists). `displacedL` / `displacedS` / `displacedH` remember
65
+ * the y of a pre-existing anchor (endpoint or user-authored) the placement
66
+ * overwrote at that x, so moving the placement or toggling off restores it
67
+ * instead of deleting it. `priorLightnessEndpoints` /
68
+ * `priorSaturationEndpoints` / `priorHueEndpoints` remember the two
58
69
  * endpoints exactly as they stood before the curve's first-ever placement
59
70
  * (a smoothed reshape, not algebraically invertible the way a later
60
71
  * scaled-handle re-placement is), so a clear can still restore the true
@@ -64,8 +75,10 @@ interface PaletteConfig {
64
75
  step: number;
65
76
  displacedL?: number;
66
77
  displacedS?: number;
78
+ displacedH?: number;
67
79
  priorLightnessEndpoints?: [CurveAnchor, CurveAnchor];
68
80
  priorSaturationEndpoints?: [CurveAnchor, CurveAnchor];
81
+ priorHueEndpoints?: [CurveAnchor, CurveAnchor];
69
82
  };
70
83
  /**
71
84
  * Set to true by importers when they overlay `cssVariables[--color-{ns}-*]`
@@ -33,11 +33,21 @@ interface PaletteConfig {
33
33
  baseColor: Oklch;
34
34
  lightnessCurve: CurveAnchor[];
35
35
  saturationCurve: CurveAnchor[];
36
+ /** Signed hue offset in degrees per step, applied on top of the base hue.
37
+ * Absent means flat zero: the palette holds one hue, which is what every
38
+ * theme saved before this field did. */
39
+ hueCurve?: CurveAnchor[];
36
40
  scaleCurves: Record<string, {
37
41
  lightness: CurveAnchor[];
38
42
  saturation: CurveAnchor[];
43
+ hue?: CurveAnchor[];
39
44
  }>;
40
45
  curveOffset: Record<string, number>;
46
+ /** Per curve key: are the tangents derived from the points, or held by hand?
47
+ * Only an explicit switch-off is recorded. A missing key means the curve's own
48
+ * shape answers (`isAutoSmoothCurve`), which is what every theme saved before
49
+ * the flag existed relies on. */
50
+ curveAutoSmooth?: Record<string, boolean>;
41
51
  overrides: Record<string, Oklch>;
42
52
  snappedScales: string[];
43
53
  emptyMode?: 'solid' | 'gradient';
@@ -50,11 +60,12 @@ interface PaletteConfig {
50
60
  /**
51
61
  * Where the base color sits in the ramp while `anchorToBase` is on: the
52
62
  * PALETTE_STEPS index whose curve anchors are pinned to the base color
53
- * (lightness = base L, saturation = multiplier 100). `displacedL` /
54
- * `displacedS` remember the y of a pre-existing anchor (endpoint or
55
- * user-authored) the placement overwrote at that x, so moving the
56
- * placement or toggling off restores it instead of deleting it.
57
- * `priorLightnessEndpoints` / `priorSaturationEndpoints` remember the two
63
+ * (lightness = base L, saturation = multiplier 100, hue delta = 0 when a
64
+ * hue curve exists). `displacedL` / `displacedS` / `displacedH` remember
65
+ * the y of a pre-existing anchor (endpoint or user-authored) the placement
66
+ * overwrote at that x, so moving the placement or toggling off restores it
67
+ * instead of deleting it. `priorLightnessEndpoints` /
68
+ * `priorSaturationEndpoints` / `priorHueEndpoints` remember the two
58
69
  * endpoints exactly as they stood before the curve's first-ever placement
59
70
  * (a smoothed reshape, not algebraically invertible the way a later
60
71
  * scaled-handle re-placement is), so a clear can still restore the true
@@ -64,8 +75,10 @@ interface PaletteConfig {
64
75
  step: number;
65
76
  displacedL?: number;
66
77
  displacedS?: number;
78
+ displacedH?: number;
67
79
  priorLightnessEndpoints?: [CurveAnchor, CurveAnchor];
68
80
  priorSaturationEndpoints?: [CurveAnchor, CurveAnchor];
81
+ priorHueEndpoints?: [CurveAnchor, CurveAnchor];
69
82
  };
70
83
  /**
71
84
  * Set to true by importers when they overlay `cssVariables[--color-{ns}-*]`
@@ -33,6 +33,7 @@ __export(tokensCssMigrations_exports, {
33
33
  TOKENS_CSS_MIGRATIONS: () => TOKENS_CSS_MIGRATIONS,
34
34
  collectDefinedTokens: () => collectDefinedTokens,
35
35
  collectReferencedTokens: () => collectReferencedTokens,
36
+ collectTokenValues: () => collectTokenValues,
36
37
  enforceBreakingRequiresMajor: () => enforceBreakingRequiresMajor,
37
38
  ensureScale: () => ensureScale,
38
39
  findContractViolations: () => findContractViolations,
@@ -61,11 +62,17 @@ function extractGlobalRootBody(source) {
61
62
  // vite-plugin/tokensCssMigrations/cssTokenOps.ts
62
63
  var DECL_RE = /(^|[\s;{])(--[a-z0-9-]+)\s*:/gi;
63
64
  var REF_RE = /var\(\s*(--[a-z0-9-]+)/gi;
65
+ var DECL_VALUE_RE = /(^|[\s;{])(--[a-z0-9-]+)\s*:([^;}]*)/gi;
64
66
  function collectDefinedTokens(css) {
65
67
  const out = /* @__PURE__ */ new Set();
66
68
  for (const m of css.matchAll(DECL_RE)) out.add(m[2]);
67
69
  return out;
68
70
  }
71
+ function collectTokenValues(css) {
72
+ const out = /* @__PURE__ */ new Map();
73
+ for (const m of css.matchAll(DECL_VALUE_RE)) out.set(m[2], m[3].trim());
74
+ return out;
75
+ }
69
76
  function collectReferencedTokens(css) {
70
77
  const out = /* @__PURE__ */ new Set();
71
78
  for (const m of css.matchAll(REF_RE)) out.add(m[1]);
@@ -399,6 +406,62 @@ var tokensCssMigration_2026_07_20_semanticTextStyles = {
399
406
  }
400
407
  };
401
408
 
409
+ // src/system/internal/oklch.ts
410
+ function srgbToLinear(c) {
411
+ return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
412
+ }
413
+ function hexToLinearRgb(hex) {
414
+ const r = parseInt(hex.slice(1, 3), 16) / 255;
415
+ const g = parseInt(hex.slice(3, 5), 16) / 255;
416
+ const b = parseInt(hex.slice(5, 7), 16) / 255;
417
+ return [srgbToLinear(r), srgbToLinear(g), srgbToLinear(b)];
418
+ }
419
+ function linearRgbToOklab(r, g, b) {
420
+ const l_ = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
421
+ const m_ = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
422
+ const s_ = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
423
+ const l = Math.cbrt(l_);
424
+ const m = Math.cbrt(m_);
425
+ const s = Math.cbrt(s_);
426
+ return [
427
+ 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,
428
+ 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,
429
+ 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s
430
+ ];
431
+ }
432
+ function oklabToOklch(L, a, b) {
433
+ const c = Math.sqrt(a * a + b * b);
434
+ let h = Math.atan2(b, a) * 180 / Math.PI;
435
+ if (h < 0) h += 360;
436
+ return { l: L, c, h };
437
+ }
438
+ function hexToOklch(hex) {
439
+ const [r, g, b] = hexToLinearRgb(hex);
440
+ const [L, a, bVal] = linearRgbToOklab(r, g, b);
441
+ return oklabToOklch(L, a, bVal);
442
+ }
443
+ function trim(value, decimals) {
444
+ return Number(value.toFixed(decimals)).toString();
445
+ }
446
+ function oklchToCss(l, c, h) {
447
+ const cs = trim(c, 4);
448
+ return `oklch(${trim(l, 4)} ${cs} ${cs === "0" ? "0" : trim(h, 2)})`;
449
+ }
450
+
451
+ // vite-plugin/tokensCssMigrations/migrations/2026-08-19-oklch-color-values.ts
452
+ var HEX_DECLARATION_RE = /(--[a-z0-9-]+:\s*)#([0-9a-f]{6})(?=\s*[;}])/gi;
453
+ var tokensCssMigration_2026_08_19_oklchColorValues = {
454
+ id: "2026-08-19-oklch-color-values",
455
+ kind: "breaking",
456
+ description: "Rewrite hex token values as oklch()",
457
+ apply(css) {
458
+ return css.replace(HEX_DECLARATION_RE, (_match, prefix, hex) => {
459
+ const { l, c, h } = hexToOklch(`#${hex}`);
460
+ return `${prefix}${oklchToCss(l, c, h)}`;
461
+ });
462
+ }
463
+ };
464
+
402
465
  // vite-plugin/files/dataPaths.ts
403
466
  var import_fs = __toESM(require("fs"), 1);
404
467
  var import_path = __toESM(require("path"), 1);
@@ -441,7 +504,8 @@ var TOKENS_CSS_MIGRATIONS = [
441
504
  tokensCssMigration_2026_06_04_removeDeadSizeIconScale,
442
505
  tokensCssMigration_2026_06_04_easingColorAndTypescaleAdditions,
443
506
  tokensCssMigration_2026_07_20_lineHeightRename,
444
- tokensCssMigration_2026_07_20_semanticTextStyles
507
+ tokensCssMigration_2026_07_20_semanticTextStyles,
508
+ tokensCssMigration_2026_08_19_oklchColorValues
445
509
  ];
446
510
  function runTokensCssMigrations(css) {
447
511
  return foldMigrations(css, () => true);
@@ -466,10 +530,11 @@ function findContractViolations(canonicalCss) {
466
530
  const violations = [];
467
531
  for (const m of TOKENS_CSS_MIGRATIONS) {
468
532
  if (m.kind !== "additive") continue;
469
- const before = collectDefinedTokens(canonicalCss);
470
- const after = collectDefinedTokens(m.apply(canonicalCss));
471
- const removed = [...before].filter((t) => !after.has(t)).sort();
472
- if (removed.length) violations.push({ id: m.id, removed });
533
+ const before = collectTokenValues(canonicalCss);
534
+ const after = collectTokenValues(m.apply(canonicalCss));
535
+ const removed = [...before.keys()].filter((t) => !after.has(t)).sort();
536
+ const changed = [...before.entries()].filter(([t, v]) => after.has(t) && after.get(t) !== v).map(([t]) => t).sort();
537
+ if (removed.length || changed.length) violations.push({ id: m.id, removed, changed });
473
538
  }
474
539
  return violations;
475
540
  }
@@ -530,6 +595,7 @@ function validateTokensCss(input) {
530
595
  TOKENS_CSS_MIGRATIONS,
531
596
  collectDefinedTokens,
532
597
  collectReferencedTokens,
598
+ collectTokenValues,
533
599
  enforceBreakingRequiresMajor,
534
600
  ensureScale,
535
601
  findContractViolations,
@@ -52,6 +52,8 @@ interface TokensCssMigration {
52
52
  */
53
53
  /** Names declared as custom properties (`--x: …;`) anywhere in the source. */
54
54
  declare function collectDefinedTokens(css: string): Set<string>;
55
+ /** Declared name → value, last declaration winning (as the cascade would). */
56
+ declare function collectTokenValues(css: string): Map<string, string>;
55
57
  /** Names referenced via `var(--x)` anywhere in the source. */
56
58
  declare function collectReferencedTokens(css: string): Set<string>;
57
59
  interface ScaleEntry {
@@ -123,16 +125,25 @@ interface ContractViolation {
123
125
  id: string;
124
126
  /** Token names the migration removed or renamed away despite declaring `additive`. */
125
127
  removed: string[];
128
+ /** Token names whose value the migration rewrote despite declaring `additive`. */
129
+ changed: string[];
126
130
  }
127
131
  /**
128
- * Guardrail for the token-as-API contract: an `additive` migration must never
129
- * remove or rename a token. We verify behaviorally rather than trusting the
130
- * label — apply each additive migration to the package's own canonical
131
- * `tokens.css` (which defines the full current vocabulary) and flag any token
132
- * that disappears. A rename surfaces as the removal of its old name, so it is
133
- * caught too. This catches the dangerous direction: a breaking change shipped as
134
- * a backward-compatible one. (Over-labeling a no-op as `breaking` is harmless
135
- * and not checked.)
132
+ * Guardrail for the token-as-API contract: an `additive` migration must only
133
+ * ever insert new names — it must never remove or rename a token, and never
134
+ * rewrite the value of one a consumer already references. We verify
135
+ * behaviorally rather than trusting the label: apply each additive migration to
136
+ * the package's own canonical `tokens.css` (which defines the full current
137
+ * vocabulary) and flag any token that disappears or changes value. A rename
138
+ * surfaces as the removal of its old name, so it is caught too.
139
+ *
140
+ * The value half is what makes a value-rewriting migration (hex → `oklch()`)
141
+ * impossible to mislabel: it renames nothing, so a name-only guard would wave
142
+ * it through as additive and the dev plugin would auto-apply a breaking change
143
+ * to a consumer's vendored file.
144
+ *
145
+ * This catches the dangerous direction only. (Over-labeling a no-op as
146
+ * `breaking` is harmless and not checked.)
136
147
  */
137
148
  declare function findContractViolations(canonicalCss: string): ContractViolation[];
138
149
  type SemverBump = 'major' | 'minor' | 'patch' | 'none';
@@ -183,4 +194,4 @@ interface ValidateInput {
183
194
  */
184
195
  declare function validateTokensCss(input: ValidateInput): MissingToken[];
185
196
 
186
- export { type BreakingGateResult, type ComponentSource, type ContractViolation, type MissingToken, type RunResult, type SemverBump, TOKENS_CSS_MIGRATIONS, type TokensCssMigration, type ValidateInput, collectDefinedTokens, collectReferencedTokens, enforceBreakingRequiresMajor, ensureScale, findContractViolations, removeToken, removeTokensMatching, renameToken, runAdditiveTokensCssMigrations, runTokensCssMigrations, semverBumpType, validateTokensCss };
197
+ export { type BreakingGateResult, type ComponentSource, type ContractViolation, type MissingToken, type RunResult, type SemverBump, TOKENS_CSS_MIGRATIONS, type TokensCssMigration, type ValidateInput, collectDefinedTokens, collectReferencedTokens, collectTokenValues, enforceBreakingRequiresMajor, ensureScale, findContractViolations, removeToken, removeTokensMatching, renameToken, runAdditiveTokensCssMigrations, runTokensCssMigrations, semverBumpType, validateTokensCss };