@motion-proto/live-tokens 0.50.0 → 0.53.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.
Files changed (91) hide show
  1. package/.claude/skills/live-tokens-adjust-shape-space/SKILL.md +7 -1
  2. package/CHANGELOG.md +108 -0
  3. package/bin/adjust.mjs +16 -39
  4. package/bin/generate-theme.mjs +20 -6
  5. package/dist-plugin/adjust/index.cjs +781 -21
  6. package/dist-plugin/adjust/index.d.cts +2 -1
  7. package/dist-plugin/adjust/index.d.ts +2 -1
  8. package/dist-plugin/adjust/index.js +43 -21
  9. package/dist-plugin/{chunk-6OZFXIQI.js → chunk-232GZGQU.js} +207 -12
  10. package/dist-plugin/chunk-NE6N66EE.js +753 -0
  11. package/dist-plugin/{chunk-76TFDTJO.js → chunk-PB2JTK2H.js} +179 -128
  12. package/dist-plugin/{chunk-44RSTAII.js → chunk-TKZBVIW5.js} +33 -5
  13. package/dist-plugin/chunk-YR6GPXW2.js +129 -0
  14. package/dist-plugin/generateColorsAndType/index.cjs +135 -63
  15. package/dist-plugin/generateColorsAndType/index.d.cts +2 -1
  16. package/dist-plugin/generateColorsAndType/index.d.ts +2 -1
  17. package/dist-plugin/generateColorsAndType/index.js +28 -784
  18. package/dist-plugin/{themeTypes-DSwKq-bj.d.ts → index-DpTIRZ2H.d.cts} +67 -26
  19. package/dist-plugin/{themeTypes-DSwKq-bj.d.cts → index-DpTIRZ2H.d.ts} +67 -26
  20. package/dist-plugin/index.cjs +1254 -140
  21. package/dist-plugin/index.js +106 -82
  22. package/dist-plugin/migrateData/index.cjs +956 -14
  23. package/dist-plugin/migrateData/index.js +10 -3
  24. package/dist-plugin/tokensCssMigrations/index.cjs +71 -5
  25. package/dist-plugin/tokensCssMigrations/index.d.cts +20 -9
  26. package/dist-plugin/tokensCssMigrations/index.d.ts +20 -9
  27. package/dist-plugin/tokensCssMigrations/index.js +4 -1
  28. package/package.json +8 -4
  29. package/src/editor/component-editor/NotificationEditor.svelte +6 -0
  30. package/src/editor/component-editor/scaffolding/ComponentFileManager.svelte +9 -23
  31. package/src/editor/component-editor/scaffolding/LinkedBlock.svelte +8 -8
  32. package/src/editor/core/components/adjustAliases.ts +49 -22
  33. package/src/editor/core/components/aliasKinds.ts +7 -2
  34. package/src/editor/core/components/componentConfigService.ts +1 -1
  35. package/src/editor/core/palettes/oklch.ts +3 -137
  36. package/src/editor/core/palettes/paletteDerivation.ts +79 -37
  37. package/src/editor/core/store/editorStore.ts +7 -197
  38. package/src/editor/core/store/editorTypes.ts +9 -30
  39. package/src/editor/core/themes/generateColorsAndType.ts +18 -8
  40. package/src/editor/core/themes/lookSummary.ts +3 -25
  41. package/src/editor/core/themes/migrateComponentConfig.ts +205 -0
  42. package/src/editor/core/themes/migrations/2026-05-19-sectiondivider-rich-gradient.ts +1 -1
  43. package/src/editor/core/themes/migrations/2026-05-20-sectiondivider-slim-variants.ts +1 -1
  44. package/src/editor/core/themes/migrations/2026-05-22-sectiondivider-intrinsics-to-css.ts +1 -1
  45. package/src/editor/core/themes/parsers/gradient.ts +211 -0
  46. package/src/editor/core/themes/slices/gradients.ts +5 -58
  47. package/src/editor/core/themes/themeService.ts +22 -9
  48. package/src/editor/core/themes/themeTypes.ts +89 -27
  49. package/src/editor/docs/content/editing-tokens.md +6 -2
  50. package/src/editor/docs/content/themes-workflow.md +9 -11
  51. package/src/editor/docs/content/where-themes-live.md +2 -2
  52. package/src/editor/docs/content.generated.ts +3 -3
  53. package/src/editor/index.ts +1 -0
  54. package/src/editor/styles/ui-editor.css +5 -2
  55. package/src/editor/ui/BezierCurveEditor.svelte +90 -67
  56. package/src/editor/ui/PaletteEditor.svelte +180 -59
  57. package/src/editor/ui/ThemePanel.svelte +24 -15
  58. package/src/editor/ui/Toggle.svelte +36 -24
  59. package/src/editor/ui/UIPillButton.svelte +1 -1
  60. package/src/editor/ui/UIReveal.svelte +47 -0
  61. package/src/editor/ui/UISquareButton.svelte +1 -1
  62. package/src/editor/ui/colors/ColorStory.svelte +12 -8
  63. package/src/editor/ui/colors/ColorsTab.svelte +4 -5
  64. package/src/editor/ui/curveEngine.ts +101 -21
  65. package/src/editor/ui/palette/OverridesPanel.svelte +23 -8
  66. package/src/editor/ui/palette/PaletteBase.svelte +17 -78
  67. package/src/editor/ui/palette/PaletteJumpButton.svelte +3 -3
  68. package/src/editor/ui/palette/ScaleCurveEditor.svelte +110 -20
  69. package/src/editor/ui/palette/curveSummary.ts +20 -0
  70. package/src/editor/ui/palette/dockMagnify.ts +5 -13
  71. package/src/editor/ui/palette/paletteMath.ts +7 -4
  72. package/src/live-tokens/data/colors-and-type/autumn.json +528 -528
  73. package/src/live-tokens/data/colors-and-type/default.json +247 -247
  74. package/src/live-tokens/data/colors-and-type/halloween.json +532 -532
  75. package/src/live-tokens/data/colors-and-type/midnight-study.json +538 -538
  76. package/src/live-tokens/data/colors-and-type/ocean.json +521 -521
  77. package/src/live-tokens/data/colors-and-type/royal-velvet.json +532 -532
  78. package/src/live-tokens/data/colors-and-type/spring-meadow.json +504 -504
  79. package/src/live-tokens/data/colors-and-type/sunset.json +531 -531
  80. package/src/live-tokens/data/themes/autumn.json +604 -568
  81. package/src/live-tokens/data/themes/halloween.json +584 -583
  82. package/src/live-tokens/data/themes/midnight-study.json +673 -605
  83. package/src/live-tokens/data/themes/ocean.json +597 -561
  84. package/src/live-tokens/data/themes/royal-velvet.json +574 -573
  85. package/src/live-tokens/data/themes/spring-meadow.json +590 -556
  86. package/src/live-tokens/data/themes/sunset.json +632 -571
  87. package/src/live-tokens/data/tokens.generated.css +282 -282
  88. package/src/system/components/FloatingTokenTags.css +0 -1
  89. package/src/system/internal/backgroundContrast.ts +7 -0
  90. package/src/system/internal/oklch.ts +189 -0
  91. package/src/system/styles/tokens.css +283 -283
@@ -0,0 +1,189 @@
1
+ // OKLCH color space conversions — hand-rolled, no dependencies
2
+ // Pipeline: sRGB hex → linear RGB → OKLab (via M1×M2 + cube root) → OKLCH (polar)
3
+
4
+ export interface Oklch {
5
+ l: number; // 0..1
6
+ c: number; // 0..~0.4
7
+ h: number; // 0..360
8
+ }
9
+
10
+ // --- sRGB gamma ---
11
+
12
+ function srgbToLinear(c: number): number {
13
+ return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
14
+ }
15
+
16
+ function linearToSrgb(c: number): number {
17
+ return c <= 0.0031308 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
18
+ }
19
+
20
+ // --- Hex ↔ linear RGB ---
21
+
22
+ function hexToLinearRgb(hex: string): [number, number, number] {
23
+ const r = parseInt(hex.slice(1, 3), 16) / 255;
24
+ const g = parseInt(hex.slice(3, 5), 16) / 255;
25
+ const b = parseInt(hex.slice(5, 7), 16) / 255;
26
+ return [srgbToLinear(r), srgbToLinear(g), srgbToLinear(b)];
27
+ }
28
+
29
+ function linearRgbToHex(r: number, g: number, b: number): string {
30
+ const toHex = (c: number) => {
31
+ const v = Math.round(Math.max(0, Math.min(1, linearToSrgb(c))) * 255);
32
+ return v.toString(16).padStart(2, '0');
33
+ };
34
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
35
+ }
36
+
37
+ // --- Linear RGB ↔ OKLab ---
38
+ // Uses the two-matrix approach from Björn Ottosson's blog
39
+
40
+ function linearRgbToOklab(r: number, g: number, b: number): [number, number, number] {
41
+ const l_ = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
42
+ const m_ = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
43
+ const s_ = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
44
+
45
+ const l = Math.cbrt(l_);
46
+ const m = Math.cbrt(m_);
47
+ const s = Math.cbrt(s_);
48
+
49
+ return [
50
+ 0.2104542553 * l + 0.7936177850 * m - 0.0040720468 * s,
51
+ 1.9779984951 * l - 2.4285922050 * m + 0.4505937099 * s,
52
+ 0.0259040371 * l + 0.7827717662 * m - 0.8086757660 * s,
53
+ ];
54
+ }
55
+
56
+ function oklabToLinearRgb(L: number, a: number, b: number): [number, number, number] {
57
+ const l_ = L + 0.3963377774 * a + 0.2158037573 * b;
58
+ const m_ = L - 0.1055613458 * a - 0.0638541728 * b;
59
+ const s_ = L - 0.0894841775 * a - 1.2914855480 * b;
60
+
61
+ const l = l_ * l_ * l_;
62
+ const m = m_ * m_ * m_;
63
+ const s = s_ * s_ * s_;
64
+
65
+ return [
66
+ +4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
67
+ -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
68
+ -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s,
69
+ ];
70
+ }
71
+
72
+ // --- OKLab ↔ OKLCH ---
73
+
74
+ function oklabToOklch(L: number, a: number, b: number): Oklch {
75
+ const c = Math.sqrt(a * a + b * b);
76
+ let h = (Math.atan2(b, a) * 180) / Math.PI;
77
+ if (h < 0) h += 360;
78
+ return { l: L, c, h };
79
+ }
80
+
81
+ function oklchToOklab(l: number, c: number, h: number): [number, number, number] {
82
+ const hRad = (h * Math.PI) / 180;
83
+ return [l, c * Math.cos(hRad), c * Math.sin(hRad)];
84
+ }
85
+
86
+ // --- Public API ---
87
+
88
+ export function hexToOklch(hex: string): Oklch {
89
+ const [r, g, b] = hexToLinearRgb(hex);
90
+ const [L, a, bVal] = linearRgbToOklab(r, g, b);
91
+ return oklabToOklch(L, a, bVal);
92
+ }
93
+
94
+ export function oklchToHex(l: number, c: number, h: number): string {
95
+ const [L, a, b] = oklchToOklab(l, c, h);
96
+ const [r, g, bVal] = oklabToLinearRgb(L, a, b);
97
+ return linearRgbToHex(r, g, bVal);
98
+ }
99
+
100
+ function isInGamut(r: number, g: number, b: number): boolean {
101
+ const eps = 0.0001;
102
+ return r >= -eps && r <= 1 + eps && g >= -eps && g <= 1 + eps && b >= -eps && b <= 1 + eps;
103
+ }
104
+
105
+ /** The clamped sRGB projection: reduce chroma into gamut, then serialize to hex.
106
+ * This is the correct projection for unclamped stored intent — naive
107
+ * `oklchToHex` per-channel clips (shifting hue), this preserves hue and L. */
108
+ export function oklchToHexClamped(l: number, c: number, h: number): string {
109
+ const g = gamutClamp(l, c, h);
110
+ return oklchToHex(g.l, g.c, g.h);
111
+ }
112
+
113
+ export function gamutClamp(l: number, c: number, h: number): Oklch {
114
+ // Clamp lightness
115
+ if (l <= 0) return { l: 0, c: 0, h };
116
+ if (l >= 1) return { l: 1, c: 0, h };
117
+
118
+ // Binary search: reduce chroma until in sRGB gamut
119
+ const [L, a, b] = oklchToOklab(l, c, h);
120
+ const [r, g, bVal] = oklabToLinearRgb(L, a, b);
121
+
122
+ if (isInGamut(r, g, bVal)) return { l, c, h };
123
+
124
+ let lo = 0;
125
+ let hi = c;
126
+ for (let i = 0; i < 20; i++) {
127
+ const mid = (lo + hi) / 2;
128
+ const [La, aa, ba] = oklchToOklab(l, mid, h);
129
+ const [rr, gg, bb] = oklabToLinearRgb(La, aa, ba);
130
+ if (isInGamut(rr, gg, bb)) {
131
+ lo = mid;
132
+ } else {
133
+ hi = mid;
134
+ }
135
+ }
136
+ return { l, c: lo, h };
137
+ }
138
+
139
+ // --- CSS serialization + parsing ---
140
+
141
+ function trim(value: number, decimals: number): string {
142
+ return Number(value.toFixed(decimals)).toString();
143
+ }
144
+
145
+ export function oklchToCss(l: number, c: number, h: number): string {
146
+ const cs = trim(c, 4);
147
+ // Hue is meaningless without chroma, and the OKLab round trip leaves noise
148
+ // there (#ffffff lands on h≈89.88). Pin it so achromatic values read as
149
+ // achromatic instead of arbitrary.
150
+ return `oklch(${trim(l, 4)} ${cs} ${cs === '0' ? '0' : trim(h, 2)})`;
151
+ }
152
+
153
+ /** The clamped sRGB projection as an `oklch()` string — the CSS counterpart of
154
+ * `oklchToHexClamped`. Clamping keeps flip-day output visually identical to
155
+ * the hex it replaces; emitting unclamped (wide-gamut) values is a separate
156
+ * decision. */
157
+ export function oklchToCssClamped(l: number, c: number, h: number): string {
158
+ const g = gamutClamp(l, c, h);
159
+ return oklchToCss(g.l, g.c, g.h);
160
+ }
161
+
162
+ const OKLCH_RE = /^oklch\(\s*([\d.]+)(%?)\s+([\d.]+)(%?)\s+([\d.]+)(?:deg)?\s*\)$/i;
163
+ const HEX6_RE = /^#[0-9a-f]{6}$/i;
164
+
165
+ export function parseOklchCss(value: string): Oklch | null {
166
+ const m = OKLCH_RE.exec(value.trim());
167
+ if (!m) return null;
168
+ const l = Number.parseFloat(m[1]) / (m[2] === '%' ? 100 : 1);
169
+ // Percentage chroma is relative to 0.4 per the CSS Color 4 definition.
170
+ const c = Number.parseFloat(m[3]) * (m[4] === '%' ? 0.004 : 1);
171
+ return { l, c, h: Number.parseFloat(m[5]) };
172
+ }
173
+
174
+ /** Input boundary for color strings arriving from CSS: accepts the `oklch()`
175
+ * this system now emits and the 6-digit hex it emitted before the flip, so
176
+ * themes promoted either side of it still reconcile. */
177
+ export function cssColorToOklch(value: string): Oklch | null {
178
+ const raw = value.trim();
179
+ if (HEX6_RE.test(raw)) return hexToOklch(raw);
180
+ return parseOklchCss(raw);
181
+ }
182
+
183
+ export function oklchToRgb255(l: number, c: number, h: number): { r: number; g: number; b: number } {
184
+ const clamped = gamutClamp(l, c, h);
185
+ const [L, a, bVal] = oklchToOklab(clamped.l, clamped.c, clamped.h);
186
+ const [r, g, b] = oklabToLinearRgb(L, a, bVal);
187
+ const to255 = (channel: number) => Math.round(Math.max(0, Math.min(1, linearToSrgb(channel))) * 255);
188
+ return { r: to255(r), g: to255(g), b: to255(b) };
189
+ }