@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.
- package/.claude/skills/live-tokens-adjust-shape-space/SKILL.md +7 -1
- package/CHANGELOG.md +108 -0
- package/bin/adjust.mjs +16 -39
- package/bin/generate-theme.mjs +20 -6
- package/dist-plugin/adjust/index.cjs +781 -21
- package/dist-plugin/adjust/index.d.cts +2 -1
- package/dist-plugin/adjust/index.d.ts +2 -1
- package/dist-plugin/adjust/index.js +43 -21
- package/dist-plugin/{chunk-6OZFXIQI.js → chunk-232GZGQU.js} +207 -12
- package/dist-plugin/chunk-NE6N66EE.js +753 -0
- package/dist-plugin/{chunk-76TFDTJO.js → chunk-PB2JTK2H.js} +179 -128
- package/dist-plugin/{chunk-44RSTAII.js → chunk-TKZBVIW5.js} +33 -5
- package/dist-plugin/chunk-YR6GPXW2.js +129 -0
- package/dist-plugin/generateColorsAndType/index.cjs +135 -63
- package/dist-plugin/generateColorsAndType/index.d.cts +2 -1
- package/dist-plugin/generateColorsAndType/index.d.ts +2 -1
- package/dist-plugin/generateColorsAndType/index.js +28 -784
- package/dist-plugin/{themeTypes-DSwKq-bj.d.ts → index-DpTIRZ2H.d.cts} +67 -26
- package/dist-plugin/{themeTypes-DSwKq-bj.d.cts → index-DpTIRZ2H.d.ts} +67 -26
- package/dist-plugin/index.cjs +1254 -140
- package/dist-plugin/index.js +106 -82
- package/dist-plugin/migrateData/index.cjs +956 -14
- package/dist-plugin/migrateData/index.js +10 -3
- package/dist-plugin/tokensCssMigrations/index.cjs +71 -5
- package/dist-plugin/tokensCssMigrations/index.d.cts +20 -9
- package/dist-plugin/tokensCssMigrations/index.d.ts +20 -9
- package/dist-plugin/tokensCssMigrations/index.js +4 -1
- package/package.json +8 -4
- package/src/editor/component-editor/NotificationEditor.svelte +6 -0
- package/src/editor/component-editor/scaffolding/ComponentFileManager.svelte +9 -23
- package/src/editor/component-editor/scaffolding/LinkedBlock.svelte +8 -8
- package/src/editor/core/components/adjustAliases.ts +49 -22
- package/src/editor/core/components/aliasKinds.ts +7 -2
- package/src/editor/core/components/componentConfigService.ts +1 -1
- package/src/editor/core/palettes/oklch.ts +3 -137
- package/src/editor/core/palettes/paletteDerivation.ts +79 -37
- package/src/editor/core/store/editorStore.ts +7 -197
- package/src/editor/core/store/editorTypes.ts +9 -30
- package/src/editor/core/themes/generateColorsAndType.ts +18 -8
- package/src/editor/core/themes/lookSummary.ts +3 -25
- package/src/editor/core/themes/migrateComponentConfig.ts +205 -0
- package/src/editor/core/themes/migrations/2026-05-19-sectiondivider-rich-gradient.ts +1 -1
- package/src/editor/core/themes/migrations/2026-05-20-sectiondivider-slim-variants.ts +1 -1
- package/src/editor/core/themes/migrations/2026-05-22-sectiondivider-intrinsics-to-css.ts +1 -1
- package/src/editor/core/themes/parsers/gradient.ts +211 -0
- package/src/editor/core/themes/slices/gradients.ts +5 -58
- package/src/editor/core/themes/themeService.ts +22 -9
- package/src/editor/core/themes/themeTypes.ts +89 -27
- package/src/editor/docs/content/editing-tokens.md +6 -2
- package/src/editor/docs/content/themes-workflow.md +9 -11
- package/src/editor/docs/content/where-themes-live.md +2 -2
- package/src/editor/docs/content.generated.ts +3 -3
- package/src/editor/index.ts +1 -0
- package/src/editor/styles/ui-editor.css +5 -2
- package/src/editor/ui/BezierCurveEditor.svelte +90 -67
- package/src/editor/ui/PaletteEditor.svelte +180 -59
- package/src/editor/ui/ThemePanel.svelte +24 -15
- package/src/editor/ui/Toggle.svelte +36 -24
- package/src/editor/ui/UIPillButton.svelte +1 -1
- package/src/editor/ui/UIReveal.svelte +47 -0
- package/src/editor/ui/UISquareButton.svelte +1 -1
- package/src/editor/ui/colors/ColorStory.svelte +12 -8
- package/src/editor/ui/colors/ColorsTab.svelte +4 -5
- package/src/editor/ui/curveEngine.ts +101 -21
- package/src/editor/ui/palette/OverridesPanel.svelte +23 -8
- package/src/editor/ui/palette/PaletteBase.svelte +17 -78
- package/src/editor/ui/palette/PaletteJumpButton.svelte +3 -3
- package/src/editor/ui/palette/ScaleCurveEditor.svelte +110 -20
- package/src/editor/ui/palette/curveSummary.ts +20 -0
- package/src/editor/ui/palette/dockMagnify.ts +5 -13
- package/src/editor/ui/palette/paletteMath.ts +7 -4
- package/src/live-tokens/data/colors-and-type/autumn.json +528 -528
- package/src/live-tokens/data/colors-and-type/default.json +247 -247
- package/src/live-tokens/data/colors-and-type/halloween.json +532 -532
- package/src/live-tokens/data/colors-and-type/midnight-study.json +538 -538
- package/src/live-tokens/data/colors-and-type/ocean.json +521 -521
- package/src/live-tokens/data/colors-and-type/royal-velvet.json +532 -532
- package/src/live-tokens/data/colors-and-type/spring-meadow.json +504 -504
- package/src/live-tokens/data/colors-and-type/sunset.json +531 -531
- package/src/live-tokens/data/themes/autumn.json +604 -568
- package/src/live-tokens/data/themes/halloween.json +584 -583
- package/src/live-tokens/data/themes/midnight-study.json +673 -605
- package/src/live-tokens/data/themes/ocean.json +597 -561
- package/src/live-tokens/data/themes/royal-velvet.json +574 -573
- package/src/live-tokens/data/themes/spring-meadow.json +590 -556
- package/src/live-tokens/data/themes/sunset.json +632 -571
- package/src/live-tokens/data/tokens.generated.css +282 -282
- package/src/system/components/FloatingTokenTags.css +0 -1
- package/src/system/internal/backgroundContrast.ts +7 -0
- package/src/system/internal/oklch.ts +189 -0
- package/src/system/styles/tokens.css +283 -283
|
@@ -1,101 +1,132 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cssColorToOklch,
|
|
3
|
+
gamutClamp,
|
|
4
|
+
oklchToCssClamped
|
|
5
|
+
} from "./chunk-YR6GPXW2.js";
|
|
6
|
+
|
|
1
7
|
// src/editor/core/storage/files/versionedFileResourceClient.ts
|
|
2
8
|
function sanitizeFileName(name) {
|
|
3
9
|
return name.toLowerCase().trim().replace(/\s+/g, "-").replace(/[^a-z0-9\-_]/g, "").replace(/-+/g, "-").replace(/^[-_]+|-+$/g, "") || "unnamed";
|
|
4
10
|
}
|
|
5
11
|
|
|
6
|
-
// src/editor/core/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return
|
|
12
|
-
}
|
|
13
|
-
function
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
function
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
return
|
|
23
|
-
}
|
|
24
|
-
return
|
|
25
|
-
}
|
|
26
|
-
function
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
return
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
function
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const [r, g, bVal] = oklabToLinearRgb(L, a, b);
|
|
70
|
-
return linearRgbToHex(r, g, bVal);
|
|
71
|
-
}
|
|
72
|
-
function isInGamut(r, g, b) {
|
|
73
|
-
const eps = 1e-4;
|
|
74
|
-
return r >= -eps && r <= 1 + eps && g >= -eps && g <= 1 + eps && b >= -eps && b <= 1 + eps;
|
|
75
|
-
}
|
|
76
|
-
function oklchToHexClamped(l, c, h) {
|
|
77
|
-
const g = gamutClamp(l, c, h);
|
|
78
|
-
return oklchToHex(g.l, g.c, g.h);
|
|
79
|
-
}
|
|
80
|
-
function gamutClamp(l, c, h) {
|
|
81
|
-
if (l <= 0) return { l: 0, c: 0, h };
|
|
82
|
-
if (l >= 1) return { l: 1, c: 0, h };
|
|
83
|
-
const [L, a, b] = oklchToOklab(l, c, h);
|
|
84
|
-
const [r, g, bVal] = oklabToLinearRgb(L, a, b);
|
|
85
|
-
if (isInGamut(r, g, bVal)) return { l, c, h };
|
|
86
|
-
let lo = 0;
|
|
87
|
-
let hi = c;
|
|
88
|
-
for (let i = 0; i < 20; i++) {
|
|
89
|
-
const mid = (lo + hi) / 2;
|
|
90
|
-
const [La, aa, ba] = oklchToOklab(l, mid, h);
|
|
91
|
-
const [rr, gg, bb] = oklabToLinearRgb(La, aa, ba);
|
|
92
|
-
if (isInGamut(rr, gg, bb)) {
|
|
93
|
-
lo = mid;
|
|
94
|
-
} else {
|
|
95
|
-
hi = mid;
|
|
12
|
+
// src/editor/core/themes/parsers/colorOpacity.ts
|
|
13
|
+
var COLOR_OPACITY_RE = /^color-mix\(in srgb,\s*var\((--[a-z0-9-]+)\)\s+(\d+)%,\s*transparent\)$/i;
|
|
14
|
+
function parseColorOpacity(value) {
|
|
15
|
+
const m = value.trim().match(COLOR_OPACITY_RE);
|
|
16
|
+
if (!m) return null;
|
|
17
|
+
return { name: m[1], opacity: parseInt(m[2], 10) };
|
|
18
|
+
}
|
|
19
|
+
function formatColorOpacity(name, opacity) {
|
|
20
|
+
return `color-mix(in srgb, var(${name}) ${opacity}%, transparent)`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// src/editor/core/themes/parsers/gradient.ts
|
|
24
|
+
var RADIAL_BASE_PX = 100;
|
|
25
|
+
function formatStopColor(s) {
|
|
26
|
+
const opacity = s.opacity ?? 100;
|
|
27
|
+
if (s.color.startsWith("--")) {
|
|
28
|
+
return opacity >= 100 ? `var(${s.color})` : formatColorOpacity(s.color, opacity);
|
|
29
|
+
}
|
|
30
|
+
return opacity >= 100 ? s.color : `color-mix(in srgb, ${s.color} ${opacity}%, transparent)`;
|
|
31
|
+
}
|
|
32
|
+
function formatGradientStops(stops) {
|
|
33
|
+
return stops.map((s) => `${formatStopColor(s)} ${s.position}%`).join(", ");
|
|
34
|
+
}
|
|
35
|
+
function formatRadialShape(v) {
|
|
36
|
+
const ax = v.aspectX ?? 1;
|
|
37
|
+
const ay = v.aspectY ?? 1;
|
|
38
|
+
if (ax === 1 && ay === 1) {
|
|
39
|
+
return v.radius && v.radius > 0 ? `circle ${v.radius}px` : "circle";
|
|
40
|
+
}
|
|
41
|
+
const base = v.radius && v.radius > 0 ? v.radius : RADIAL_BASE_PX;
|
|
42
|
+
return `ellipse ${(base * ax).toFixed(2)}px ${(base * ay).toFixed(2)}px`;
|
|
43
|
+
}
|
|
44
|
+
function formatGradientValue(v) {
|
|
45
|
+
if (v.type === "none") return "transparent";
|
|
46
|
+
if (v.type === "solid") {
|
|
47
|
+
const first = v.stops[0];
|
|
48
|
+
return first ? formatStopColor(first) : "transparent";
|
|
49
|
+
}
|
|
50
|
+
const stops = formatGradientStops(v.stops);
|
|
51
|
+
if (v.type === "linear") return `linear-gradient(${v.angle}deg, ${stops})`;
|
|
52
|
+
return `radial-gradient(${formatRadialShape(v)} at ${v.centerX ?? 50}% 50%, ${stops})`;
|
|
53
|
+
}
|
|
54
|
+
var NUM = String.raw`-?\d+(?:\.\d+)?`;
|
|
55
|
+
var LINEAR_RE = new RegExp(String.raw`^linear-gradient\(\s*(${NUM})deg\s*,\s*(.+)\)$`, "i");
|
|
56
|
+
var RADIAL_RE = new RegExp(
|
|
57
|
+
String.raw`^radial-gradient\(\s*(circle|circle\s+${NUM}px|ellipse\s+${NUM}px\s+${NUM}px)\s+at\s+(${NUM})%\s+50%\s*,\s*(.+)\)$`,
|
|
58
|
+
"i"
|
|
59
|
+
);
|
|
60
|
+
var STOP_RE = new RegExp(String.raw`^(.*?)\s+(${NUM})%$`);
|
|
61
|
+
var CIRCLE_RADIUS_RE = new RegExp(String.raw`^circle\s+(${NUM})px$`, "i");
|
|
62
|
+
var ELLIPSE_RE = new RegExp(String.raw`^ellipse\s+(${NUM})px\s+(${NUM})px$`, "i");
|
|
63
|
+
var VAR_RE = /^var\((--[a-z0-9-]+)\)$/i;
|
|
64
|
+
function splitTopLevel(s) {
|
|
65
|
+
const parts = [];
|
|
66
|
+
let depth = 0;
|
|
67
|
+
let start = 0;
|
|
68
|
+
for (let i = 0; i < s.length; i++) {
|
|
69
|
+
const c = s[i];
|
|
70
|
+
if (c === "(") depth++;
|
|
71
|
+
else if (c === ")") depth--;
|
|
72
|
+
else if (c === "," && depth === 0) {
|
|
73
|
+
parts.push(s.slice(start, i));
|
|
74
|
+
start = i + 1;
|
|
96
75
|
}
|
|
97
76
|
}
|
|
98
|
-
|
|
77
|
+
parts.push(s.slice(start));
|
|
78
|
+
return parts;
|
|
79
|
+
}
|
|
80
|
+
function parseStop(raw) {
|
|
81
|
+
const m = raw.trim().match(STOP_RE);
|
|
82
|
+
if (!m) return null;
|
|
83
|
+
const position = parseFloat(m[2]);
|
|
84
|
+
const color = m[1].trim();
|
|
85
|
+
const opacity = parseColorOpacity(color);
|
|
86
|
+
if (opacity) return { position, color: opacity.name, opacity: opacity.opacity };
|
|
87
|
+
const token = color.match(VAR_RE);
|
|
88
|
+
return { position, color: token ? token[1] : color };
|
|
89
|
+
}
|
|
90
|
+
function parseStops(raw) {
|
|
91
|
+
const stops = [];
|
|
92
|
+
for (const part of splitTopLevel(raw)) {
|
|
93
|
+
const stop = parseStop(part);
|
|
94
|
+
if (!stop) return null;
|
|
95
|
+
stops.push(stop);
|
|
96
|
+
}
|
|
97
|
+
return stops.length > 0 ? stops : null;
|
|
98
|
+
}
|
|
99
|
+
function parseRadialShape(raw) {
|
|
100
|
+
const shape = raw.trim();
|
|
101
|
+
if (/^circle$/i.test(shape)) return {};
|
|
102
|
+
const circle = shape.match(CIRCLE_RADIUS_RE);
|
|
103
|
+
if (circle) return { radius: parseFloat(circle[1]) };
|
|
104
|
+
const ellipse = shape.match(ELLIPSE_RE);
|
|
105
|
+
if (!ellipse) return null;
|
|
106
|
+
const ax = parseFloat(ellipse[1]) / RADIAL_BASE_PX;
|
|
107
|
+
const ay = parseFloat(ellipse[2]) / RADIAL_BASE_PX;
|
|
108
|
+
return { ...ax === 1 ? {} : { aspectX: ax }, ...ay === 1 ? {} : { aspectY: ay } };
|
|
109
|
+
}
|
|
110
|
+
function parseGradientValue(value) {
|
|
111
|
+
const css = value.trim();
|
|
112
|
+
const linear = css.match(LINEAR_RE);
|
|
113
|
+
if (linear) {
|
|
114
|
+
const stops2 = parseStops(linear[2]);
|
|
115
|
+
return stops2 && { type: "linear", angle: parseFloat(linear[1]), stops: stops2 };
|
|
116
|
+
}
|
|
117
|
+
const radial = css.match(RADIAL_RE);
|
|
118
|
+
if (!radial) return null;
|
|
119
|
+
const shape = parseRadialShape(radial[1]);
|
|
120
|
+
const stops = parseStops(radial[3]);
|
|
121
|
+
if (!shape || !stops) return null;
|
|
122
|
+
const centerX = parseFloat(radial[2]);
|
|
123
|
+
return {
|
|
124
|
+
type: "radial",
|
|
125
|
+
angle: 0,
|
|
126
|
+
...shape,
|
|
127
|
+
...centerX === 50 ? {} : { centerX },
|
|
128
|
+
stops
|
|
129
|
+
};
|
|
99
130
|
}
|
|
100
131
|
|
|
101
132
|
// src/editor/ui/curveEngine.ts
|
|
@@ -121,6 +152,15 @@ function tangentAnchor(x, y, prev, next) {
|
|
|
121
152
|
const outDx = next ? (next.x - x) * HANDLE_SPAN : 0;
|
|
122
153
|
return { x, y, inDx, inDy: m * inDx, outDx, outDy: m * outDx };
|
|
123
154
|
}
|
|
155
|
+
function isCornerAnchor(a) {
|
|
156
|
+
return a.inDx === 0 && a.inDy === 0 && a.outDx === 0 && a.outDy === 0;
|
|
157
|
+
}
|
|
158
|
+
function resmoothAutoCurve(anchors) {
|
|
159
|
+
if (anchors.length < 2) return anchors;
|
|
160
|
+
return anchors.map(
|
|
161
|
+
(a, i) => isCornerAnchor(a) ? a : tangentAnchor(a.x, a.y, anchors[i - 1] ?? null, anchors[i + 1] ?? null)
|
|
162
|
+
);
|
|
163
|
+
}
|
|
124
164
|
function evalBezier(p0x, p0y, c0x, c0y, c1x, c1y, p1x, p1y, t) {
|
|
125
165
|
const u = 1 - t, u2 = u * u, u3 = u2 * u;
|
|
126
166
|
const t2 = t * t, t3 = t2 * t;
|
|
@@ -216,37 +256,39 @@ var SCALES = [
|
|
|
216
256
|
];
|
|
217
257
|
var BW_GUARD_MIN_L = 0.17;
|
|
218
258
|
var BW_GUARD_MAX_L = 0.93;
|
|
219
|
-
var
|
|
220
|
-
var
|
|
259
|
+
var autoCurve = (...anchors) => resmoothAutoCurve(anchors);
|
|
260
|
+
var DEFAULT_PALETTE_LIGHTNESS = () => autoCurve(makeAnchor(0, 95), makeAnchor(100, 8));
|
|
261
|
+
var DEFAULT_PALETTE_SATURATION = () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 100));
|
|
262
|
+
var wrapHue = (h) => (h % 360 + 360) % 360;
|
|
221
263
|
function scaleCurveDefaults(scheme = "dark") {
|
|
222
264
|
if (scheme === "light") {
|
|
223
265
|
return {
|
|
224
266
|
Surfaces: {
|
|
225
|
-
lightness: () =>
|
|
226
|
-
saturation: () =>
|
|
267
|
+
lightness: () => autoCurve(makeAnchor(0, 98), makeAnchor(100, 82)),
|
|
268
|
+
saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 100))
|
|
227
269
|
},
|
|
228
270
|
Borders: {
|
|
229
|
-
lightness: () =>
|
|
230
|
-
saturation: () =>
|
|
271
|
+
lightness: () => autoCurve(makeAnchor(0, 92), makeAnchor(100, 45)),
|
|
272
|
+
saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 100))
|
|
231
273
|
},
|
|
232
274
|
Text: {
|
|
233
|
-
lightness: () =>
|
|
234
|
-
saturation: () =>
|
|
275
|
+
lightness: () => autoCurve(makeAnchor(0, 30), makeAnchor(100, 120)),
|
|
276
|
+
saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 15))
|
|
235
277
|
}
|
|
236
278
|
};
|
|
237
279
|
}
|
|
238
280
|
return {
|
|
239
281
|
Surfaces: {
|
|
240
|
-
lightness: () =>
|
|
241
|
-
saturation: () =>
|
|
282
|
+
lightness: () => autoCurve(makeAnchor(0, 15), makeAnchor(100, 47)),
|
|
283
|
+
saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 100))
|
|
242
284
|
},
|
|
243
285
|
Borders: {
|
|
244
|
-
lightness: () =>
|
|
245
|
-
saturation: () =>
|
|
286
|
+
lightness: () => autoCurve(makeAnchor(0, 25), makeAnchor(100, 80)),
|
|
287
|
+
saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 100))
|
|
246
288
|
},
|
|
247
289
|
Text: {
|
|
248
|
-
lightness: () =>
|
|
249
|
-
saturation: () =>
|
|
290
|
+
lightness: () => autoCurve(makeAnchor(0, 120), makeAnchor(100, 55)),
|
|
291
|
+
saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 15))
|
|
250
292
|
}
|
|
251
293
|
};
|
|
252
294
|
}
|
|
@@ -265,14 +307,16 @@ function scaleStepToX(step, scale) {
|
|
|
265
307
|
return scale.steps.length > 1 ? idx / (scale.steps.length - 1) * 100 : 50;
|
|
266
308
|
}
|
|
267
309
|
function serializeDerivedValue(value) {
|
|
268
|
-
return value.kind === "raw" ? value.css :
|
|
310
|
+
return value.kind === "raw" ? value.css : oklchToCssClamped(value.l, value.c, value.h);
|
|
269
311
|
}
|
|
270
|
-
function computePaletteOklch(index, base, lightnessCurve, saturationCurve, curveOffset) {
|
|
271
|
-
const { c: baseC
|
|
312
|
+
function computePaletteOklch(index, base, lightnessCurve, saturationCurve, curveOffset, hueCurve) {
|
|
313
|
+
const { c: baseC } = base;
|
|
272
314
|
const xPos = stepIndexToX(index);
|
|
273
315
|
const targetL = Math.max(0, Math.min(100, sampleCurve(lightnessCurve, xPos) + (curveOffset.lightness ?? 0))) / 100;
|
|
274
316
|
const satMul = Math.max(0, Math.min(2, (sampleCurve(saturationCurve, xPos) + (curveOffset.saturation ?? 0)) / 100));
|
|
275
317
|
const targetC = baseC * satMul;
|
|
318
|
+
const hueDelta = (hueCurve ? sampleCurve(hueCurve, xPos) : 0) + (curveOffset.hue ?? 0);
|
|
319
|
+
const h = hueDelta === 0 ? base.h : wrapHue(base.h + hueDelta);
|
|
276
320
|
return gamutClamp(targetL, targetC, h);
|
|
277
321
|
}
|
|
278
322
|
function nearestPaletteStep(lightnessCurve, baseL) {
|
|
@@ -368,10 +412,12 @@ function syncBaseAnchor(cfg) {
|
|
|
368
412
|
const fresh = prev === void 0;
|
|
369
413
|
let lCurve = cfg.lightnessCurve;
|
|
370
414
|
let sCurve = cfg.saturationCurve;
|
|
415
|
+
let hCurve = cfg.hueCurve;
|
|
371
416
|
if (prev) {
|
|
372
417
|
const prevX = stepIndexToX(prev.step);
|
|
373
418
|
lCurve = liftCurveAnchor(lCurve, prevX, prev.displacedL);
|
|
374
419
|
sCurve = liftCurveAnchor(sCurve, prevX, prev.displacedS);
|
|
420
|
+
if (hCurve) hCurve = liftCurveAnchor(hCurve, prevX, prev.displacedH);
|
|
375
421
|
}
|
|
376
422
|
const step = nearestPaletteStep(lCurve, cfg.baseColor.l);
|
|
377
423
|
const x = stepIndexToX(step);
|
|
@@ -379,12 +425,19 @@ function syncBaseAnchor(cfg) {
|
|
|
379
425
|
const s = setCurveAnchor(sCurve, x, 100, fresh);
|
|
380
426
|
cfg.lightnessCurve = l.curve;
|
|
381
427
|
cfg.saturationCurve = s.curve;
|
|
428
|
+
const h = hCurve ? setCurveAnchor(hCurve, x, 0, fresh) : void 0;
|
|
429
|
+
if (h) cfg.hueCurve = h.curve;
|
|
382
430
|
cfg.anchorPlacement = {
|
|
383
431
|
step,
|
|
384
432
|
displacedL: l.displacedY,
|
|
385
433
|
displacedS: s.displacedY,
|
|
434
|
+
displacedH: h?.displacedY,
|
|
386
435
|
priorLightnessEndpoints: prev?.priorLightnessEndpoints ?? l.priorEndpoints,
|
|
387
|
-
priorSaturationEndpoints: prev?.priorSaturationEndpoints ?? s.priorEndpoints
|
|
436
|
+
priorSaturationEndpoints: prev?.priorSaturationEndpoints ?? s.priorEndpoints,
|
|
437
|
+
// No else-branch reading `prev?.priorHueEndpoints`: that could only fire
|
|
438
|
+
// if a placed hue curve later went absent, which RJC 7 (reset never
|
|
439
|
+
// deletes) never lets happen.
|
|
440
|
+
priorHueEndpoints: h ? prev?.priorHueEndpoints ?? h.priorEndpoints : void 0
|
|
388
441
|
};
|
|
389
442
|
}
|
|
390
443
|
function computeDerivedOklch(step, base, scaleTitle, scaleCurves, curveOffset) {
|
|
@@ -393,8 +446,10 @@ function computeDerivedOklch(step, base, scaleTitle, scaleCurves, curveOffset) {
|
|
|
393
446
|
const defs = defaultScaleCurves[scaleTitle];
|
|
394
447
|
const lCurve = scaleCurves[scaleTitle]?.lightness ?? defs.lightness();
|
|
395
448
|
const sCurve = scaleCurves[scaleTitle]?.saturation ?? defs.saturation();
|
|
449
|
+
const hCurve = scaleCurves[scaleTitle]?.hue;
|
|
396
450
|
const lOff = curveOffset[`${scaleTitle}-lightness`] ?? 0;
|
|
397
451
|
const sOff = curveOffset[`${scaleTitle}-saturation`] ?? 0;
|
|
452
|
+
const hOff = curveOffset[`${scaleTitle}-hue`] ?? 0;
|
|
398
453
|
const { l: baseL, c: baseC, h: baseH } = base;
|
|
399
454
|
let targetL;
|
|
400
455
|
if (scale.isText) {
|
|
@@ -405,7 +460,9 @@ function computeDerivedOklch(step, base, scaleTitle, scaleCurves, curveOffset) {
|
|
|
405
460
|
}
|
|
406
461
|
const satMul = Math.max(0, Math.min(2, (sampleCurve(sCurve, xPos) + sOff) / 100));
|
|
407
462
|
const targetC = baseC * satMul;
|
|
408
|
-
|
|
463
|
+
const hueDelta = (hCurve ? sampleCurve(hCurve, xPos) : 0) + hOff;
|
|
464
|
+
const targetH = hueDelta === 0 ? baseH : wrapHue(baseH + hueDelta);
|
|
465
|
+
return gamutClamp(targetL, targetC, targetH);
|
|
409
466
|
}
|
|
410
467
|
function scaleToCssVar(scaleTitle, stepName, cssNamespace) {
|
|
411
468
|
if (cssNamespace === null) return null;
|
|
@@ -434,7 +491,7 @@ function derivePaletteValues(spec, config) {
|
|
|
434
491
|
const saturationCurve = config.saturationCurve ?? DEFAULT_PALETTE_SATURATION();
|
|
435
492
|
PALETTE_STEPS.forEach((ps, index) => {
|
|
436
493
|
const k = paletteStepKey(ps.label);
|
|
437
|
-
const value = k in overrides ? { kind: "color", ...overrides[k] } : { kind: "color", ...computePaletteOklch(index, baseColor, lightnessCurve, saturationCurve, curveOffset) };
|
|
494
|
+
const value = k in overrides ? { kind: "color", ...overrides[k] } : { kind: "color", ...computePaletteOklch(index, baseColor, lightnessCurve, saturationCurve, curveOffset, config.hueCurve) };
|
|
438
495
|
out[`--color-${spec.cssNamespace}-${ps.label}`] = value;
|
|
439
496
|
});
|
|
440
497
|
for (const scale of SCALES) {
|
|
@@ -469,8 +526,8 @@ function derivePaletteValues(spec, config) {
|
|
|
469
526
|
);
|
|
470
527
|
const stopsCss = sortedStops.map((s) => {
|
|
471
528
|
const stopValue = out[`--color-${spec.cssNamespace}-${s.paletteLabel}`];
|
|
472
|
-
const
|
|
473
|
-
return `${
|
|
529
|
+
const css = stopValue ? serializeDerivedValue(stopValue) : "oklch(0 0 0)";
|
|
530
|
+
return `${css} ${s.position}%`;
|
|
474
531
|
}).join(", ");
|
|
475
532
|
let gradient;
|
|
476
533
|
switch (gradientStyle) {
|
|
@@ -489,13 +546,6 @@ function derivePaletteValues(spec, config) {
|
|
|
489
546
|
}
|
|
490
547
|
return out;
|
|
491
548
|
}
|
|
492
|
-
function derivePaletteVars(spec, config) {
|
|
493
|
-
const out = {};
|
|
494
|
-
for (const [k, v] of Object.entries(derivePaletteValues(spec, config))) {
|
|
495
|
-
out[k] = serializeDerivedValue(v);
|
|
496
|
-
}
|
|
497
|
-
return out;
|
|
498
|
-
}
|
|
499
549
|
function palettesToValues(palettes) {
|
|
500
550
|
const out = {};
|
|
501
551
|
for (const spec of PALETTE_SPECS) {
|
|
@@ -510,7 +560,6 @@ function palettesToVars(palettes) {
|
|
|
510
560
|
}
|
|
511
561
|
return out;
|
|
512
562
|
}
|
|
513
|
-
var HEX_RE = /^#[0-9a-f]{6}$/i;
|
|
514
563
|
function reconcilePalettesFromCssVars(palettes, cssVars) {
|
|
515
564
|
const next = structuredClone(palettes);
|
|
516
565
|
const consumed = /* @__PURE__ */ new Set();
|
|
@@ -519,16 +568,17 @@ function reconcilePalettesFromCssVars(palettes, cssVars) {
|
|
|
519
568
|
const current = next[spec.label];
|
|
520
569
|
if (current === void 0) continue;
|
|
521
570
|
if (current._imported === true) {
|
|
522
|
-
const
|
|
523
|
-
|
|
524
|
-
|
|
571
|
+
const anchor = cssVars[`--color-${spec.cssNamespace}-500`];
|
|
572
|
+
const anchorOklch = anchor ? cssColorToOklch(anchor) : null;
|
|
573
|
+
if (anchorOklch) {
|
|
574
|
+
next[spec.label] = { ...current, baseColor: anchorOklch, _imported: false };
|
|
525
575
|
syncBaseAnchor(next[spec.label]);
|
|
526
576
|
snapped.add(spec.label);
|
|
527
577
|
} else {
|
|
528
578
|
next[spec.label] = { ...current, _imported: false };
|
|
529
579
|
}
|
|
530
580
|
}
|
|
531
|
-
for (const k of Object.keys(
|
|
581
|
+
for (const k of Object.keys(derivePaletteValues(spec, next[spec.label]))) {
|
|
532
582
|
consumed.add(k);
|
|
533
583
|
}
|
|
534
584
|
}
|
|
@@ -536,11 +586,12 @@ function reconcilePalettesFromCssVars(palettes, cssVars) {
|
|
|
536
586
|
}
|
|
537
587
|
|
|
538
588
|
export {
|
|
589
|
+
parseColorOpacity,
|
|
590
|
+
formatGradientValue,
|
|
591
|
+
parseGradientValue,
|
|
539
592
|
sanitizeFileName,
|
|
540
|
-
hexToOklch,
|
|
541
|
-
oklchToHex,
|
|
542
|
-
gamutClamp,
|
|
543
593
|
makeAnchor,
|
|
594
|
+
resmoothAutoCurve,
|
|
544
595
|
PALETTE_SPECS,
|
|
545
596
|
PALETTE_STEPS,
|
|
546
597
|
SCALES,
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
hexToOklch,
|
|
3
|
+
oklchToCss
|
|
4
|
+
} from "./chunk-YR6GPXW2.js";
|
|
5
|
+
|
|
1
6
|
// src/editor/core/themes/parsers/globalRootBlock.ts
|
|
2
7
|
function extractGlobalRootBody(source) {
|
|
3
8
|
const re = /:global\(:root\)\s*\{([^}]*)\}/g;
|
|
@@ -12,11 +17,17 @@ function extractGlobalRootBody(source) {
|
|
|
12
17
|
// vite-plugin/tokensCssMigrations/cssTokenOps.ts
|
|
13
18
|
var DECL_RE = /(^|[\s;{])(--[a-z0-9-]+)\s*:/gi;
|
|
14
19
|
var REF_RE = /var\(\s*(--[a-z0-9-]+)/gi;
|
|
20
|
+
var DECL_VALUE_RE = /(^|[\s;{])(--[a-z0-9-]+)\s*:([^;}]*)/gi;
|
|
15
21
|
function collectDefinedTokens(css) {
|
|
16
22
|
const out = /* @__PURE__ */ new Set();
|
|
17
23
|
for (const m of css.matchAll(DECL_RE)) out.add(m[2]);
|
|
18
24
|
return out;
|
|
19
25
|
}
|
|
26
|
+
function collectTokenValues(css) {
|
|
27
|
+
const out = /* @__PURE__ */ new Map();
|
|
28
|
+
for (const m of css.matchAll(DECL_VALUE_RE)) out.set(m[2], m[3].trim());
|
|
29
|
+
return out;
|
|
30
|
+
}
|
|
20
31
|
function collectReferencedTokens(css) {
|
|
21
32
|
const out = /* @__PURE__ */ new Set();
|
|
22
33
|
for (const m of css.matchAll(REF_RE)) out.add(m[1]);
|
|
@@ -350,6 +361,20 @@ var tokensCssMigration_2026_07_20_semanticTextStyles = {
|
|
|
350
361
|
}
|
|
351
362
|
};
|
|
352
363
|
|
|
364
|
+
// vite-plugin/tokensCssMigrations/migrations/2026-08-19-oklch-color-values.ts
|
|
365
|
+
var HEX_DECLARATION_RE = /(--[a-z0-9-]+:\s*)#([0-9a-f]{6})(?=\s*[;}])/gi;
|
|
366
|
+
var tokensCssMigration_2026_08_19_oklchColorValues = {
|
|
367
|
+
id: "2026-08-19-oklch-color-values",
|
|
368
|
+
kind: "breaking",
|
|
369
|
+
description: "Rewrite hex token values as oklch()",
|
|
370
|
+
apply(css) {
|
|
371
|
+
return css.replace(HEX_DECLARATION_RE, (_match, prefix, hex) => {
|
|
372
|
+
const { l, c, h } = hexToOklch(`#${hex}`);
|
|
373
|
+
return `${prefix}${oklchToCss(l, c, h)}`;
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
|
|
353
378
|
// vite-plugin/tokensCssMigrations/index.ts
|
|
354
379
|
var TOKENS_CSS_MIGRATIONS = [
|
|
355
380
|
tokensCssMigration_2026_05_29_typographyScaleAdditions,
|
|
@@ -358,7 +383,8 @@ var TOKENS_CSS_MIGRATIONS = [
|
|
|
358
383
|
tokensCssMigration_2026_06_04_removeDeadSizeIconScale,
|
|
359
384
|
tokensCssMigration_2026_06_04_easingColorAndTypescaleAdditions,
|
|
360
385
|
tokensCssMigration_2026_07_20_lineHeightRename,
|
|
361
|
-
tokensCssMigration_2026_07_20_semanticTextStyles
|
|
386
|
+
tokensCssMigration_2026_07_20_semanticTextStyles,
|
|
387
|
+
tokensCssMigration_2026_08_19_oklchColorValues
|
|
362
388
|
];
|
|
363
389
|
function runTokensCssMigrations(css) {
|
|
364
390
|
return foldMigrations(css, () => true);
|
|
@@ -383,10 +409,11 @@ function findContractViolations(canonicalCss) {
|
|
|
383
409
|
const violations = [];
|
|
384
410
|
for (const m of TOKENS_CSS_MIGRATIONS) {
|
|
385
411
|
if (m.kind !== "additive") continue;
|
|
386
|
-
const before =
|
|
387
|
-
const after =
|
|
388
|
-
const removed = [...before].filter((t) => !after.has(t)).sort();
|
|
389
|
-
|
|
412
|
+
const before = collectTokenValues(canonicalCss);
|
|
413
|
+
const after = collectTokenValues(m.apply(canonicalCss));
|
|
414
|
+
const removed = [...before.keys()].filter((t) => !after.has(t)).sort();
|
|
415
|
+
const changed = [...before.entries()].filter(([t, v]) => after.has(t) && after.get(t) !== v).map(([t]) => t).sort();
|
|
416
|
+
if (removed.length || changed.length) violations.push({ id: m.id, removed, changed });
|
|
390
417
|
}
|
|
391
418
|
return violations;
|
|
392
419
|
}
|
|
@@ -446,6 +473,7 @@ function validateTokensCss(input) {
|
|
|
446
473
|
export {
|
|
447
474
|
extractGlobalRootBody,
|
|
448
475
|
collectDefinedTokens,
|
|
476
|
+
collectTokenValues,
|
|
449
477
|
collectReferencedTokens,
|
|
450
478
|
ensureScale,
|
|
451
479
|
renameToken,
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// src/system/internal/oklch.ts
|
|
2
|
+
function srgbToLinear(c) {
|
|
3
|
+
return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
4
|
+
}
|
|
5
|
+
function linearToSrgb(c) {
|
|
6
|
+
return c <= 31308e-7 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
|
|
7
|
+
}
|
|
8
|
+
function hexToLinearRgb(hex) {
|
|
9
|
+
const r = parseInt(hex.slice(1, 3), 16) / 255;
|
|
10
|
+
const g = parseInt(hex.slice(3, 5), 16) / 255;
|
|
11
|
+
const b = parseInt(hex.slice(5, 7), 16) / 255;
|
|
12
|
+
return [srgbToLinear(r), srgbToLinear(g), srgbToLinear(b)];
|
|
13
|
+
}
|
|
14
|
+
function linearRgbToHex(r, g, b) {
|
|
15
|
+
const toHex = (c) => {
|
|
16
|
+
const v = Math.round(Math.max(0, Math.min(1, linearToSrgb(c))) * 255);
|
|
17
|
+
return v.toString(16).padStart(2, "0");
|
|
18
|
+
};
|
|
19
|
+
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
20
|
+
}
|
|
21
|
+
function linearRgbToOklab(r, g, b) {
|
|
22
|
+
const l_ = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
|
|
23
|
+
const m_ = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
|
|
24
|
+
const s_ = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
|
|
25
|
+
const l = Math.cbrt(l_);
|
|
26
|
+
const m = Math.cbrt(m_);
|
|
27
|
+
const s = Math.cbrt(s_);
|
|
28
|
+
return [
|
|
29
|
+
0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,
|
|
30
|
+
1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,
|
|
31
|
+
0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
function oklabToLinearRgb(L, a, b) {
|
|
35
|
+
const l_ = L + 0.3963377774 * a + 0.2158037573 * b;
|
|
36
|
+
const m_ = L - 0.1055613458 * a - 0.0638541728 * b;
|
|
37
|
+
const s_ = L - 0.0894841775 * a - 1.291485548 * b;
|
|
38
|
+
const l = l_ * l_ * l_;
|
|
39
|
+
const m = m_ * m_ * m_;
|
|
40
|
+
const s = s_ * s_ * s_;
|
|
41
|
+
return [
|
|
42
|
+
4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
|
|
43
|
+
-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
|
|
44
|
+
-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s
|
|
45
|
+
];
|
|
46
|
+
}
|
|
47
|
+
function oklabToOklch(L, a, b) {
|
|
48
|
+
const c = Math.sqrt(a * a + b * b);
|
|
49
|
+
let h = Math.atan2(b, a) * 180 / Math.PI;
|
|
50
|
+
if (h < 0) h += 360;
|
|
51
|
+
return { l: L, c, h };
|
|
52
|
+
}
|
|
53
|
+
function oklchToOklab(l, c, h) {
|
|
54
|
+
const hRad = h * Math.PI / 180;
|
|
55
|
+
return [l, c * Math.cos(hRad), c * Math.sin(hRad)];
|
|
56
|
+
}
|
|
57
|
+
function hexToOklch(hex) {
|
|
58
|
+
const [r, g, b] = hexToLinearRgb(hex);
|
|
59
|
+
const [L, a, bVal] = linearRgbToOklab(r, g, b);
|
|
60
|
+
return oklabToOklch(L, a, bVal);
|
|
61
|
+
}
|
|
62
|
+
function oklchToHex(l, c, h) {
|
|
63
|
+
const [L, a, b] = oklchToOklab(l, c, h);
|
|
64
|
+
const [r, g, bVal] = oklabToLinearRgb(L, a, b);
|
|
65
|
+
return linearRgbToHex(r, g, bVal);
|
|
66
|
+
}
|
|
67
|
+
function isInGamut(r, g, b) {
|
|
68
|
+
const eps = 1e-4;
|
|
69
|
+
return r >= -eps && r <= 1 + eps && g >= -eps && g <= 1 + eps && b >= -eps && b <= 1 + eps;
|
|
70
|
+
}
|
|
71
|
+
function oklchToHexClamped(l, c, h) {
|
|
72
|
+
const g = gamutClamp(l, c, h);
|
|
73
|
+
return oklchToHex(g.l, g.c, g.h);
|
|
74
|
+
}
|
|
75
|
+
function gamutClamp(l, c, h) {
|
|
76
|
+
if (l <= 0) return { l: 0, c: 0, h };
|
|
77
|
+
if (l >= 1) return { l: 1, c: 0, h };
|
|
78
|
+
const [L, a, b] = oklchToOklab(l, c, h);
|
|
79
|
+
const [r, g, bVal] = oklabToLinearRgb(L, a, b);
|
|
80
|
+
if (isInGamut(r, g, bVal)) return { l, c, h };
|
|
81
|
+
let lo = 0;
|
|
82
|
+
let hi = c;
|
|
83
|
+
for (let i = 0; i < 20; i++) {
|
|
84
|
+
const mid = (lo + hi) / 2;
|
|
85
|
+
const [La, aa, ba] = oklchToOklab(l, mid, h);
|
|
86
|
+
const [rr, gg, bb] = oklabToLinearRgb(La, aa, ba);
|
|
87
|
+
if (isInGamut(rr, gg, bb)) {
|
|
88
|
+
lo = mid;
|
|
89
|
+
} else {
|
|
90
|
+
hi = mid;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return { l, c: lo, h };
|
|
94
|
+
}
|
|
95
|
+
function trim(value, decimals) {
|
|
96
|
+
return Number(value.toFixed(decimals)).toString();
|
|
97
|
+
}
|
|
98
|
+
function oklchToCss(l, c, h) {
|
|
99
|
+
const cs = trim(c, 4);
|
|
100
|
+
return `oklch(${trim(l, 4)} ${cs} ${cs === "0" ? "0" : trim(h, 2)})`;
|
|
101
|
+
}
|
|
102
|
+
function oklchToCssClamped(l, c, h) {
|
|
103
|
+
const g = gamutClamp(l, c, h);
|
|
104
|
+
return oklchToCss(g.l, g.c, g.h);
|
|
105
|
+
}
|
|
106
|
+
var OKLCH_RE = /^oklch\(\s*([\d.]+)(%?)\s+([\d.]+)(%?)\s+([\d.]+)(?:deg)?\s*\)$/i;
|
|
107
|
+
var HEX6_RE = /^#[0-9a-f]{6}$/i;
|
|
108
|
+
function parseOklchCss(value) {
|
|
109
|
+
const m = OKLCH_RE.exec(value.trim());
|
|
110
|
+
if (!m) return null;
|
|
111
|
+
const l = Number.parseFloat(m[1]) / (m[2] === "%" ? 100 : 1);
|
|
112
|
+
const c = Number.parseFloat(m[3]) * (m[4] === "%" ? 4e-3 : 1);
|
|
113
|
+
return { l, c, h: Number.parseFloat(m[5]) };
|
|
114
|
+
}
|
|
115
|
+
function cssColorToOklch(value) {
|
|
116
|
+
const raw = value.trim();
|
|
117
|
+
if (HEX6_RE.test(raw)) return hexToOklch(raw);
|
|
118
|
+
return parseOklchCss(raw);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export {
|
|
122
|
+
hexToOklch,
|
|
123
|
+
oklchToHex,
|
|
124
|
+
oklchToHexClamped,
|
|
125
|
+
gamutClamp,
|
|
126
|
+
oklchToCss,
|
|
127
|
+
oklchToCssClamped,
|
|
128
|
+
cssColorToOklch
|
|
129
|
+
};
|