@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
package/dist-plugin/index.cjs
CHANGED
|
@@ -59,32 +59,134 @@ function parseColorOpacity(value) {
|
|
|
59
59
|
if (!m) return null;
|
|
60
60
|
return { name: m[1], opacity: parseInt(m[2], 10) };
|
|
61
61
|
}
|
|
62
|
+
function formatColorOpacity(name, opacity) {
|
|
63
|
+
return `color-mix(in srgb, var(${name}) ${opacity}%, transparent)`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/editor/core/themes/parsers/gradient.ts
|
|
67
|
+
var RADIAL_BASE_PX = 100;
|
|
68
|
+
function formatStopColor(s) {
|
|
69
|
+
const opacity = s.opacity ?? 100;
|
|
70
|
+
if (s.color.startsWith("--")) {
|
|
71
|
+
return opacity >= 100 ? `var(${s.color})` : formatColorOpacity(s.color, opacity);
|
|
72
|
+
}
|
|
73
|
+
return opacity >= 100 ? s.color : `color-mix(in srgb, ${s.color} ${opacity}%, transparent)`;
|
|
74
|
+
}
|
|
75
|
+
function formatGradientStops(stops) {
|
|
76
|
+
return stops.map((s) => `${formatStopColor(s)} ${s.position}%`).join(", ");
|
|
77
|
+
}
|
|
78
|
+
function formatRadialShape(v) {
|
|
79
|
+
const ax = v.aspectX ?? 1;
|
|
80
|
+
const ay = v.aspectY ?? 1;
|
|
81
|
+
if (ax === 1 && ay === 1) {
|
|
82
|
+
return v.radius && v.radius > 0 ? `circle ${v.radius}px` : "circle";
|
|
83
|
+
}
|
|
84
|
+
const base = v.radius && v.radius > 0 ? v.radius : RADIAL_BASE_PX;
|
|
85
|
+
return `ellipse ${(base * ax).toFixed(2)}px ${(base * ay).toFixed(2)}px`;
|
|
86
|
+
}
|
|
87
|
+
function formatGradientValue(v) {
|
|
88
|
+
if (v.type === "none") return "transparent";
|
|
89
|
+
if (v.type === "solid") {
|
|
90
|
+
const first = v.stops[0];
|
|
91
|
+
return first ? formatStopColor(first) : "transparent";
|
|
92
|
+
}
|
|
93
|
+
const stops = formatGradientStops(v.stops);
|
|
94
|
+
if (v.type === "linear") return `linear-gradient(${v.angle}deg, ${stops})`;
|
|
95
|
+
return `radial-gradient(${formatRadialShape(v)} at ${v.centerX ?? 50}% 50%, ${stops})`;
|
|
96
|
+
}
|
|
97
|
+
var NUM = String.raw`-?\d+(?:\.\d+)?`;
|
|
98
|
+
var LINEAR_RE = new RegExp(String.raw`^linear-gradient\(\s*(${NUM})deg\s*,\s*(.+)\)$`, "i");
|
|
99
|
+
var RADIAL_RE = new RegExp(
|
|
100
|
+
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*(.+)\)$`,
|
|
101
|
+
"i"
|
|
102
|
+
);
|
|
103
|
+
var STOP_RE = new RegExp(String.raw`^(.*?)\s+(${NUM})%$`);
|
|
104
|
+
var CIRCLE_RADIUS_RE = new RegExp(String.raw`^circle\s+(${NUM})px$`, "i");
|
|
105
|
+
var ELLIPSE_RE = new RegExp(String.raw`^ellipse\s+(${NUM})px\s+(${NUM})px$`, "i");
|
|
106
|
+
var VAR_RE = /^var\((--[a-z0-9-]+)\)$/i;
|
|
107
|
+
function splitTopLevel(s) {
|
|
108
|
+
const parts = [];
|
|
109
|
+
let depth = 0;
|
|
110
|
+
let start = 0;
|
|
111
|
+
for (let i = 0; i < s.length; i++) {
|
|
112
|
+
const c = s[i];
|
|
113
|
+
if (c === "(") depth++;
|
|
114
|
+
else if (c === ")") depth--;
|
|
115
|
+
else if (c === "," && depth === 0) {
|
|
116
|
+
parts.push(s.slice(start, i));
|
|
117
|
+
start = i + 1;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
parts.push(s.slice(start));
|
|
121
|
+
return parts;
|
|
122
|
+
}
|
|
123
|
+
function parseStop(raw) {
|
|
124
|
+
const m = raw.trim().match(STOP_RE);
|
|
125
|
+
if (!m) return null;
|
|
126
|
+
const position = parseFloat(m[2]);
|
|
127
|
+
const color = m[1].trim();
|
|
128
|
+
const opacity = parseColorOpacity(color);
|
|
129
|
+
if (opacity) return { position, color: opacity.name, opacity: opacity.opacity };
|
|
130
|
+
const token = color.match(VAR_RE);
|
|
131
|
+
return { position, color: token ? token[1] : color };
|
|
132
|
+
}
|
|
133
|
+
function parseStops(raw) {
|
|
134
|
+
const stops = [];
|
|
135
|
+
for (const part of splitTopLevel(raw)) {
|
|
136
|
+
const stop = parseStop(part);
|
|
137
|
+
if (!stop) return null;
|
|
138
|
+
stops.push(stop);
|
|
139
|
+
}
|
|
140
|
+
return stops.length > 0 ? stops : null;
|
|
141
|
+
}
|
|
142
|
+
function parseRadialShape(raw) {
|
|
143
|
+
const shape = raw.trim();
|
|
144
|
+
if (/^circle$/i.test(shape)) return {};
|
|
145
|
+
const circle = shape.match(CIRCLE_RADIUS_RE);
|
|
146
|
+
if (circle) return { radius: parseFloat(circle[1]) };
|
|
147
|
+
const ellipse = shape.match(ELLIPSE_RE);
|
|
148
|
+
if (!ellipse) return null;
|
|
149
|
+
const ax = parseFloat(ellipse[1]) / RADIAL_BASE_PX;
|
|
150
|
+
const ay = parseFloat(ellipse[2]) / RADIAL_BASE_PX;
|
|
151
|
+
return { ...ax === 1 ? {} : { aspectX: ax }, ...ay === 1 ? {} : { aspectY: ay } };
|
|
152
|
+
}
|
|
153
|
+
function parseGradientValue(value) {
|
|
154
|
+
const css = value.trim();
|
|
155
|
+
const linear = css.match(LINEAR_RE);
|
|
156
|
+
if (linear) {
|
|
157
|
+
const stops2 = parseStops(linear[2]);
|
|
158
|
+
return stops2 && { type: "linear", angle: parseFloat(linear[1]), stops: stops2 };
|
|
159
|
+
}
|
|
160
|
+
const radial = css.match(RADIAL_RE);
|
|
161
|
+
if (!radial) return null;
|
|
162
|
+
const shape = parseRadialShape(radial[1]);
|
|
163
|
+
const stops = parseStops(radial[3]);
|
|
164
|
+
if (!shape || !stops) return null;
|
|
165
|
+
const centerX = parseFloat(radial[2]);
|
|
166
|
+
return {
|
|
167
|
+
type: "radial",
|
|
168
|
+
angle: 0,
|
|
169
|
+
...shape,
|
|
170
|
+
...centerX === 50 ? {} : { centerX },
|
|
171
|
+
stops
|
|
172
|
+
};
|
|
173
|
+
}
|
|
62
174
|
|
|
63
175
|
// src/editor/core/storage/files/versionedFileResourceClient.ts
|
|
64
176
|
function sanitizeFileName(name) {
|
|
65
177
|
return name.toLowerCase().trim().replace(/\s+/g, "-").replace(/[^a-z0-9\-_]/g, "").replace(/-+/g, "-").replace(/^[-_]+|-+$/g, "") || "unnamed";
|
|
66
178
|
}
|
|
67
179
|
|
|
68
|
-
// src/
|
|
180
|
+
// src/system/internal/oklch.ts
|
|
69
181
|
function srgbToLinear(c) {
|
|
70
182
|
return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
71
183
|
}
|
|
72
|
-
function linearToSrgb(c) {
|
|
73
|
-
return c <= 31308e-7 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
|
|
74
|
-
}
|
|
75
184
|
function hexToLinearRgb(hex) {
|
|
76
185
|
const r = parseInt(hex.slice(1, 3), 16) / 255;
|
|
77
186
|
const g = parseInt(hex.slice(3, 5), 16) / 255;
|
|
78
187
|
const b = parseInt(hex.slice(5, 7), 16) / 255;
|
|
79
188
|
return [srgbToLinear(r), srgbToLinear(g), srgbToLinear(b)];
|
|
80
189
|
}
|
|
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
190
|
function linearRgbToOklab(r, g, b) {
|
|
89
191
|
const l_ = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
|
|
90
192
|
const m_ = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
|
|
@@ -126,19 +228,10 @@ function hexToOklch(hex) {
|
|
|
126
228
|
const [L, a, bVal] = linearRgbToOklab(r, g, b);
|
|
127
229
|
return oklabToOklch(L, a, bVal);
|
|
128
230
|
}
|
|
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
231
|
function isInGamut(r, g, b) {
|
|
135
232
|
const eps = 1e-4;
|
|
136
233
|
return r >= -eps && r <= 1 + eps && g >= -eps && g <= 1 + eps && b >= -eps && b <= 1 + eps;
|
|
137
234
|
}
|
|
138
|
-
function oklchToHexClamped(l, c, h) {
|
|
139
|
-
const g = gamutClamp(l, c, h);
|
|
140
|
-
return oklchToHex(g.l, g.c, g.h);
|
|
141
|
-
}
|
|
142
235
|
function gamutClamp(l, c, h) {
|
|
143
236
|
if (l <= 0) return { l: 0, c: 0, h };
|
|
144
237
|
if (l >= 1) return { l: 1, c: 0, h };
|
|
@@ -159,6 +252,31 @@ function gamutClamp(l, c, h) {
|
|
|
159
252
|
}
|
|
160
253
|
return { l, c: lo, h };
|
|
161
254
|
}
|
|
255
|
+
function trim(value, decimals) {
|
|
256
|
+
return Number(value.toFixed(decimals)).toString();
|
|
257
|
+
}
|
|
258
|
+
function oklchToCss(l, c, h) {
|
|
259
|
+
const cs = trim(c, 4);
|
|
260
|
+
return `oklch(${trim(l, 4)} ${cs} ${cs === "0" ? "0" : trim(h, 2)})`;
|
|
261
|
+
}
|
|
262
|
+
function oklchToCssClamped(l, c, h) {
|
|
263
|
+
const g = gamutClamp(l, c, h);
|
|
264
|
+
return oklchToCss(g.l, g.c, g.h);
|
|
265
|
+
}
|
|
266
|
+
var OKLCH_RE = /^oklch\(\s*([\d.]+)(%?)\s+([\d.]+)(%?)\s+([\d.]+)(?:deg)?\s*\)$/i;
|
|
267
|
+
var HEX6_RE = /^#[0-9a-f]{6}$/i;
|
|
268
|
+
function parseOklchCss(value) {
|
|
269
|
+
const m = OKLCH_RE.exec(value.trim());
|
|
270
|
+
if (!m) return null;
|
|
271
|
+
const l = Number.parseFloat(m[1]) / (m[2] === "%" ? 100 : 1);
|
|
272
|
+
const c = Number.parseFloat(m[3]) * (m[4] === "%" ? 4e-3 : 1);
|
|
273
|
+
return { l, c, h: Number.parseFloat(m[5]) };
|
|
274
|
+
}
|
|
275
|
+
function cssColorToOklch(value) {
|
|
276
|
+
const raw = value.trim();
|
|
277
|
+
if (HEX6_RE.test(raw)) return hexToOklch(raw);
|
|
278
|
+
return parseOklchCss(raw);
|
|
279
|
+
}
|
|
162
280
|
|
|
163
281
|
// src/editor/ui/curveEngine.ts
|
|
164
282
|
function makeAnchor(x, y, tangentLen = 15) {
|
|
@@ -183,6 +301,15 @@ function tangentAnchor(x, y, prev, next) {
|
|
|
183
301
|
const outDx = next ? (next.x - x) * HANDLE_SPAN : 0;
|
|
184
302
|
return { x, y, inDx, inDy: m * inDx, outDx, outDy: m * outDx };
|
|
185
303
|
}
|
|
304
|
+
function isCornerAnchor(a) {
|
|
305
|
+
return a.inDx === 0 && a.inDy === 0 && a.outDx === 0 && a.outDy === 0;
|
|
306
|
+
}
|
|
307
|
+
function resmoothAutoCurve(anchors) {
|
|
308
|
+
if (anchors.length < 2) return anchors;
|
|
309
|
+
return anchors.map(
|
|
310
|
+
(a, i) => isCornerAnchor(a) ? a : tangentAnchor(a.x, a.y, anchors[i - 1] ?? null, anchors[i + 1] ?? null)
|
|
311
|
+
);
|
|
312
|
+
}
|
|
186
313
|
function evalBezier(p0x, p0y, c0x, c0y, c1x, c1y, p1x, p1y, t) {
|
|
187
314
|
const u = 1 - t, u2 = u * u, u3 = u2 * u;
|
|
188
315
|
const t2 = t * t, t3 = t2 * t;
|
|
@@ -278,37 +405,39 @@ var SCALES = [
|
|
|
278
405
|
];
|
|
279
406
|
var BW_GUARD_MIN_L = 0.17;
|
|
280
407
|
var BW_GUARD_MAX_L = 0.93;
|
|
281
|
-
var
|
|
282
|
-
var
|
|
408
|
+
var autoCurve = (...anchors) => resmoothAutoCurve(anchors);
|
|
409
|
+
var DEFAULT_PALETTE_LIGHTNESS = () => autoCurve(makeAnchor(0, 95), makeAnchor(100, 8));
|
|
410
|
+
var DEFAULT_PALETTE_SATURATION = () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 100));
|
|
411
|
+
var wrapHue = (h) => (h % 360 + 360) % 360;
|
|
283
412
|
function scaleCurveDefaults(scheme = "dark") {
|
|
284
413
|
if (scheme === "light") {
|
|
285
414
|
return {
|
|
286
415
|
Surfaces: {
|
|
287
|
-
lightness: () =>
|
|
288
|
-
saturation: () =>
|
|
416
|
+
lightness: () => autoCurve(makeAnchor(0, 98), makeAnchor(100, 82)),
|
|
417
|
+
saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 100))
|
|
289
418
|
},
|
|
290
419
|
Borders: {
|
|
291
|
-
lightness: () =>
|
|
292
|
-
saturation: () =>
|
|
420
|
+
lightness: () => autoCurve(makeAnchor(0, 92), makeAnchor(100, 45)),
|
|
421
|
+
saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 100))
|
|
293
422
|
},
|
|
294
423
|
Text: {
|
|
295
|
-
lightness: () =>
|
|
296
|
-
saturation: () =>
|
|
424
|
+
lightness: () => autoCurve(makeAnchor(0, 30), makeAnchor(100, 120)),
|
|
425
|
+
saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 15))
|
|
297
426
|
}
|
|
298
427
|
};
|
|
299
428
|
}
|
|
300
429
|
return {
|
|
301
430
|
Surfaces: {
|
|
302
|
-
lightness: () =>
|
|
303
|
-
saturation: () =>
|
|
431
|
+
lightness: () => autoCurve(makeAnchor(0, 15), makeAnchor(100, 47)),
|
|
432
|
+
saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 100))
|
|
304
433
|
},
|
|
305
434
|
Borders: {
|
|
306
|
-
lightness: () =>
|
|
307
|
-
saturation: () =>
|
|
435
|
+
lightness: () => autoCurve(makeAnchor(0, 25), makeAnchor(100, 80)),
|
|
436
|
+
saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 100))
|
|
308
437
|
},
|
|
309
438
|
Text: {
|
|
310
|
-
lightness: () =>
|
|
311
|
-
saturation: () =>
|
|
439
|
+
lightness: () => autoCurve(makeAnchor(0, 120), makeAnchor(100, 55)),
|
|
440
|
+
saturation: () => autoCurve(makeAnchor(0, 100), makeAnchor(100, 15))
|
|
312
441
|
}
|
|
313
442
|
};
|
|
314
443
|
}
|
|
@@ -327,14 +456,16 @@ function scaleStepToX(step, scale) {
|
|
|
327
456
|
return scale.steps.length > 1 ? idx / (scale.steps.length - 1) * 100 : 50;
|
|
328
457
|
}
|
|
329
458
|
function serializeDerivedValue(value) {
|
|
330
|
-
return value.kind === "raw" ? value.css :
|
|
459
|
+
return value.kind === "raw" ? value.css : oklchToCssClamped(value.l, value.c, value.h);
|
|
331
460
|
}
|
|
332
|
-
function computePaletteOklch(index, base, lightnessCurve, saturationCurve, curveOffset) {
|
|
333
|
-
const { c: baseC
|
|
461
|
+
function computePaletteOklch(index, base, lightnessCurve, saturationCurve, curveOffset, hueCurve) {
|
|
462
|
+
const { c: baseC } = base;
|
|
334
463
|
const xPos = stepIndexToX(index);
|
|
335
464
|
const targetL = Math.max(0, Math.min(100, sampleCurve(lightnessCurve, xPos) + (curveOffset.lightness ?? 0))) / 100;
|
|
336
465
|
const satMul = Math.max(0, Math.min(2, (sampleCurve(saturationCurve, xPos) + (curveOffset.saturation ?? 0)) / 100));
|
|
337
466
|
const targetC = baseC * satMul;
|
|
467
|
+
const hueDelta = (hueCurve ? sampleCurve(hueCurve, xPos) : 0) + (curveOffset.hue ?? 0);
|
|
468
|
+
const h = hueDelta === 0 ? base.h : wrapHue(base.h + hueDelta);
|
|
338
469
|
return gamutClamp(targetL, targetC, h);
|
|
339
470
|
}
|
|
340
471
|
function nearestPaletteStep(lightnessCurve, baseL) {
|
|
@@ -430,10 +561,12 @@ function syncBaseAnchor(cfg) {
|
|
|
430
561
|
const fresh = prev === void 0;
|
|
431
562
|
let lCurve = cfg.lightnessCurve;
|
|
432
563
|
let sCurve = cfg.saturationCurve;
|
|
564
|
+
let hCurve = cfg.hueCurve;
|
|
433
565
|
if (prev) {
|
|
434
566
|
const prevX = stepIndexToX(prev.step);
|
|
435
567
|
lCurve = liftCurveAnchor(lCurve, prevX, prev.displacedL);
|
|
436
568
|
sCurve = liftCurveAnchor(sCurve, prevX, prev.displacedS);
|
|
569
|
+
if (hCurve) hCurve = liftCurveAnchor(hCurve, prevX, prev.displacedH);
|
|
437
570
|
}
|
|
438
571
|
const step = nearestPaletteStep(lCurve, cfg.baseColor.l);
|
|
439
572
|
const x = stepIndexToX(step);
|
|
@@ -441,12 +574,19 @@ function syncBaseAnchor(cfg) {
|
|
|
441
574
|
const s = setCurveAnchor(sCurve, x, 100, fresh);
|
|
442
575
|
cfg.lightnessCurve = l.curve;
|
|
443
576
|
cfg.saturationCurve = s.curve;
|
|
577
|
+
const h = hCurve ? setCurveAnchor(hCurve, x, 0, fresh) : void 0;
|
|
578
|
+
if (h) cfg.hueCurve = h.curve;
|
|
444
579
|
cfg.anchorPlacement = {
|
|
445
580
|
step,
|
|
446
581
|
displacedL: l.displacedY,
|
|
447
582
|
displacedS: s.displacedY,
|
|
583
|
+
displacedH: h?.displacedY,
|
|
448
584
|
priorLightnessEndpoints: prev?.priorLightnessEndpoints ?? l.priorEndpoints,
|
|
449
|
-
priorSaturationEndpoints: prev?.priorSaturationEndpoints ?? s.priorEndpoints
|
|
585
|
+
priorSaturationEndpoints: prev?.priorSaturationEndpoints ?? s.priorEndpoints,
|
|
586
|
+
// No else-branch reading `prev?.priorHueEndpoints`: that could only fire
|
|
587
|
+
// if a placed hue curve later went absent, which RJC 7 (reset never
|
|
588
|
+
// deletes) never lets happen.
|
|
589
|
+
priorHueEndpoints: h ? prev?.priorHueEndpoints ?? h.priorEndpoints : void 0
|
|
450
590
|
};
|
|
451
591
|
}
|
|
452
592
|
function computeDerivedOklch(step, base, scaleTitle, scaleCurves, curveOffset) {
|
|
@@ -455,8 +595,10 @@ function computeDerivedOklch(step, base, scaleTitle, scaleCurves, curveOffset) {
|
|
|
455
595
|
const defs = defaultScaleCurves[scaleTitle];
|
|
456
596
|
const lCurve = scaleCurves[scaleTitle]?.lightness ?? defs.lightness();
|
|
457
597
|
const sCurve = scaleCurves[scaleTitle]?.saturation ?? defs.saturation();
|
|
598
|
+
const hCurve = scaleCurves[scaleTitle]?.hue;
|
|
458
599
|
const lOff = curveOffset[`${scaleTitle}-lightness`] ?? 0;
|
|
459
600
|
const sOff = curveOffset[`${scaleTitle}-saturation`] ?? 0;
|
|
601
|
+
const hOff = curveOffset[`${scaleTitle}-hue`] ?? 0;
|
|
460
602
|
const { l: baseL, c: baseC, h: baseH } = base;
|
|
461
603
|
let targetL;
|
|
462
604
|
if (scale.isText) {
|
|
@@ -467,7 +609,9 @@ function computeDerivedOklch(step, base, scaleTitle, scaleCurves, curveOffset) {
|
|
|
467
609
|
}
|
|
468
610
|
const satMul = Math.max(0, Math.min(2, (sampleCurve(sCurve, xPos) + sOff) / 100));
|
|
469
611
|
const targetC = baseC * satMul;
|
|
470
|
-
|
|
612
|
+
const hueDelta = (hCurve ? sampleCurve(hCurve, xPos) : 0) + hOff;
|
|
613
|
+
const targetH = hueDelta === 0 ? baseH : wrapHue(baseH + hueDelta);
|
|
614
|
+
return gamutClamp(targetL, targetC, targetH);
|
|
471
615
|
}
|
|
472
616
|
function scaleToCssVar(scaleTitle, stepName, cssNamespace) {
|
|
473
617
|
if (cssNamespace === null) return null;
|
|
@@ -496,7 +640,7 @@ function derivePaletteValues(spec, config) {
|
|
|
496
640
|
const saturationCurve = config.saturationCurve ?? DEFAULT_PALETTE_SATURATION();
|
|
497
641
|
PALETTE_STEPS.forEach((ps, index) => {
|
|
498
642
|
const k = paletteStepKey(ps.label);
|
|
499
|
-
const value = k in overrides ? { kind: "color", ...overrides[k] } : { kind: "color", ...computePaletteOklch(index, baseColor, lightnessCurve, saturationCurve, curveOffset) };
|
|
643
|
+
const value = k in overrides ? { kind: "color", ...overrides[k] } : { kind: "color", ...computePaletteOklch(index, baseColor, lightnessCurve, saturationCurve, curveOffset, config.hueCurve) };
|
|
500
644
|
out[`--color-${spec.cssNamespace}-${ps.label}`] = value;
|
|
501
645
|
});
|
|
502
646
|
for (const scale of SCALES) {
|
|
@@ -531,8 +675,8 @@ function derivePaletteValues(spec, config) {
|
|
|
531
675
|
);
|
|
532
676
|
const stopsCss = sortedStops.map((s) => {
|
|
533
677
|
const stopValue = out[`--color-${spec.cssNamespace}-${s.paletteLabel}`];
|
|
534
|
-
const
|
|
535
|
-
return `${
|
|
678
|
+
const css = stopValue ? serializeDerivedValue(stopValue) : "oklch(0 0 0)";
|
|
679
|
+
return `${css} ${s.position}%`;
|
|
536
680
|
}).join(", ");
|
|
537
681
|
let gradient;
|
|
538
682
|
switch (gradientStyle) {
|
|
@@ -551,13 +695,6 @@ function derivePaletteValues(spec, config) {
|
|
|
551
695
|
}
|
|
552
696
|
return out;
|
|
553
697
|
}
|
|
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
698
|
function palettesToValues(palettes) {
|
|
562
699
|
const out = {};
|
|
563
700
|
for (const spec of PALETTE_SPECS) {
|
|
@@ -572,7 +709,6 @@ function palettesToVars(palettes) {
|
|
|
572
709
|
}
|
|
573
710
|
return out;
|
|
574
711
|
}
|
|
575
|
-
var HEX_RE = /^#[0-9a-f]{6}$/i;
|
|
576
712
|
function reconcilePalettesFromCssVars(palettes, cssVars) {
|
|
577
713
|
const next = structuredClone(palettes);
|
|
578
714
|
const consumed = /* @__PURE__ */ new Set();
|
|
@@ -581,16 +717,17 @@ function reconcilePalettesFromCssVars(palettes, cssVars) {
|
|
|
581
717
|
const current = next[spec.label];
|
|
582
718
|
if (current === void 0) continue;
|
|
583
719
|
if (current._imported === true) {
|
|
584
|
-
const
|
|
585
|
-
|
|
586
|
-
|
|
720
|
+
const anchor = cssVars[`--color-${spec.cssNamespace}-500`];
|
|
721
|
+
const anchorOklch = anchor ? cssColorToOklch(anchor) : null;
|
|
722
|
+
if (anchorOklch) {
|
|
723
|
+
next[spec.label] = { ...current, baseColor: anchorOklch, _imported: false };
|
|
587
724
|
syncBaseAnchor(next[spec.label]);
|
|
588
725
|
snapped.add(spec.label);
|
|
589
726
|
} else {
|
|
590
727
|
next[spec.label] = { ...current, _imported: false };
|
|
591
728
|
}
|
|
592
729
|
}
|
|
593
|
-
for (const k of Object.keys(
|
|
730
|
+
for (const k of Object.keys(derivePaletteValues(spec, next[spec.label]))) {
|
|
594
731
|
consumed.add(k);
|
|
595
732
|
}
|
|
596
733
|
}
|
|
@@ -617,6 +754,754 @@ function migratePaletteColorsToOklch(editorConfigs) {
|
|
|
617
754
|
return out;
|
|
618
755
|
}
|
|
619
756
|
|
|
757
|
+
// src/editor/core/themes/migrations/2026-04-24-legacy-keys-and-bg-to-canvas.ts
|
|
758
|
+
var LEGACY_KEY_RENAMES = {
|
|
759
|
+
"--empty": "--page-bg",
|
|
760
|
+
"--empty-attachment": "--page-bg-attachment",
|
|
761
|
+
// Orphan exports dropped from tokens.css; no new home — silently discard.
|
|
762
|
+
"--border-neutral": null,
|
|
763
|
+
// Shadow cleanup: these five tokens were removed (low/zero consumers,
|
|
764
|
+
// aesthetic drift). Dialog migrated onto --shadow-2xl; focus rings moved
|
|
765
|
+
// to their own --ring-focus-* namespace, which themes don't carry by
|
|
766
|
+
// default — tokens.css provides the canonical values.
|
|
767
|
+
"--shadow-app": null,
|
|
768
|
+
"--shadow-card": null,
|
|
769
|
+
"--shadow-overlay": null,
|
|
770
|
+
"--shadow-focus": null,
|
|
771
|
+
"--shadow-glow-green": null
|
|
772
|
+
};
|
|
773
|
+
var BG_TO_CANVAS_PREFIXES = ["--color-bg-", "--surface-bg", "--border-bg", "--text-bg"];
|
|
774
|
+
function migrateBgToCanvas(rawVars) {
|
|
775
|
+
for (const oldKey of Object.keys(rawVars)) {
|
|
776
|
+
for (const prefix of BG_TO_CANVAS_PREFIXES) {
|
|
777
|
+
if (!oldKey.startsWith(prefix)) continue;
|
|
778
|
+
const suffix = oldKey.slice(prefix.length);
|
|
779
|
+
if (suffix && !suffix.startsWith("-")) continue;
|
|
780
|
+
const newKey = prefix.replace("-bg", "-canvas") + suffix;
|
|
781
|
+
if (newKey === oldKey) continue;
|
|
782
|
+
const value = rawVars[oldKey];
|
|
783
|
+
delete rawVars[oldKey];
|
|
784
|
+
if (!(newKey in rawVars)) rawVars[newKey] = value;
|
|
785
|
+
break;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
function migrateLegacyKeys(rawVars) {
|
|
790
|
+
for (const [oldKey, newKey] of Object.entries(LEGACY_KEY_RENAMES)) {
|
|
791
|
+
if (!(oldKey in rawVars)) continue;
|
|
792
|
+
const value = rawVars[oldKey];
|
|
793
|
+
delete rawVars[oldKey];
|
|
794
|
+
if (newKey && !(newKey in rawVars)) rawVars[newKey] = value;
|
|
795
|
+
}
|
|
796
|
+
migrateBgToCanvas(rawVars);
|
|
797
|
+
}
|
|
798
|
+
var colorsAndTypeMigration_2026_04_24_legacyKeysAndBgToCanvas = {
|
|
799
|
+
id: "2026-04-24-legacy-keys-and-bg-to-canvas",
|
|
800
|
+
fromVersion: 0,
|
|
801
|
+
toVersion: 1,
|
|
802
|
+
appliesTo: "colors-and-type",
|
|
803
|
+
apply(rawVars) {
|
|
804
|
+
const out = { ...rawVars };
|
|
805
|
+
migrateLegacyKeys(out);
|
|
806
|
+
return out;
|
|
807
|
+
}
|
|
808
|
+
};
|
|
809
|
+
|
|
810
|
+
// src/editor/core/themes/migrations/2026-04-24-component-prefix-and-suffix-renames.ts
|
|
811
|
+
var COMPONENT_PREFIX_RENAMES = {
|
|
812
|
+
"--segment-": "--segmentedcontrol-",
|
|
813
|
+
"--collapsible-": "--collapsiblesection-",
|
|
814
|
+
"--progress-": "--progressbar-",
|
|
815
|
+
"--section-divider-": "--sectiondivider-",
|
|
816
|
+
"--radio-": "--radiobutton-",
|
|
817
|
+
"--inline-edit-": "--inlineeditactions-"
|
|
818
|
+
};
|
|
819
|
+
var COMPONENT_SUFFIX_RENAMES = {
|
|
820
|
+
progressbar: [["-track-bg", "-track-surface"]],
|
|
821
|
+
inlineeditactions: [
|
|
822
|
+
["-bg-hover", "-hover-surface"],
|
|
823
|
+
["-bg", "-surface"]
|
|
824
|
+
]
|
|
825
|
+
};
|
|
826
|
+
var componentMigration_2026_04_24_prefixAndSuffixRenames = {
|
|
827
|
+
id: "2026-04-24-component-prefix-and-suffix-renames",
|
|
828
|
+
fromVersion: 0,
|
|
829
|
+
toVersion: 1,
|
|
830
|
+
appliesTo: "component-config",
|
|
831
|
+
apply(rawVars, meta) {
|
|
832
|
+
const component = meta.component ?? "";
|
|
833
|
+
const out = {};
|
|
834
|
+
const suffixRules = COMPONENT_SUFFIX_RENAMES[component] ?? [];
|
|
835
|
+
for (const [oldKey, value] of Object.entries(rawVars)) {
|
|
836
|
+
let key = oldKey;
|
|
837
|
+
if (key === "--detail-nav-bg") key = "--detailnav-surface";
|
|
838
|
+
for (const [oldPrefix, newPrefix] of Object.entries(COMPONENT_PREFIX_RENAMES)) {
|
|
839
|
+
if (key.startsWith(oldPrefix)) {
|
|
840
|
+
key = newPrefix + key.slice(oldPrefix.length);
|
|
841
|
+
break;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
for (const [oldSuffix, newSuffix] of suffixRules) {
|
|
845
|
+
if (key.endsWith(oldSuffix)) {
|
|
846
|
+
key = key.slice(0, -oldSuffix.length) + newSuffix;
|
|
847
|
+
break;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
if (!(key in out)) out[key] = value;
|
|
851
|
+
}
|
|
852
|
+
return out;
|
|
853
|
+
}
|
|
854
|
+
};
|
|
855
|
+
|
|
856
|
+
// src/editor/core/themes/migrations/2026-04-27-segmentedcontrol-disabled-flatten.ts
|
|
857
|
+
var OPTION_DISABLED_PREFIX = "--segmentedcontrol-option-disabled-";
|
|
858
|
+
var DISABLED_PREFIX = "--segmentedcontrol-disabled-";
|
|
859
|
+
var SELECTED_DISABLED_PREFIX = "--segmentedcontrol-selected-disabled-";
|
|
860
|
+
var SELECTED_HOVER_PREFIX = "--segmentedcontrol-selected-hover-";
|
|
861
|
+
var componentMigration_2026_04_27_segmentedcontrolDisabledFlatten = {
|
|
862
|
+
id: "2026-04-27-segmentedcontrol-disabled-flatten",
|
|
863
|
+
fromVersion: 1,
|
|
864
|
+
toVersion: 2,
|
|
865
|
+
appliesTo: "component-config",
|
|
866
|
+
apply(rawVars, meta) {
|
|
867
|
+
if (meta.component !== "segmentedcontrol") return { ...rawVars };
|
|
868
|
+
const out = {};
|
|
869
|
+
for (const [oldKey, value] of Object.entries(rawVars)) {
|
|
870
|
+
let key = oldKey;
|
|
871
|
+
if (key.startsWith(SELECTED_DISABLED_PREFIX)) continue;
|
|
872
|
+
if (key.startsWith(SELECTED_HOVER_PREFIX)) continue;
|
|
873
|
+
if (key.startsWith(OPTION_DISABLED_PREFIX)) {
|
|
874
|
+
key = DISABLED_PREFIX + key.slice(OPTION_DISABLED_PREFIX.length);
|
|
875
|
+
}
|
|
876
|
+
if (!(key in out)) out[key] = value;
|
|
877
|
+
}
|
|
878
|
+
return out;
|
|
879
|
+
}
|
|
880
|
+
};
|
|
881
|
+
|
|
882
|
+
// src/editor/core/themes/migrations/2026-05-08-collapsiblesection-variant-namespace.ts
|
|
883
|
+
var PREFIX = "--collapsiblesection-";
|
|
884
|
+
var STATE_NAMES = /* @__PURE__ */ new Set(["default", "hover", "active", "expanded"]);
|
|
885
|
+
var componentMigration_2026_05_08_collapsiblesectionVariantNamespace = {
|
|
886
|
+
id: "2026-05-08-collapsiblesection-variant-namespace",
|
|
887
|
+
fromVersion: 2,
|
|
888
|
+
toVersion: 3,
|
|
889
|
+
appliesTo: "component-config",
|
|
890
|
+
apply(rawVars, meta) {
|
|
891
|
+
if (meta.component !== "collapsiblesection") return { ...rawVars };
|
|
892
|
+
const out = {};
|
|
893
|
+
for (const [oldKey, value] of Object.entries(rawVars)) {
|
|
894
|
+
let key = oldKey;
|
|
895
|
+
if (key.startsWith(PREFIX)) {
|
|
896
|
+
const tail = key.slice(PREFIX.length);
|
|
897
|
+
const firstSegment = tail.split("-", 1)[0];
|
|
898
|
+
if (STATE_NAMES.has(firstSegment)) {
|
|
899
|
+
key = `${PREFIX}container-${tail}`;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
if (!(key in out)) out[key] = value;
|
|
903
|
+
}
|
|
904
|
+
return out;
|
|
905
|
+
}
|
|
906
|
+
};
|
|
907
|
+
|
|
908
|
+
// src/editor/core/themes/migrations/2026-05-08-collapsiblesection-frame-and-cleanup.ts
|
|
909
|
+
var PFX = "--collapsiblesection-";
|
|
910
|
+
var componentMigration_2026_05_08_collapsiblesectionFrameAndCleanup = {
|
|
911
|
+
id: "2026-05-08-collapsiblesection-frame-and-cleanup",
|
|
912
|
+
fromVersion: 3,
|
|
913
|
+
toVersion: 4,
|
|
914
|
+
appliesTo: "component-config",
|
|
915
|
+
apply(rawVars, meta) {
|
|
916
|
+
if (meta.component !== "collapsiblesection") return { ...rawVars };
|
|
917
|
+
const out = {};
|
|
918
|
+
for (const prop of ["surface", "border", "border-width", "radius"]) {
|
|
919
|
+
const src = `${PFX}container-default-${prop}`;
|
|
920
|
+
if (src in rawVars) {
|
|
921
|
+
out[`${PFX}container-frame-${prop}`] = rawVars[src];
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
925
|
+
if (/^--collapsiblesection-chromeless-(default|hover|active)-(border|border-width|radius)$/.test(key)) continue;
|
|
926
|
+
if (/^--collapsiblesection-container-(hover|active)-(border|border-width|radius)$/.test(key)) continue;
|
|
927
|
+
if (/^--collapsiblesection-container-default-(border|border-width|radius)$/.test(key)) continue;
|
|
928
|
+
if (/^--collapsiblesection-divider-(default|hover|active)-radius$/.test(key)) continue;
|
|
929
|
+
if (/^--collapsiblesection-(chromeless|divider|container)-expanded-(border|border-width|radius)$/.test(key)) continue;
|
|
930
|
+
if (/^--collapsiblesection-(chromeless|divider)-expanded-surface$/.test(key)) continue;
|
|
931
|
+
if (!(key in out)) out[key] = value;
|
|
932
|
+
}
|
|
933
|
+
return out;
|
|
934
|
+
}
|
|
935
|
+
};
|
|
936
|
+
|
|
937
|
+
// src/editor/core/themes/migrations/2026-05-10-sectiondivider-gradient-stops.ts
|
|
938
|
+
var PFX2 = "--sectiondivider-";
|
|
939
|
+
var VARIANTS = ["canvas", "neutral", "alternate", "primary", "accent", "special"];
|
|
940
|
+
var OLD_STOP_RE = /^--sectiondivider-(canvas|neutral|alternate|primary|accent|special)-gradient-stop-\d+$/;
|
|
941
|
+
var componentMigration_2026_05_10_sectiondividerGradientStops = {
|
|
942
|
+
id: "2026-05-10-sectiondivider-gradient-stops",
|
|
943
|
+
fromVersion: 4,
|
|
944
|
+
toVersion: 5,
|
|
945
|
+
appliesTo: "component-config",
|
|
946
|
+
apply(rawVars, meta) {
|
|
947
|
+
if (meta.component !== "sectiondivider") return { ...rawVars };
|
|
948
|
+
const out = {};
|
|
949
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
950
|
+
if (OLD_STOP_RE.test(key)) continue;
|
|
951
|
+
out[key] = value;
|
|
952
|
+
}
|
|
953
|
+
const setIfMissing = (key, fallback) => {
|
|
954
|
+
if (!(key in out)) out[key] = fallback;
|
|
955
|
+
};
|
|
956
|
+
for (const v of VARIANTS) {
|
|
957
|
+
const old1 = rawVars[`${PFX2}${v}-gradient-stop-1`];
|
|
958
|
+
const old2 = rawVars[`${PFX2}${v}-gradient-stop-2`];
|
|
959
|
+
const old4 = rawVars[`${PFX2}${v}-gradient-stop-4`];
|
|
960
|
+
setIfMissing(`${PFX2}${v}-gradient-angle`, "--gradient-angle-diagonal");
|
|
961
|
+
setIfMissing(`${PFX2}${v}-gradient-stop-1-color`, old1 ?? `--surface-${v}-highest`);
|
|
962
|
+
setIfMissing(`${PFX2}${v}-gradient-stop-1-position`, "--gradient-stop-start");
|
|
963
|
+
setIfMissing(`${PFX2}${v}-gradient-stop-2-color`, old2 ?? `--surface-${v}-higher`);
|
|
964
|
+
setIfMissing(`${PFX2}${v}-gradient-stop-2-position`, "--gradient-stop-mid");
|
|
965
|
+
setIfMissing(`${PFX2}${v}-gradient-stop-3-color`, old4 ?? `--surface-${v}`);
|
|
966
|
+
setIfMissing(`${PFX2}${v}-gradient-stop-3-position`, "--gradient-stop-end");
|
|
967
|
+
}
|
|
968
|
+
return out;
|
|
969
|
+
}
|
|
970
|
+
};
|
|
971
|
+
|
|
972
|
+
// src/editor/core/themes/migrations/2026-05-13-primary-to-brand.ts
|
|
973
|
+
var PALETTE_STEPS2 = ["100", "200", "300", "400", "500", "600", "700", "800", "850", "900", "950"];
|
|
974
|
+
var SURFACE_SUFFIXES = ["lowest", "lower", "low", "high", "higher", "highest"];
|
|
975
|
+
var BORDER_SUFFIXES = ["faint", "subtle", "medium", "strong"];
|
|
976
|
+
var TEXT_SUFFIXES = ["secondary", "tertiary", "muted", "disabled"];
|
|
977
|
+
var RENAME_MAP = (() => {
|
|
978
|
+
const m = {};
|
|
979
|
+
for (const step of PALETTE_STEPS2) m[`--color-primary-${step}`] = `--color-brand-${step}`;
|
|
980
|
+
m["--surface-primary"] = "--surface-brand";
|
|
981
|
+
for (const suf of SURFACE_SUFFIXES) m[`--surface-primary-${suf}`] = `--surface-brand-${suf}`;
|
|
982
|
+
m["--border-primary"] = "--border-brand";
|
|
983
|
+
for (const suf of BORDER_SUFFIXES) m[`--border-primary-${suf}`] = `--border-brand-${suf}`;
|
|
984
|
+
m["--text-primary-color"] = "--text-brand";
|
|
985
|
+
for (const suf of TEXT_SUFFIXES) m[`--text-primary-${suf}`] = `--text-brand-${suf}`;
|
|
986
|
+
return m;
|
|
987
|
+
})();
|
|
988
|
+
function renameToken(name) {
|
|
989
|
+
return RENAME_MAP[name] ?? name;
|
|
990
|
+
}
|
|
991
|
+
function renameKeys(rawVars) {
|
|
992
|
+
const out = {};
|
|
993
|
+
for (const [k, v] of Object.entries(rawVars)) {
|
|
994
|
+
out[renameToken(k)] = v;
|
|
995
|
+
}
|
|
996
|
+
return out;
|
|
997
|
+
}
|
|
998
|
+
function renameKeysAndValues(rawVars) {
|
|
999
|
+
const out = {};
|
|
1000
|
+
for (const [k, v] of Object.entries(rawVars)) {
|
|
1001
|
+
out[renameToken(k)] = renameToken(v);
|
|
1002
|
+
}
|
|
1003
|
+
return out;
|
|
1004
|
+
}
|
|
1005
|
+
var colorsAndTypeMigration_2026_05_13_primaryToBrand = {
|
|
1006
|
+
id: "2026-05-13-primary-to-brand-theme",
|
|
1007
|
+
fromVersion: 1,
|
|
1008
|
+
toVersion: 2,
|
|
1009
|
+
appliesTo: "colors-and-type",
|
|
1010
|
+
apply: renameKeys
|
|
1011
|
+
};
|
|
1012
|
+
var componentMigration_2026_05_13_primaryToBrand = {
|
|
1013
|
+
id: "2026-05-13-primary-to-brand-component",
|
|
1014
|
+
fromVersion: 5,
|
|
1015
|
+
toVersion: 6,
|
|
1016
|
+
appliesTo: "component-config",
|
|
1017
|
+
apply: renameKeysAndValues
|
|
1018
|
+
};
|
|
1019
|
+
|
|
1020
|
+
// src/editor/core/themes/migrations/2026-05-19-collapsiblesection-drop-frame-surface.ts
|
|
1021
|
+
function dropFrameSurface(rawVars, meta) {
|
|
1022
|
+
if (meta.component !== "collapsiblesection") return rawVars;
|
|
1023
|
+
const { "--collapsiblesection-container-frame-surface": _drop, ...rest } = rawVars;
|
|
1024
|
+
return rest;
|
|
1025
|
+
}
|
|
1026
|
+
var componentMigration_2026_05_19_collapsiblesectionDropFrameSurface = {
|
|
1027
|
+
id: "2026-05-19-collapsiblesection-drop-frame-surface",
|
|
1028
|
+
fromVersion: 6,
|
|
1029
|
+
toVersion: 7,
|
|
1030
|
+
appliesTo: "component-config",
|
|
1031
|
+
apply: dropFrameSurface
|
|
1032
|
+
};
|
|
1033
|
+
|
|
1034
|
+
// src/editor/core/themes/migrations/2026-05-19-sectiondivider-rich-gradient.ts
|
|
1035
|
+
var FLAT_RE = /^--sectiondivider-(canvas|neutral|alternate|primary|accent|special)-gradient-(angle|stop-[123]-(color|position))$/;
|
|
1036
|
+
var componentMigration_2026_05_19_sectiondividerRichGradient = {
|
|
1037
|
+
id: "2026-05-19-sectiondivider-rich-gradient",
|
|
1038
|
+
fromVersion: 7,
|
|
1039
|
+
toVersion: 8,
|
|
1040
|
+
appliesTo: "component-config",
|
|
1041
|
+
apply(rawVars, meta) {
|
|
1042
|
+
if (meta.component !== "sectiondivider") return { ...rawVars };
|
|
1043
|
+
const out = {};
|
|
1044
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
1045
|
+
if (FLAT_RE.test(key)) continue;
|
|
1046
|
+
out[key] = value;
|
|
1047
|
+
}
|
|
1048
|
+
return out;
|
|
1049
|
+
}
|
|
1050
|
+
};
|
|
1051
|
+
|
|
1052
|
+
// src/editor/core/themes/migrations/2026-05-20-sectiondivider-slim-variants.ts
|
|
1053
|
+
var VARIANTS2 = ["lg", "md", "sm"];
|
|
1054
|
+
var SUFFIX_RENAMES = [
|
|
1055
|
+
[/-title-border-width$/, "-title-outline-width"],
|
|
1056
|
+
[/-title-stroke-color$/, "-title-outline-color"],
|
|
1057
|
+
[
|
|
1058
|
+
/^--sectiondivider-(canvas|neutral|alternate|primary|accent|special)-padding$/,
|
|
1059
|
+
"--sectiondivider-$1-spacing"
|
|
1060
|
+
]
|
|
1061
|
+
];
|
|
1062
|
+
function renameKeySuffix(key) {
|
|
1063
|
+
for (const [re, repl] of SUFFIX_RENAMES) {
|
|
1064
|
+
if (re.test(key)) return key.replace(re, repl);
|
|
1065
|
+
}
|
|
1066
|
+
return key;
|
|
1067
|
+
}
|
|
1068
|
+
function splitFamilyKey(key) {
|
|
1069
|
+
const m = key.match(/^--sectiondivider-(canvas|neutral|alternate|primary|accent|special)-(.+)$/);
|
|
1070
|
+
if (!m) return null;
|
|
1071
|
+
return { family: m[1], suffix: m[2] };
|
|
1072
|
+
}
|
|
1073
|
+
var componentMigration_2026_05_20_sectiondividerSlimVariants = {
|
|
1074
|
+
id: "2026-05-20-sectiondivider-slim-variants",
|
|
1075
|
+
fromVersion: 8,
|
|
1076
|
+
toVersion: 9,
|
|
1077
|
+
appliesTo: "component-config",
|
|
1078
|
+
apply(rawVars, meta) {
|
|
1079
|
+
if (meta.component !== "sectiondivider") return { ...rawVars };
|
|
1080
|
+
const out = {};
|
|
1081
|
+
const canvasValues = {};
|
|
1082
|
+
for (const [rawKey, value] of Object.entries(rawVars)) {
|
|
1083
|
+
const key = renameKeySuffix(rawKey);
|
|
1084
|
+
const parts = splitFamilyKey(key);
|
|
1085
|
+
if (!parts) {
|
|
1086
|
+
out[key] = value;
|
|
1087
|
+
continue;
|
|
1088
|
+
}
|
|
1089
|
+
if (parts.family !== "canvas") continue;
|
|
1090
|
+
canvasValues[parts.suffix] = value;
|
|
1091
|
+
}
|
|
1092
|
+
for (const suffix of Object.keys(canvasValues)) {
|
|
1093
|
+
for (const v of VARIANTS2) {
|
|
1094
|
+
out[`--sectiondivider-${v}-${suffix}`] = canvasValues[suffix];
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
return out;
|
|
1098
|
+
}
|
|
1099
|
+
};
|
|
1100
|
+
|
|
1101
|
+
// src/editor/core/themes/migrations/2026-05-21-sectiondivider-spacing-to-padding.ts
|
|
1102
|
+
var componentMigration_2026_05_21_sectiondividerSpacingToPadding = {
|
|
1103
|
+
id: "2026-05-21-sectiondivider-spacing-to-padding",
|
|
1104
|
+
fromVersion: 9,
|
|
1105
|
+
toVersion: 10,
|
|
1106
|
+
appliesTo: "component-config",
|
|
1107
|
+
apply(rawVars, meta) {
|
|
1108
|
+
if (meta.component !== "sectiondivider") return { ...rawVars };
|
|
1109
|
+
const out = {};
|
|
1110
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
1111
|
+
const renamed = key.replace(
|
|
1112
|
+
/^--sectiondivider-(lg|md|sm)-spacing$/,
|
|
1113
|
+
"--sectiondivider-$1-padding"
|
|
1114
|
+
);
|
|
1115
|
+
out[renamed] = value;
|
|
1116
|
+
}
|
|
1117
|
+
return out;
|
|
1118
|
+
}
|
|
1119
|
+
};
|
|
1120
|
+
|
|
1121
|
+
// src/editor/core/themes/migrations/2026-05-22-sectiondivider-intrinsics-to-css.ts
|
|
1122
|
+
var componentMigration_2026_05_22_sectiondividerIntrinsicsToCss = {
|
|
1123
|
+
id: "2026-05-22-sectiondivider-intrinsics-to-css",
|
|
1124
|
+
fromVersion: 10,
|
|
1125
|
+
toVersion: 11,
|
|
1126
|
+
appliesTo: "component-config",
|
|
1127
|
+
apply(rawVars, meta) {
|
|
1128
|
+
if (meta.component !== "sectiondivider") return { ...rawVars };
|
|
1129
|
+
const VARIANTS4 = ["lg", "md", "sm"];
|
|
1130
|
+
const prefix = "--sectiondivider-";
|
|
1131
|
+
const dropped = /* @__PURE__ */ new Set();
|
|
1132
|
+
for (const v of VARIANTS4) {
|
|
1133
|
+
dropped.add(`${prefix}${v}-show-eyebrow`);
|
|
1134
|
+
dropped.add(`${prefix}${v}-show-description`);
|
|
1135
|
+
dropped.add(`${prefix}${v}-show-hairline`);
|
|
1136
|
+
dropped.add(`${prefix}${v}-hairline`);
|
|
1137
|
+
dropped.add(`${prefix}${v}-eyebrow-uppercase`);
|
|
1138
|
+
}
|
|
1139
|
+
const out = {};
|
|
1140
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
1141
|
+
if (dropped.has(key)) continue;
|
|
1142
|
+
out[key] = value;
|
|
1143
|
+
}
|
|
1144
|
+
for (const v of VARIANTS4) {
|
|
1145
|
+
const showEyebrow = rawVars[`${prefix}${v}-show-eyebrow`];
|
|
1146
|
+
if (showEyebrow !== void 0) {
|
|
1147
|
+
out[`${prefix}${v}-eyebrow-display`] = showEyebrow === "1" ? "block" : "none";
|
|
1148
|
+
}
|
|
1149
|
+
const showDesc = rawVars[`${prefix}${v}-show-description`];
|
|
1150
|
+
if (showDesc !== void 0) {
|
|
1151
|
+
out[`${prefix}${v}-description-display`] = showDesc === "1" ? "flex" : "none";
|
|
1152
|
+
}
|
|
1153
|
+
const showHair = rawVars[`${prefix}${v}-show-hairline`];
|
|
1154
|
+
const oldHair = rawVars[`${prefix}${v}-hairline`];
|
|
1155
|
+
const oldHairIsPos = typeof oldHair === "string" && oldHair !== "" && oldHair !== "off";
|
|
1156
|
+
let newHair;
|
|
1157
|
+
if (showHair === "") newHair = "none";
|
|
1158
|
+
else if (showHair === "1") newHair = oldHairIsPos ? oldHair : "above-label";
|
|
1159
|
+
else if (oldHair !== void 0) newHair = oldHairIsPos ? oldHair : "none";
|
|
1160
|
+
if (newHair !== void 0) {
|
|
1161
|
+
out[`${prefix}${v}-hairline`] = newHair;
|
|
1162
|
+
}
|
|
1163
|
+
const upper = rawVars[`${prefix}${v}-eyebrow-uppercase`];
|
|
1164
|
+
if (upper !== void 0) {
|
|
1165
|
+
out[`${prefix}${v}-eyebrow-text-transform`] = upper === "1" ? "uppercase" : "none";
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
return out;
|
|
1169
|
+
}
|
|
1170
|
+
};
|
|
1171
|
+
|
|
1172
|
+
// src/editor/core/themes/migrations/2026-05-24-segmentedcontrol-divider-inset.ts
|
|
1173
|
+
var componentMigration_2026_05_24_segmentedcontrolDividerInset = {
|
|
1174
|
+
id: "2026-05-24-segmentedcontrol-divider-inset",
|
|
1175
|
+
fromVersion: 11,
|
|
1176
|
+
toVersion: 12,
|
|
1177
|
+
appliesTo: "component-config",
|
|
1178
|
+
apply(rawVars, meta) {
|
|
1179
|
+
if (meta.component !== "segmentedcontrol") return { ...rawVars };
|
|
1180
|
+
const out = {};
|
|
1181
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
1182
|
+
if (key === "--segmentedcontrol-divider-height") continue;
|
|
1183
|
+
out[key] = value;
|
|
1184
|
+
}
|
|
1185
|
+
return out;
|
|
1186
|
+
}
|
|
1187
|
+
};
|
|
1188
|
+
|
|
1189
|
+
// src/editor/core/themes/migrations/2026-05-24-promote-state-shared-tokens.ts
|
|
1190
|
+
var BUTTON_VARIANTS = ["primary", "secondary", "outline", "success", "danger", "warning"];
|
|
1191
|
+
var BUTTON_STATES = ["hover", "disabled"];
|
|
1192
|
+
var BUTTON_PROPS = ["padding", "radius", "border-width"];
|
|
1193
|
+
var buttonDeadKeys = new Set(
|
|
1194
|
+
BUTTON_VARIANTS.flatMap(
|
|
1195
|
+
(v) => BUTTON_STATES.flatMap(
|
|
1196
|
+
(s) => BUTTON_PROPS.map((p) => `--button-${v}-${s}-${p}`)
|
|
1197
|
+
)
|
|
1198
|
+
)
|
|
1199
|
+
);
|
|
1200
|
+
var segmentedcontrolDeadKeys = /* @__PURE__ */ new Set([
|
|
1201
|
+
"--segmentedcontrol-selected-icon-size",
|
|
1202
|
+
"--segmentedcontrol-option-hover-icon-size",
|
|
1203
|
+
"--segmentedcontrol-disabled-icon-size"
|
|
1204
|
+
]);
|
|
1205
|
+
var componentMigration_2026_05_24_promoteStateSharedTokens = {
|
|
1206
|
+
id: "2026-05-24-promote-state-shared-tokens",
|
|
1207
|
+
fromVersion: 12,
|
|
1208
|
+
toVersion: 13,
|
|
1209
|
+
appliesTo: "component-config",
|
|
1210
|
+
apply(rawVars, meta) {
|
|
1211
|
+
const dead = meta.component === "button" ? buttonDeadKeys : meta.component === "segmentedcontrol" ? segmentedcontrolDeadKeys : null;
|
|
1212
|
+
if (!dead) return { ...rawVars };
|
|
1213
|
+
const out = {};
|
|
1214
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
1215
|
+
if (dead.has(key)) continue;
|
|
1216
|
+
out[key] = value;
|
|
1217
|
+
}
|
|
1218
|
+
return out;
|
|
1219
|
+
}
|
|
1220
|
+
};
|
|
1221
|
+
|
|
1222
|
+
// src/editor/core/themes/migrations/2026-05-24-progressbar-collapse-variants.ts
|
|
1223
|
+
var PRIMARY_PREFIX = "--progressbar-primary-";
|
|
1224
|
+
var NEW_PREFIX = "--progressbar-";
|
|
1225
|
+
var DROP_PREFIXES = [
|
|
1226
|
+
"--progressbar-success-",
|
|
1227
|
+
"--progressbar-warning-",
|
|
1228
|
+
"--progressbar-danger-",
|
|
1229
|
+
"--progressbar-info-"
|
|
1230
|
+
];
|
|
1231
|
+
var componentMigration_2026_05_24_progressbarCollapseVariants = {
|
|
1232
|
+
id: "2026-05-24-progressbar-collapse-variants",
|
|
1233
|
+
fromVersion: 13,
|
|
1234
|
+
toVersion: 14,
|
|
1235
|
+
appliesTo: "component-config",
|
|
1236
|
+
apply(rawVars, meta) {
|
|
1237
|
+
if (meta.component !== "progressbar") return { ...rawVars };
|
|
1238
|
+
const out = {};
|
|
1239
|
+
for (const [oldKey, value] of Object.entries(rawVars)) {
|
|
1240
|
+
if (DROP_PREFIXES.some((p) => oldKey.startsWith(p))) continue;
|
|
1241
|
+
const key = oldKey.startsWith(PRIMARY_PREFIX) ? NEW_PREFIX + oldKey.slice(PRIMARY_PREFIX.length) : oldKey;
|
|
1242
|
+
if (!(key in out)) out[key] = value;
|
|
1243
|
+
}
|
|
1244
|
+
return out;
|
|
1245
|
+
}
|
|
1246
|
+
};
|
|
1247
|
+
|
|
1248
|
+
// src/editor/core/themes/migrations/2026-05-24-collapsiblesection-drop-active-state.ts
|
|
1249
|
+
function dropActiveState(rawVars, meta) {
|
|
1250
|
+
if (meta.component !== "collapsiblesection") return rawVars;
|
|
1251
|
+
const re = /^--collapsiblesection-(chromeless|divider|container)-active-/;
|
|
1252
|
+
const out = {};
|
|
1253
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
1254
|
+
if (re.test(key)) continue;
|
|
1255
|
+
out[key] = value;
|
|
1256
|
+
}
|
|
1257
|
+
return out;
|
|
1258
|
+
}
|
|
1259
|
+
var componentMigration_2026_05_24_collapsiblesectionDropActiveState = {
|
|
1260
|
+
id: "2026-05-24-collapsiblesection-drop-active-state",
|
|
1261
|
+
fromVersion: 14,
|
|
1262
|
+
toVersion: 15,
|
|
1263
|
+
appliesTo: "component-config",
|
|
1264
|
+
apply: dropActiveState
|
|
1265
|
+
};
|
|
1266
|
+
|
|
1267
|
+
// src/editor/core/themes/migrations/2026-05-25-cornerbadge-flatten-variants.ts
|
|
1268
|
+
var VARIANTS3 = ["primary", "accent", "neutral", "alternate", "canvas", "special", "success", "warning", "danger", "info"];
|
|
1269
|
+
var RE = new RegExp(`^--corner-badge-(${VARIANTS3.join("|")})-(.+)$`);
|
|
1270
|
+
var CURRENT_COLOR_PROPS = /* @__PURE__ */ new Set(["surface", "border", "text"]);
|
|
1271
|
+
function flattenVariants(rawVars, meta) {
|
|
1272
|
+
if (meta.component !== "cornerbadge") return rawVars;
|
|
1273
|
+
const out = {};
|
|
1274
|
+
const collected = /* @__PURE__ */ new Map();
|
|
1275
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
1276
|
+
const m = key.match(RE);
|
|
1277
|
+
if (m) {
|
|
1278
|
+
const prop = m[2];
|
|
1279
|
+
if (CURRENT_COLOR_PROPS.has(prop)) {
|
|
1280
|
+
out[key] = value;
|
|
1281
|
+
continue;
|
|
1282
|
+
}
|
|
1283
|
+
if (!collected.has(prop)) collected.set(prop, value);
|
|
1284
|
+
continue;
|
|
1285
|
+
}
|
|
1286
|
+
out[key] = value;
|
|
1287
|
+
}
|
|
1288
|
+
for (const [prop, value] of collected) {
|
|
1289
|
+
const flatKey = `--corner-badge-${prop}`;
|
|
1290
|
+
if (!(flatKey in out)) out[flatKey] = value;
|
|
1291
|
+
}
|
|
1292
|
+
return out;
|
|
1293
|
+
}
|
|
1294
|
+
var componentMigration_2026_05_25_cornerbadgeFlattenVariants = {
|
|
1295
|
+
id: "2026-05-25-cornerbadge-flatten-variants",
|
|
1296
|
+
fromVersion: 15,
|
|
1297
|
+
toVersion: 16,
|
|
1298
|
+
appliesTo: "component-config",
|
|
1299
|
+
apply: flattenVariants
|
|
1300
|
+
};
|
|
1301
|
+
|
|
1302
|
+
// src/editor/core/themes/migrations/2026-05-26-drop-overlay-extra-stops.ts
|
|
1303
|
+
var DROPPED_TO_KEPT = {
|
|
1304
|
+
"--overlay-lowest": "--overlay-low",
|
|
1305
|
+
"--overlay-lower": "--overlay-low",
|
|
1306
|
+
"--overlay-higher": "--overlay-high",
|
|
1307
|
+
"--overlay-highest": "--overlay-high"
|
|
1308
|
+
};
|
|
1309
|
+
var colorsAndTypeMigration_2026_05_26_dropOverlayExtraStops = {
|
|
1310
|
+
id: "2026-05-26-drop-overlay-extra-stops-theme",
|
|
1311
|
+
fromVersion: 2,
|
|
1312
|
+
toVersion: 3,
|
|
1313
|
+
appliesTo: "colors-and-type",
|
|
1314
|
+
apply(rawVars) {
|
|
1315
|
+
const out = {};
|
|
1316
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
1317
|
+
if (key in DROPPED_TO_KEPT) continue;
|
|
1318
|
+
out[key] = value;
|
|
1319
|
+
}
|
|
1320
|
+
return out;
|
|
1321
|
+
}
|
|
1322
|
+
};
|
|
1323
|
+
var componentMigration_2026_05_26_dropOverlayExtraStops = {
|
|
1324
|
+
id: "2026-05-26-drop-overlay-extra-stops-component",
|
|
1325
|
+
fromVersion: 16,
|
|
1326
|
+
toVersion: 17,
|
|
1327
|
+
appliesTo: "component-config",
|
|
1328
|
+
apply(rawVars) {
|
|
1329
|
+
const out = {};
|
|
1330
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
1331
|
+
out[key] = DROPPED_TO_KEPT[value] ?? value;
|
|
1332
|
+
}
|
|
1333
|
+
return out;
|
|
1334
|
+
}
|
|
1335
|
+
};
|
|
1336
|
+
|
|
1337
|
+
// src/editor/core/themes/migrations/2026-05-29-tabbar-indicator-thickness-to-per-state-width.ts
|
|
1338
|
+
var TABBAR_STATES = ["default", "hover", "active", "disabled"];
|
|
1339
|
+
var OLD_KEY = "--tabbar-bar-indicator-thickness";
|
|
1340
|
+
var FALLBACK = "--border-width-2";
|
|
1341
|
+
var componentMigration_2026_05_29_tabbarIndicatorThicknessToPerStateWidth = {
|
|
1342
|
+
id: "2026-05-29-tabbar-indicator-thickness-to-per-state-width",
|
|
1343
|
+
fromVersion: 17,
|
|
1344
|
+
toVersion: 18,
|
|
1345
|
+
appliesTo: "component-config",
|
|
1346
|
+
apply(rawVars, meta) {
|
|
1347
|
+
if (meta.component !== "tabbar") return { ...rawVars };
|
|
1348
|
+
const seed = rawVars[OLD_KEY] ?? FALLBACK;
|
|
1349
|
+
const out = {};
|
|
1350
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
1351
|
+
if (key === OLD_KEY) continue;
|
|
1352
|
+
out[key] = value;
|
|
1353
|
+
}
|
|
1354
|
+
for (const state of TABBAR_STATES) {
|
|
1355
|
+
const newKey = `--tabbar-${state}-indicator-border-width`;
|
|
1356
|
+
if (!(newKey in out)) out[newKey] = seed;
|
|
1357
|
+
}
|
|
1358
|
+
return out;
|
|
1359
|
+
}
|
|
1360
|
+
};
|
|
1361
|
+
|
|
1362
|
+
// src/editor/core/themes/migrations/2026-05-29-segmentedcontrol-small-divider-rename.ts
|
|
1363
|
+
var RENAMES = {
|
|
1364
|
+
"--segmentedcontrol-divider-small-thickness": "--segmentedcontrol-small-divider-thickness",
|
|
1365
|
+
"--segmentedcontrol-divider-small-inset": "--segmentedcontrol-small-divider-inset"
|
|
1366
|
+
};
|
|
1367
|
+
var componentMigration_2026_05_29_segmentedcontrolSmallDividerRename = {
|
|
1368
|
+
id: "2026-05-29-segmentedcontrol-small-divider-rename",
|
|
1369
|
+
fromVersion: 18,
|
|
1370
|
+
toVersion: 19,
|
|
1371
|
+
appliesTo: "component-config",
|
|
1372
|
+
apply(rawVars, meta) {
|
|
1373
|
+
if (meta.component !== "segmentedcontrol") return { ...rawVars };
|
|
1374
|
+
const out = {};
|
|
1375
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
1376
|
+
out[RENAMES[key] ?? key] = value;
|
|
1377
|
+
}
|
|
1378
|
+
return out;
|
|
1379
|
+
}
|
|
1380
|
+
};
|
|
1381
|
+
|
|
1382
|
+
// src/editor/core/themes/migrations/2026-05-29-toggle-derive-track-from-thumb.ts
|
|
1383
|
+
var componentMigration_2026_05_29_toggleDeriveTrackFromThumb = {
|
|
1384
|
+
id: "2026-05-29-toggle-derive-track-from-thumb",
|
|
1385
|
+
fromVersion: 19,
|
|
1386
|
+
toVersion: 20,
|
|
1387
|
+
appliesTo: "component-config",
|
|
1388
|
+
apply(rawVars, meta) {
|
|
1389
|
+
if (meta.component !== "toggle") return { ...rawVars };
|
|
1390
|
+
const out = {};
|
|
1391
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
1392
|
+
if (key === "--toggle-track-width" || key === "--toggle-track-thickness") continue;
|
|
1393
|
+
out[key] = value;
|
|
1394
|
+
}
|
|
1395
|
+
if (!("--toggle-track-padding" in out)) {
|
|
1396
|
+
out["--toggle-track-padding"] = "--space-2";
|
|
1397
|
+
}
|
|
1398
|
+
return out;
|
|
1399
|
+
}
|
|
1400
|
+
};
|
|
1401
|
+
|
|
1402
|
+
// src/editor/core/themes/migrations/2026-08-13-drop-legacy-shape-space-keys.ts
|
|
1403
|
+
var DROPPED = /* @__PURE__ */ new Set([
|
|
1404
|
+
"--badge-trait-radius",
|
|
1405
|
+
"--badge-trait-padding",
|
|
1406
|
+
"--sectiondivider-padding",
|
|
1407
|
+
"--dialog-primary-default-radius",
|
|
1408
|
+
"--dialog-primary-default-padding",
|
|
1409
|
+
"--dialog-primary-hover-radius",
|
|
1410
|
+
"--dialog-primary-hover-padding",
|
|
1411
|
+
"--dialog-secondary-default-radius",
|
|
1412
|
+
"--dialog-secondary-default-padding",
|
|
1413
|
+
"--dialog-secondary-hover-radius",
|
|
1414
|
+
"--dialog-secondary-hover-padding"
|
|
1415
|
+
]);
|
|
1416
|
+
var colorsAndTypeMigration_2026_08_13_dropLegacyShapeSpaceKeys = {
|
|
1417
|
+
id: "2026-08-13-drop-legacy-shape-space-keys",
|
|
1418
|
+
fromVersion: 3,
|
|
1419
|
+
toVersion: 4,
|
|
1420
|
+
appliesTo: "colors-and-type",
|
|
1421
|
+
apply(rawVars) {
|
|
1422
|
+
const out = {};
|
|
1423
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
1424
|
+
if (DROPPED.has(key)) continue;
|
|
1425
|
+
out[key] = value;
|
|
1426
|
+
}
|
|
1427
|
+
return out;
|
|
1428
|
+
}
|
|
1429
|
+
};
|
|
1430
|
+
|
|
1431
|
+
// src/editor/core/themes/migrations/2026-08-15-line-height-scale-rename.ts
|
|
1432
|
+
var RENAMED = {
|
|
1433
|
+
"--line-height-xs": "--line-height-none",
|
|
1434
|
+
"--line-height-sm": "--line-height-tighter",
|
|
1435
|
+
"--line-height-md": "--line-height-normal",
|
|
1436
|
+
"--line-height-lg": "--line-height-relaxed",
|
|
1437
|
+
"--line-height-xl": "--line-height-relaxed"
|
|
1438
|
+
};
|
|
1439
|
+
var REFERENCE = /--line-height-(?:xs|sm|md|lg|xl)(?![\w-])/g;
|
|
1440
|
+
function renameValues(rawVars) {
|
|
1441
|
+
const out = {};
|
|
1442
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
1443
|
+
out[key] = typeof value === "string" ? value.replace(REFERENCE, (name) => RENAMED[name]) : value;
|
|
1444
|
+
}
|
|
1445
|
+
return out;
|
|
1446
|
+
}
|
|
1447
|
+
var colorsAndTypeMigration_2026_08_15_lineHeightScaleRename = {
|
|
1448
|
+
id: "2026-08-15-line-height-scale-rename-colors-and-type",
|
|
1449
|
+
fromVersion: 4,
|
|
1450
|
+
toVersion: 5,
|
|
1451
|
+
appliesTo: "colors-and-type",
|
|
1452
|
+
apply: renameValues
|
|
1453
|
+
};
|
|
1454
|
+
var componentMigration_2026_08_15_lineHeightScaleRename = {
|
|
1455
|
+
id: "2026-08-15-line-height-scale-rename-component",
|
|
1456
|
+
fromVersion: 20,
|
|
1457
|
+
toVersion: 21,
|
|
1458
|
+
appliesTo: "component-config",
|
|
1459
|
+
apply: renameValues
|
|
1460
|
+
};
|
|
1461
|
+
|
|
1462
|
+
// src/editor/core/themes/migrations/index.ts
|
|
1463
|
+
var MIGRATIONS = [
|
|
1464
|
+
colorsAndTypeMigration_2026_04_24_legacyKeysAndBgToCanvas,
|
|
1465
|
+
colorsAndTypeMigration_2026_05_13_primaryToBrand,
|
|
1466
|
+
componentMigration_2026_04_24_prefixAndSuffixRenames,
|
|
1467
|
+
componentMigration_2026_04_27_segmentedcontrolDisabledFlatten,
|
|
1468
|
+
componentMigration_2026_05_08_collapsiblesectionVariantNamespace,
|
|
1469
|
+
componentMigration_2026_05_08_collapsiblesectionFrameAndCleanup,
|
|
1470
|
+
componentMigration_2026_05_10_sectiondividerGradientStops,
|
|
1471
|
+
componentMigration_2026_05_13_primaryToBrand,
|
|
1472
|
+
componentMigration_2026_05_19_collapsiblesectionDropFrameSurface,
|
|
1473
|
+
componentMigration_2026_05_19_sectiondividerRichGradient,
|
|
1474
|
+
componentMigration_2026_05_20_sectiondividerSlimVariants,
|
|
1475
|
+
componentMigration_2026_05_21_sectiondividerSpacingToPadding,
|
|
1476
|
+
componentMigration_2026_05_22_sectiondividerIntrinsicsToCss,
|
|
1477
|
+
componentMigration_2026_05_24_segmentedcontrolDividerInset,
|
|
1478
|
+
componentMigration_2026_05_24_promoteStateSharedTokens,
|
|
1479
|
+
componentMigration_2026_05_24_progressbarCollapseVariants,
|
|
1480
|
+
componentMigration_2026_05_24_collapsiblesectionDropActiveState,
|
|
1481
|
+
componentMigration_2026_05_25_cornerbadgeFlattenVariants,
|
|
1482
|
+
colorsAndTypeMigration_2026_05_26_dropOverlayExtraStops,
|
|
1483
|
+
componentMigration_2026_05_26_dropOverlayExtraStops,
|
|
1484
|
+
componentMigration_2026_05_29_tabbarIndicatorThicknessToPerStateWidth,
|
|
1485
|
+
componentMigration_2026_05_29_segmentedcontrolSmallDividerRename,
|
|
1486
|
+
componentMigration_2026_05_29_toggleDeriveTrackFromThumb,
|
|
1487
|
+
colorsAndTypeMigration_2026_08_13_dropLegacyShapeSpaceKeys,
|
|
1488
|
+
colorsAndTypeMigration_2026_08_15_lineHeightScaleRename,
|
|
1489
|
+
componentMigration_2026_08_15_lineHeightScaleRename
|
|
1490
|
+
];
|
|
1491
|
+
function countFor(kind) {
|
|
1492
|
+
return MIGRATIONS.filter((m) => m.appliesTo === kind).length;
|
|
1493
|
+
}
|
|
1494
|
+
var CURRENT_COLORS_AND_TYPE_SCHEMA_VERSION = countFor("colors-and-type");
|
|
1495
|
+
var CURRENT_COMPONENT_SCHEMA_VERSION = countFor("component-config");
|
|
1496
|
+
function runMigrations(kind, fileVersion, rawVars, meta = {}) {
|
|
1497
|
+
const applicable = MIGRATIONS.filter((m) => m.appliesTo === kind && m.fromVersion >= fileVersion).sort((a, b) => a.toVersion - b.toVersion);
|
|
1498
|
+
let out = { ...rawVars };
|
|
1499
|
+
for (const m of applicable) {
|
|
1500
|
+
out = m.apply(out, meta);
|
|
1501
|
+
}
|
|
1502
|
+
return out;
|
|
1503
|
+
}
|
|
1504
|
+
|
|
620
1505
|
// vite-plugin/files/versionedFileResourceServer.ts
|
|
621
1506
|
var import_fs = __toESM(require("fs"), 1);
|
|
622
1507
|
var import_path = __toESM(require("path"), 1);
|
|
@@ -776,8 +1661,141 @@ async function dispatch(req, res, routes) {
|
|
|
776
1661
|
return false;
|
|
777
1662
|
}
|
|
778
1663
|
|
|
1664
|
+
// src/editor/core/themes/migrateComponentConfig.ts
|
|
1665
|
+
function migrateComponentConfig(component, aliasesIn, rawConfig, fileVersion) {
|
|
1666
|
+
const stringPart = {};
|
|
1667
|
+
const objectPart = {};
|
|
1668
|
+
for (const [k, v] of Object.entries(aliasesIn)) {
|
|
1669
|
+
if (typeof v === "string") stringPart[k] = v;
|
|
1670
|
+
else objectPart[k] = v;
|
|
1671
|
+
}
|
|
1672
|
+
const configOut = {};
|
|
1673
|
+
for (const [k, v] of Object.entries(rawConfig ?? {})) {
|
|
1674
|
+
if (typeof v === "string") stringPart[k] = v;
|
|
1675
|
+
else configOut[k] = v;
|
|
1676
|
+
}
|
|
1677
|
+
if (component === "sectiondivider") {
|
|
1678
|
+
synthesizeSectionDividerGradients(stringPart, objectPart);
|
|
1679
|
+
}
|
|
1680
|
+
const migratedString = runMigrations("component-config", fileVersion, stringPart, { component });
|
|
1681
|
+
const migratedObject = component === "sectiondivider" ? renameSectionDividerObjectSlots(objectPart) : objectPart;
|
|
1682
|
+
return {
|
|
1683
|
+
aliases: { ...migratedString, ...migratedObject },
|
|
1684
|
+
config: configOut
|
|
1685
|
+
};
|
|
1686
|
+
}
|
|
1687
|
+
var FAMILIES = ["canvas", "neutral", "alternate", "primary", "accent", "special"];
|
|
1688
|
+
var SIZE_VARIANTS = ["lg", "md", "sm"];
|
|
1689
|
+
function renameSectionDividerObjectSlots(objectPart) {
|
|
1690
|
+
const canvasSourceKeys = [
|
|
1691
|
+
"--sectiondivider-canvas-background",
|
|
1692
|
+
"--sectiondivider-canvas-gradient",
|
|
1693
|
+
"--sectiondivider-color-canvas-background"
|
|
1694
|
+
];
|
|
1695
|
+
let canvasGradient;
|
|
1696
|
+
for (const key of canvasSourceKeys) {
|
|
1697
|
+
if (objectPart[key] !== void 0) {
|
|
1698
|
+
canvasGradient = objectPart[key];
|
|
1699
|
+
break;
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
const out = {};
|
|
1703
|
+
for (const [key, value] of Object.entries(objectPart)) {
|
|
1704
|
+
let isFamilyGradient = false;
|
|
1705
|
+
for (const f of FAMILIES) {
|
|
1706
|
+
if (key === `--sectiondivider-${f}-background` || key === `--sectiondivider-${f}-gradient` || key === `--sectiondivider-color-${f}-background`) {
|
|
1707
|
+
isFamilyGradient = true;
|
|
1708
|
+
break;
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
if (isFamilyGradient) continue;
|
|
1712
|
+
out[key] = value;
|
|
1713
|
+
}
|
|
1714
|
+
if (canvasGradient !== void 0) {
|
|
1715
|
+
for (const v of SIZE_VARIANTS) {
|
|
1716
|
+
out[`--sectiondivider-${v}-background`] = canvasGradient;
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
return out;
|
|
1720
|
+
}
|
|
1721
|
+
var SECTIONDIVIDER_VARIANTS = ["canvas", "neutral", "alternate", "primary", "accent", "special"];
|
|
1722
|
+
function synthesizeSectionDividerGradients(stringPart, objectPart) {
|
|
1723
|
+
const GRADIENT_ANGLE_TOKENS = {
|
|
1724
|
+
"--gradient-angle-horizontal": 90,
|
|
1725
|
+
"--gradient-angle-vertical": 180,
|
|
1726
|
+
"--gradient-angle-diagonal": 135,
|
|
1727
|
+
"--gradient-angle-counter-diagonal": 45
|
|
1728
|
+
};
|
|
1729
|
+
const GRADIENT_STOP_POSITIONS = {
|
|
1730
|
+
"--gradient-stop-start": 0,
|
|
1731
|
+
"--gradient-stop-mid": 50,
|
|
1732
|
+
"--gradient-stop-end": 100
|
|
1733
|
+
};
|
|
1734
|
+
const parseAngle = (raw) => {
|
|
1735
|
+
if (!raw) return 135;
|
|
1736
|
+
if (raw.startsWith("--")) return GRADIENT_ANGLE_TOKENS[raw] ?? 135;
|
|
1737
|
+
const m = raw.match(/^(-?\d+(?:\.\d+)?)\s*deg$/i);
|
|
1738
|
+
return m ? parseFloat(m[1]) : 135;
|
|
1739
|
+
};
|
|
1740
|
+
const parsePosition = (raw, fallback) => {
|
|
1741
|
+
if (!raw) return fallback;
|
|
1742
|
+
if (raw.startsWith("--")) return GRADIENT_STOP_POSITIONS[raw] ?? fallback;
|
|
1743
|
+
const m = raw.match(/^(-?\d+(?:\.\d+)?)\s*%$/);
|
|
1744
|
+
return m ? parseFloat(m[1]) : fallback;
|
|
1745
|
+
};
|
|
1746
|
+
const parseStopColor = (raw) => {
|
|
1747
|
+
if (!raw) return null;
|
|
1748
|
+
if (raw.startsWith("--")) return { color: raw };
|
|
1749
|
+
const mix = raw.match(/^color-mix\(\s*in\s+srgb\s*,\s*var\((--[a-z0-9-]+)\)\s+([\d.]+)%\s*,\s*transparent\s*\)$/i);
|
|
1750
|
+
if (mix) return { color: mix[1], opacity: parseFloat(mix[2]) };
|
|
1751
|
+
return null;
|
|
1752
|
+
};
|
|
1753
|
+
for (const v of SECTIONDIVIDER_VARIANTS) {
|
|
1754
|
+
const slot = `--sectiondivider-${v}-gradient`;
|
|
1755
|
+
if (slot in objectPart) continue;
|
|
1756
|
+
const angleKey = `${slot}-angle`;
|
|
1757
|
+
const has1 = stringPart[`${slot}-stop-1-color`] !== void 0;
|
|
1758
|
+
const has2 = stringPart[`${slot}-stop-2-color`] !== void 0;
|
|
1759
|
+
const has3 = stringPart[`${slot}-stop-3-color`] !== void 0;
|
|
1760
|
+
if (!has1 && !has2 && !has3) continue;
|
|
1761
|
+
const stops = [];
|
|
1762
|
+
const positionDefaults = [0, 50, 100];
|
|
1763
|
+
for (let i = 1; i <= 3; i++) {
|
|
1764
|
+
const c = parseStopColor(stringPart[`${slot}-stop-${i}-color`]);
|
|
1765
|
+
if (!c) continue;
|
|
1766
|
+
const pos = parsePosition(stringPart[`${slot}-stop-${i}-position`], positionDefaults[i - 1]);
|
|
1767
|
+
stops.push({ position: pos, color: c.color, ...c.opacity !== void 0 ? { opacity: c.opacity } : {} });
|
|
1768
|
+
}
|
|
1769
|
+
if (stops.length < 2) continue;
|
|
1770
|
+
objectPart[slot] = {
|
|
1771
|
+
kind: "gradient",
|
|
1772
|
+
value: {
|
|
1773
|
+
type: "linear",
|
|
1774
|
+
angle: parseAngle(stringPart[angleKey]),
|
|
1775
|
+
stops
|
|
1776
|
+
}
|
|
1777
|
+
};
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
// src/editor/core/themes/themeTypes.ts
|
|
1782
|
+
var THEME_SCHEMA_VERSION = 4;
|
|
1783
|
+
|
|
1784
|
+
// src/editor/core/components/componentConfigKeys.ts
|
|
1785
|
+
var KNOWN_COMPONENT_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
1786
|
+
"--dialog-confirm-variant",
|
|
1787
|
+
"--dialog-cancel-variant",
|
|
1788
|
+
// SectionDivider per-variant `color-family` is editor metadata that drives
|
|
1789
|
+
// the family-swap rewrite on aliases. It is not a runtime CSS value, so it
|
|
1790
|
+
// stays in the config bucket. The other intrinsics (align, hairline,
|
|
1791
|
+
// eyebrow/description visibility, eyebrow text-transform) now flow through
|
|
1792
|
+
// the alias bucket as cascading CSS vars — see the 2026-05-22 migration.
|
|
1793
|
+
"--sectiondivider-lg-color-family",
|
|
1794
|
+
"--sectiondivider-md-color-family",
|
|
1795
|
+
"--sectiondivider-sm-color-family"
|
|
1796
|
+
]);
|
|
1797
|
+
|
|
779
1798
|
// vite-plugin/themes/normalizeTheme.ts
|
|
780
|
-
var THEME_SCHEMA_VERSION = 3;
|
|
781
1799
|
function asObject(value) {
|
|
782
1800
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
783
1801
|
}
|
|
@@ -799,10 +1817,41 @@ function migrateEmbeddedKey(src) {
|
|
|
799
1817
|
const { theme, ...rest } = src;
|
|
800
1818
|
return { ...rest, colorsAndType: theme };
|
|
801
1819
|
}
|
|
1820
|
+
function routeKnownConfigKeys(aliases, config) {
|
|
1821
|
+
const outAliases = { ...aliases };
|
|
1822
|
+
const outConfig = { ...config };
|
|
1823
|
+
for (const key of Object.keys(outAliases)) {
|
|
1824
|
+
if (!KNOWN_COMPONENT_CONFIG_KEYS.has(key)) continue;
|
|
1825
|
+
if (outConfig[key] === void 0) outConfig[key] = outAliases[key];
|
|
1826
|
+
delete outAliases[key];
|
|
1827
|
+
}
|
|
1828
|
+
return { aliases: outAliases, config: outConfig };
|
|
1829
|
+
}
|
|
1830
|
+
function migrateEmbeddedComponentConfig(comp, config, fileVersion) {
|
|
1831
|
+
const { schemaVersion: _entryStamp, aliases: rawAliases, config: rawConfig, ...rest } = config;
|
|
1832
|
+
const aliasesIn = asObject(rawAliases);
|
|
1833
|
+
if (!aliasesIn) {
|
|
1834
|
+
return rawConfig !== void 0 ? { ...rest, config: rawConfig } : rest;
|
|
1835
|
+
}
|
|
1836
|
+
const migratedConfig = migrateComponentConfig(
|
|
1837
|
+
comp,
|
|
1838
|
+
aliasesIn,
|
|
1839
|
+
asObject(rawConfig) ?? void 0,
|
|
1840
|
+
fileVersion
|
|
1841
|
+
);
|
|
1842
|
+
const split = routeKnownConfigKeys(migratedConfig.aliases, migratedConfig.config);
|
|
1843
|
+
const out = { ...rest, aliases: split.aliases };
|
|
1844
|
+
if (rawConfig !== void 0 || Object.keys(split.config).length > 0) {
|
|
1845
|
+
out.config = split.config;
|
|
1846
|
+
}
|
|
1847
|
+
return out;
|
|
1848
|
+
}
|
|
802
1849
|
function normalizeTheme(raw, resolvers) {
|
|
803
1850
|
const input = asObject(raw) ?? {};
|
|
804
1851
|
const migrated = input.schemaVersion !== THEME_SCHEMA_VERSION;
|
|
805
|
-
const
|
|
1852
|
+
const inputVersion = typeof input.schemaVersion === "number" ? input.schemaVersion : 0;
|
|
1853
|
+
const src = inputVersion < 3 ? migrateEmbeddedKey(input) : input;
|
|
1854
|
+
const componentSchemaVersion = typeof input.componentSchemaVersion === "number" ? input.componentSchemaVersion : 0;
|
|
806
1855
|
const dropped = [];
|
|
807
1856
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
808
1857
|
const embeddedColorsAndType = asObject(src.colorsAndType);
|
|
@@ -821,18 +1870,42 @@ function normalizeTheme(raw, resolvers) {
|
|
|
821
1870
|
const componentConfigs = {};
|
|
822
1871
|
for (const [comp, value] of Object.entries(asObject(src.componentConfigs) ?? {})) {
|
|
823
1872
|
const embedded = asObject(value);
|
|
1873
|
+
let resolvedConfig;
|
|
824
1874
|
if (embedded) {
|
|
825
|
-
|
|
1875
|
+
resolvedConfig = stripFileMarker(embedded);
|
|
1876
|
+
} else {
|
|
1877
|
+
const configName = asString(value, "default");
|
|
1878
|
+
const resolved = asObject(resolvers.readComponentConfig(comp, configName));
|
|
1879
|
+
if (!resolved) {
|
|
1880
|
+
dropped.push(`${comp}/${configName}`);
|
|
1881
|
+
continue;
|
|
1882
|
+
}
|
|
1883
|
+
resolvedConfig = stripFileMarker(resolved);
|
|
1884
|
+
}
|
|
1885
|
+
componentConfigs[comp] = migrateEmbeddedComponentConfig(comp, resolvedConfig, componentSchemaVersion);
|
|
1886
|
+
}
|
|
1887
|
+
const filled = { components: [], aliases: 0, orphans: 0 };
|
|
1888
|
+
for (const comp of resolvers.listComponentNames()) {
|
|
1889
|
+
const base = asObject(resolvers.readComponentConfig(comp, "default"));
|
|
1890
|
+
const baseAliases = base ? asObject(base.aliases) : null;
|
|
1891
|
+
if (!base || !baseAliases) continue;
|
|
1892
|
+
const entry = componentConfigs[comp];
|
|
1893
|
+
if (!entry) {
|
|
1894
|
+
const { schemaVersion: _standaloneStamp, ...rest } = stripFileMarker(base);
|
|
1895
|
+
componentConfigs[comp] = structuredClone(rest);
|
|
1896
|
+
filled.components.push(comp);
|
|
826
1897
|
continue;
|
|
827
1898
|
}
|
|
828
|
-
const
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
1899
|
+
const entryAliases = asObject(entry.aliases) ?? {};
|
|
1900
|
+
for (const key of Object.keys(baseAliases)) {
|
|
1901
|
+
if (key in entryAliases) continue;
|
|
1902
|
+
entryAliases[key] = structuredClone(baseAliases[key]);
|
|
1903
|
+
filled.aliases++;
|
|
1904
|
+
}
|
|
1905
|
+
entry.aliases = entryAliases;
|
|
1906
|
+
for (const key of Object.keys(entryAliases)) {
|
|
1907
|
+
if (!(key in baseAliases)) filled.orphans++;
|
|
834
1908
|
}
|
|
835
|
-
componentConfigs[comp] = stripFileMarker(resolved);
|
|
836
1909
|
}
|
|
837
1910
|
return {
|
|
838
1911
|
theme: {
|
|
@@ -841,10 +1914,12 @@ function normalizeTheme(raw, resolvers) {
|
|
|
841
1914
|
updatedAt: asString(src.updatedAt, now),
|
|
842
1915
|
schemaVersion: THEME_SCHEMA_VERSION,
|
|
843
1916
|
colorsAndType,
|
|
844
|
-
componentConfigs
|
|
1917
|
+
componentConfigs,
|
|
1918
|
+
componentSchemaVersion: CURRENT_COMPONENT_SCHEMA_VERSION
|
|
845
1919
|
},
|
|
846
1920
|
dropped,
|
|
847
|
-
migrated
|
|
1921
|
+
migrated,
|
|
1922
|
+
filled
|
|
848
1923
|
};
|
|
849
1924
|
}
|
|
850
1925
|
|
|
@@ -987,7 +2062,7 @@ function ensureScale(css, opts) {
|
|
|
987
2062
|
lines.splice(insertAfter + 1, 0, ...block);
|
|
988
2063
|
return lines.join("\n");
|
|
989
2064
|
}
|
|
990
|
-
function
|
|
2065
|
+
function renameToken2(css, oldName, newName) {
|
|
991
2066
|
const defined = collectDefinedTokens(css);
|
|
992
2067
|
if (!defined.has(oldName) || defined.has(newName)) return css;
|
|
993
2068
|
const re = new RegExp(escapeRe(oldName) + "(?![a-z0-9-])", "gi");
|
|
@@ -1206,7 +2281,7 @@ var tokensCssMigration_2026_06_04_easingColorAndTypescaleAdditions = {
|
|
|
1206
2281
|
};
|
|
1207
2282
|
|
|
1208
2283
|
// vite-plugin/tokensCssMigrations/migrations/2026-07-20-line-height-rename.ts
|
|
1209
|
-
var
|
|
2284
|
+
var RENAMES2 = [
|
|
1210
2285
|
["--line-height-xs", "--line-height-none"],
|
|
1211
2286
|
["--line-height-sm", "--line-height-tighter"],
|
|
1212
2287
|
["--line-height-md", "--line-height-normal"],
|
|
@@ -1226,7 +2301,7 @@ var tokensCssMigration_2026_07_20_lineHeightRename = {
|
|
|
1226
2301
|
description: "Reshape --line-height-{xs..xl} to leading vocabulary (none/tightest/tighter/tight/normal/relaxed); retire the 2.0 slot",
|
|
1227
2302
|
apply(css) {
|
|
1228
2303
|
let out = css;
|
|
1229
|
-
for (const [oldName, newName] of
|
|
2304
|
+
for (const [oldName, newName] of RENAMES2) out = renameToken2(out, oldName, newName);
|
|
1230
2305
|
out = removeToken(out, "--line-height-xl");
|
|
1231
2306
|
out = ensureScale(out, {
|
|
1232
2307
|
anchorPrefixes: ["--line-height-", "--font-size-", "--font-weight-", "--font-"],
|
|
@@ -1303,6 +2378,20 @@ var tokensCssMigration_2026_07_20_semanticTextStyles = {
|
|
|
1303
2378
|
}
|
|
1304
2379
|
};
|
|
1305
2380
|
|
|
2381
|
+
// vite-plugin/tokensCssMigrations/migrations/2026-08-19-oklch-color-values.ts
|
|
2382
|
+
var HEX_DECLARATION_RE = /(--[a-z0-9-]+:\s*)#([0-9a-f]{6})(?=\s*[;}])/gi;
|
|
2383
|
+
var tokensCssMigration_2026_08_19_oklchColorValues = {
|
|
2384
|
+
id: "2026-08-19-oklch-color-values",
|
|
2385
|
+
kind: "breaking",
|
|
2386
|
+
description: "Rewrite hex token values as oklch()",
|
|
2387
|
+
apply(css) {
|
|
2388
|
+
return css.replace(HEX_DECLARATION_RE, (_match, prefix, hex) => {
|
|
2389
|
+
const { l, c, h } = hexToOklch(`#${hex}`);
|
|
2390
|
+
return `${prefix}${oklchToCss(l, c, h)}`;
|
|
2391
|
+
});
|
|
2392
|
+
}
|
|
2393
|
+
};
|
|
2394
|
+
|
|
1306
2395
|
// vite-plugin/tokensCssMigrations/index.ts
|
|
1307
2396
|
var TOKENS_CSS_MIGRATIONS = [
|
|
1308
2397
|
tokensCssMigration_2026_05_29_typographyScaleAdditions,
|
|
@@ -1311,7 +2400,8 @@ var TOKENS_CSS_MIGRATIONS = [
|
|
|
1311
2400
|
tokensCssMigration_2026_06_04_removeDeadSizeIconScale,
|
|
1312
2401
|
tokensCssMigration_2026_06_04_easingColorAndTypescaleAdditions,
|
|
1313
2402
|
tokensCssMigration_2026_07_20_lineHeightRename,
|
|
1314
|
-
tokensCssMigration_2026_07_20_semanticTextStyles
|
|
2403
|
+
tokensCssMigration_2026_07_20_semanticTextStyles,
|
|
2404
|
+
tokensCssMigration_2026_08_19_oklchColorValues
|
|
1315
2405
|
];
|
|
1316
2406
|
function runTokensCssMigrations(css) {
|
|
1317
2407
|
return foldMigrations(css, () => true);
|
|
@@ -1379,8 +2469,29 @@ var PKG_VERSION = (() => {
|
|
|
1379
2469
|
})();
|
|
1380
2470
|
var BUNDLE_KIND_BY_VERSION = {
|
|
1381
2471
|
1: "manifest-bundle",
|
|
2472
|
+
3: "theme-bundle",
|
|
1382
2473
|
[THEME_SCHEMA_VERSION]: "theme-bundle"
|
|
1383
2474
|
};
|
|
2475
|
+
function extractAliasDeclarations(body) {
|
|
2476
|
+
const aliases = {};
|
|
2477
|
+
const re = /(--[a-z0-9-]+)\s*:\s*([^;]+);/gi;
|
|
2478
|
+
let m;
|
|
2479
|
+
while ((m = re.exec(body)) !== null) {
|
|
2480
|
+
const value = m[2].trim();
|
|
2481
|
+
const plain = value.match(/^var\((--[a-z0-9-]+)\)$/i);
|
|
2482
|
+
if (plain) {
|
|
2483
|
+
aliases[m[1]] = plain[1];
|
|
2484
|
+
continue;
|
|
2485
|
+
}
|
|
2486
|
+
if (parseColorOpacity(value)) {
|
|
2487
|
+
aliases[m[1]] = value;
|
|
2488
|
+
continue;
|
|
2489
|
+
}
|
|
2490
|
+
const gradient = parseGradientValue(value);
|
|
2491
|
+
if (gradient) aliases[m[1]] = { kind: "gradient", value: gradient };
|
|
2492
|
+
}
|
|
2493
|
+
return aliases;
|
|
2494
|
+
}
|
|
1384
2495
|
function themeFileApi(opts) {
|
|
1385
2496
|
const dataDirs = resolveDataDirs({
|
|
1386
2497
|
dataDir: opts.dataDir,
|
|
@@ -1557,6 +2668,7 @@ function themeFileApi(opts) {
|
|
|
1557
2668
|
const overrides = [];
|
|
1558
2669
|
const defaultAliases = defaultCfg.aliases ?? {};
|
|
1559
2670
|
for (const [varName, semanticValue] of Object.entries(prodCfg.aliases ?? {})) {
|
|
2671
|
+
if (!(varName in defaultAliases)) continue;
|
|
1560
2672
|
if (!aliasValuesEqual(defaultAliases[varName], semanticValue)) {
|
|
1561
2673
|
overrides.push([varName, semanticValue]);
|
|
1562
2674
|
}
|
|
@@ -1619,18 +2731,6 @@ function themeFileApi(opts) {
|
|
|
1619
2731
|
import_fs4.default.writeFileSync(FONTS_CSS_PATH, content);
|
|
1620
2732
|
console.log(`[syncFontsToCss] Wrote ${sources.length} source(s) into ${import_path4.default.basename(FONTS_CSS_PATH)}`);
|
|
1621
2733
|
}
|
|
1622
|
-
function extractAliasDeclarations(body) {
|
|
1623
|
-
const aliases = {};
|
|
1624
|
-
const re = /(--[a-z0-9-]+)\s*:\s*([^;]+);/gi;
|
|
1625
|
-
let m;
|
|
1626
|
-
while ((m = re.exec(body)) !== null) {
|
|
1627
|
-
const value = m[2].trim();
|
|
1628
|
-
const plain = value.match(/^var\((--[a-z0-9-]+)\)$/i);
|
|
1629
|
-
if (plain) aliases[m[1]] = plain[1];
|
|
1630
|
-
else if (parseColorOpacity(value)) aliases[m[1]] = value;
|
|
1631
|
-
}
|
|
1632
|
-
return aliases;
|
|
1633
|
-
}
|
|
1634
2734
|
function componentNameFromFile(filePath) {
|
|
1635
2735
|
return import_path4.default.basename(filePath, ".svelte").toLowerCase();
|
|
1636
2736
|
}
|
|
@@ -1706,17 +2806,10 @@ ${lines.join("\n")}
|
|
|
1706
2806
|
r.ensureDir();
|
|
1707
2807
|
const defaultPath = r.filePath("default");
|
|
1708
2808
|
const sourceStat = import_fs4.default.statSync(sourcePath);
|
|
1709
|
-
|
|
1710
|
-
const defaultStat = import_fs4.default.statSync(defaultPath);
|
|
1711
|
-
if (defaultStat.mtimeMs >= sourceStat.mtimeMs) return;
|
|
1712
|
-
}
|
|
1713
|
-
const source = import_fs4.default.readFileSync(sourcePath, "utf-8");
|
|
1714
|
-
const body = extractGlobalRootBody(source);
|
|
1715
|
-
const aliases = extractAliasDeclarations(body);
|
|
1716
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1717
|
-
let createdAt = now;
|
|
2809
|
+
let createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1718
2810
|
let existingUpdatedAt;
|
|
1719
2811
|
let existingAliases;
|
|
2812
|
+
let existingSchemaVersion;
|
|
1720
2813
|
if (import_fs4.default.existsSync(defaultPath)) {
|
|
1721
2814
|
try {
|
|
1722
2815
|
const existing = JSON.parse(import_fs4.default.readFileSync(defaultPath, "utf-8"));
|
|
@@ -1725,25 +2818,29 @@ ${lines.join("\n")}
|
|
|
1725
2818
|
if (existing.aliases && typeof existing.aliases === "object") {
|
|
1726
2819
|
existingAliases = existing.aliases;
|
|
1727
2820
|
}
|
|
2821
|
+
if (typeof existing.schemaVersion === "number") existingSchemaVersion = existing.schemaVersion;
|
|
1728
2822
|
} catch {
|
|
1729
2823
|
}
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
if (val !== null && typeof val === "object" && !(token in aliases)) {
|
|
1734
|
-
aliases[token] = val;
|
|
1735
|
-
}
|
|
2824
|
+
const defaultStat = import_fs4.default.statSync(defaultPath);
|
|
2825
|
+
if (defaultStat.mtimeMs >= sourceStat.mtimeMs && existingSchemaVersion === CURRENT_COMPONENT_SCHEMA_VERSION) {
|
|
2826
|
+
return;
|
|
1736
2827
|
}
|
|
1737
2828
|
}
|
|
2829
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2830
|
+
const source = import_fs4.default.readFileSync(sourcePath, "utf-8");
|
|
2831
|
+
const body = extractGlobalRootBody(source);
|
|
2832
|
+
const aliases = extractAliasDeclarations(body);
|
|
1738
2833
|
const aliasesUnchanged = existingAliases !== void 0 && JSON.stringify(existingAliases) === JSON.stringify(aliases);
|
|
2834
|
+
const schemaStampCurrent = existingSchemaVersion === CURRENT_COMPONENT_SCHEMA_VERSION;
|
|
1739
2835
|
const defaultConfig = {
|
|
1740
2836
|
name: "default",
|
|
1741
2837
|
component: comp,
|
|
1742
2838
|
createdAt,
|
|
1743
2839
|
updatedAt: aliasesUnchanged && existingUpdatedAt ? existingUpdatedAt : now,
|
|
1744
|
-
aliases
|
|
2840
|
+
aliases,
|
|
2841
|
+
schemaVersion: CURRENT_COMPONENT_SCHEMA_VERSION
|
|
1745
2842
|
};
|
|
1746
|
-
if (aliasesUnchanged && existingUpdatedAt) {
|
|
2843
|
+
if (aliasesUnchanged && schemaStampCurrent && existingUpdatedAt) {
|
|
1747
2844
|
const t = /* @__PURE__ */ new Date();
|
|
1748
2845
|
import_fs4.default.utimesSync(defaultPath, t, t);
|
|
1749
2846
|
return;
|
|
@@ -1791,6 +2888,7 @@ ${lines.join("\n")}
|
|
|
1791
2888
|
const diskThemeResolvers = {
|
|
1792
2889
|
readColorsAndType: (name) => colorsAndTypeResource.readJson(sanitizeFileName(name)),
|
|
1793
2890
|
readComponentConfig: (comp, name) => readComponentConfig(comp, sanitizeFileName(name)),
|
|
2891
|
+
listComponentNames,
|
|
1794
2892
|
normalizeColorsAndType: (colorsAndType) => normalizeColorsAndType(colorsAndType)
|
|
1795
2893
|
};
|
|
1796
2894
|
function readTheme(fileName) {
|
|
@@ -1816,7 +2914,7 @@ ${lines.join("\n")}
|
|
|
1816
2914
|
return "corrupt";
|
|
1817
2915
|
}
|
|
1818
2916
|
function notAThemeError(fileName) {
|
|
1819
|
-
return `"${fileName}" is a colors-and-type file, not a theme. Before 0.48 those lived in themes/; move it to ${import_path4.default.basename(COLORS_AND_TYPE_DIR)}/ or delete it.`;
|
|
2917
|
+
return `"${fileName}" is a colors-and-type file, not a theme. Before 0.48 those lived in themes/; move it to ${import_path4.default.basename(COLORS_AND_TYPE_DIR)}/ or delete it. To build a theme, use the theme generator skill "generate-theme".`;
|
|
1820
2918
|
}
|
|
1821
2919
|
function respondUnreadableTheme(res, fileName, missingError) {
|
|
1822
2920
|
switch (unreadableThemeReason(fileName)) {
|
|
@@ -1878,19 +2976,26 @@ ${lines.join("\n")}
|
|
|
1878
2976
|
const componentConfigs = {};
|
|
1879
2977
|
for (const comp of listComponentNames()) {
|
|
1880
2978
|
const cfg = readComponentConfig(comp, "default");
|
|
1881
|
-
if (cfg)
|
|
2979
|
+
if (cfg) {
|
|
2980
|
+
const { schemaVersion: _standaloneStamp, ...rest } = cfg;
|
|
2981
|
+
componentConfigs[comp] = rest;
|
|
2982
|
+
}
|
|
1882
2983
|
}
|
|
1883
|
-
|
|
2984
|
+
const contentUnchanged = JSON.stringify(existing?.colorsAndType) === JSON.stringify(colorsAndType) && JSON.stringify(existing?.componentConfigs) === JSON.stringify(componentConfigs);
|
|
2985
|
+
if (existing?.schemaVersion === THEME_SCHEMA_VERSION && existing?.componentSchemaVersion === CURRENT_COMPONENT_SCHEMA_VERSION && contentUnchanged) {
|
|
1884
2986
|
return;
|
|
1885
2987
|
}
|
|
1886
2988
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1887
2989
|
writeTheme("default", {
|
|
1888
2990
|
name: "Motion Proto",
|
|
1889
2991
|
createdAt: typeof existing?.createdAt === "string" ? existing.createdAt : now,
|
|
1890
|
-
|
|
2992
|
+
// A stamp-only rewrite (componentSchemaVersion catching up) is not a
|
|
2993
|
+
// content change, so it doesn't bump this the way a real edit would.
|
|
2994
|
+
updatedAt: contentUnchanged && typeof existing?.updatedAt === "string" ? existing.updatedAt : now,
|
|
1891
2995
|
schemaVersion: THEME_SCHEMA_VERSION,
|
|
1892
2996
|
colorsAndType,
|
|
1893
|
-
componentConfigs
|
|
2997
|
+
componentConfigs,
|
|
2998
|
+
componentSchemaVersion: CURRENT_COMPONENT_SCHEMA_VERSION
|
|
1894
2999
|
});
|
|
1895
3000
|
}
|
|
1896
3001
|
function ensureThemesDir(warn) {
|
|
@@ -1922,14 +3027,24 @@ ${lines.join("\n")}
|
|
|
1922
3027
|
if (!shipped) return null;
|
|
1923
3028
|
return { data: normalizeColorsAndType(shipped), source: "default" };
|
|
1924
3029
|
}
|
|
3030
|
+
const loggedMissingThemeEntries = /* @__PURE__ */ new Set();
|
|
3031
|
+
function resolveComponentConfigOrDefault(comp, theme) {
|
|
3032
|
+
const embedded = theme?.componentConfigs[comp];
|
|
3033
|
+
if (embedded) return { ...embedded, component: comp };
|
|
3034
|
+
if (!loggedMissingThemeEntries.has(comp)) {
|
|
3035
|
+
loggedMissingThemeEntries.add(comp);
|
|
3036
|
+
console.warn(
|
|
3037
|
+
`[live-tokens] "${comp}" has no entry in the open theme; resolving from its shipped default.`
|
|
3038
|
+
);
|
|
3039
|
+
}
|
|
3040
|
+
return readComponentConfig(comp, "default");
|
|
3041
|
+
}
|
|
1925
3042
|
function resolveLiveComponentConfig(comp, theme) {
|
|
1926
3043
|
const working = componentResource(comp).readWorking();
|
|
1927
3044
|
if (working !== null) return { data: working, source: "working" };
|
|
1928
|
-
const
|
|
1929
|
-
if (embedded) return { data: { ...embedded, component: comp }, source: "theme" };
|
|
1930
|
-
const cfg = readComponentConfig(comp, "default");
|
|
3045
|
+
const cfg = resolveComponentConfigOrDefault(comp, theme);
|
|
1931
3046
|
if (!cfg) return null;
|
|
1932
|
-
return { data: cfg, source: "
|
|
3047
|
+
return { data: cfg, source: "theme" };
|
|
1933
3048
|
}
|
|
1934
3049
|
function resolveSavedColorsAndType(theme) {
|
|
1935
3050
|
if (theme?.colorsAndType) return theme.colorsAndType;
|
|
@@ -1937,9 +3052,7 @@ ${lines.join("\n")}
|
|
|
1937
3052
|
return shipped ? normalizeColorsAndType(shipped) : null;
|
|
1938
3053
|
}
|
|
1939
3054
|
function resolveSavedComponentConfig(comp, theme) {
|
|
1940
|
-
|
|
1941
|
-
if (embedded) return { ...embedded, component: comp };
|
|
1942
|
-
return readComponentConfig(comp, "default");
|
|
3055
|
+
return resolveComponentConfigOrDefault(comp, theme);
|
|
1943
3056
|
}
|
|
1944
3057
|
function sameJsonValue(a, b) {
|
|
1945
3058
|
if (a === null || b === null) return a === b;
|
|
@@ -1975,26 +3088,9 @@ ${lines.join("\n")}
|
|
|
1975
3088
|
if (entry.isDirectory()) componentResource(entry.name).clearWorking();
|
|
1976
3089
|
}
|
|
1977
3090
|
}
|
|
1978
|
-
function formatAliasGradient(v) {
|
|
1979
|
-
const stopColor = (s) => {
|
|
1980
|
-
const base = s.color.startsWith("--") ? `var(${s.color})` : s.color;
|
|
1981
|
-
const opacity = s.opacity ?? 100;
|
|
1982
|
-
return opacity >= 100 ? base : `color-mix(in srgb, ${base} ${opacity}%, transparent)`;
|
|
1983
|
-
};
|
|
1984
|
-
if (v.type === "none") return "transparent";
|
|
1985
|
-
if (v.type === "solid") {
|
|
1986
|
-
const first = v.stops[0];
|
|
1987
|
-
if (!first) return "transparent";
|
|
1988
|
-
return stopColor(first);
|
|
1989
|
-
}
|
|
1990
|
-
const stops = v.stops.map((s) => `${stopColor(s)} ${s.position}%`).join(", ");
|
|
1991
|
-
if (v.type === "linear") return `linear-gradient(${v.angle}deg, ${stops})`;
|
|
1992
|
-
const radial = v.radius && v.radius > 0 ? `circle ${v.radius}px at center` : "circle";
|
|
1993
|
-
return `radial-gradient(${radial}, ${stops})`;
|
|
1994
|
-
}
|
|
1995
3091
|
function aliasValueToCss(v) {
|
|
1996
3092
|
if (typeof v === "string") return v.startsWith("--") ? `var(${v})` : v;
|
|
1997
|
-
return
|
|
3093
|
+
return formatGradientValue(v.value);
|
|
1998
3094
|
}
|
|
1999
3095
|
function aliasValuesEqual(a, b) {
|
|
2000
3096
|
if (a === void 0 || b === void 0) return a === b;
|
|
@@ -2144,13 +3240,9 @@ ${lines.join("\n")}
|
|
|
2144
3240
|
}
|
|
2145
3241
|
}
|
|
2146
3242
|
async function handleListComponents({ res }) {
|
|
2147
|
-
const theme = activeTheme();
|
|
2148
3243
|
const components = listComponentNames().map((comp) => ({
|
|
2149
3244
|
name: comp,
|
|
2150
|
-
|
|
2151
|
-
// down, and the door only has to say where each component's live config
|
|
2152
|
-
// comes from.
|
|
2153
|
-
source: componentResource(comp).hasWorking() ? "working" : theme?.componentConfigs[comp] ? "theme" : "default"
|
|
3245
|
+
source: componentResource(comp).hasWorking() ? "working" : "theme"
|
|
2154
3246
|
}));
|
|
2155
3247
|
jsonResponse(res, 200, { components });
|
|
2156
3248
|
}
|
|
@@ -2161,6 +3253,7 @@ ${lines.join("\n")}
|
|
|
2161
3253
|
}
|
|
2162
3254
|
async function handleGetComponentActive({ params, res }) {
|
|
2163
3255
|
const [comp] = params;
|
|
3256
|
+
if (rejectUnknownComponent(res, comp)) return;
|
|
2164
3257
|
const resolved = resolveLiveComponentConfig(comp, activeTheme());
|
|
2165
3258
|
if (!resolved) {
|
|
2166
3259
|
jsonResponse(res, 404, { error: "Active config not found" });
|
|
@@ -2407,9 +3500,11 @@ ${lines.join("\n")}
|
|
|
2407
3500
|
respondUnreadableTheme(res, fileName, "Theme not found");
|
|
2408
3501
|
return;
|
|
2409
3502
|
}
|
|
2410
|
-
const { theme } = read;
|
|
3503
|
+
const { theme, filled } = read;
|
|
2411
3504
|
if (!theme.colorsAndType) {
|
|
2412
|
-
jsonResponse(res, 422, {
|
|
3505
|
+
jsonResponse(res, 422, {
|
|
3506
|
+
error: 'This theme carries no colors and type. Build one with the theme generator skill "generate-theme".'
|
|
3507
|
+
});
|
|
2413
3508
|
return;
|
|
2414
3509
|
}
|
|
2415
3510
|
clearAllWorking();
|
|
@@ -2433,7 +3528,8 @@ ${lines.join("\n")}
|
|
|
2433
3528
|
_source: resolvedColorsAndType.source
|
|
2434
3529
|
},
|
|
2435
3530
|
componentConfigs: resolvedConfigs,
|
|
2436
|
-
skippedComponents
|
|
3531
|
+
skippedComponents,
|
|
3532
|
+
filled
|
|
2437
3533
|
});
|
|
2438
3534
|
}
|
|
2439
3535
|
async function handleExportTheme({ params, res }) {
|
|
@@ -2488,10 +3584,27 @@ ${lines.join("\n")}
|
|
|
2488
3584
|
}
|
|
2489
3585
|
const bundleResolvers = {
|
|
2490
3586
|
readColorsAndType: () => bundle.theme,
|
|
2491
|
-
|
|
3587
|
+
// A named ref resolves inside the bundle only — a v1 bundle's
|
|
3588
|
+
// `${comp}/${name}` map is itself the sender's data, and a stale name
|
|
3589
|
+
// must still land in `dropped` rather than quietly picking up this
|
|
3590
|
+
// install's copy. But `'default'` never named a bundled entry; v1
|
|
3591
|
+
// spelled "no override" that way (normalizeTheme.ts's pointer-
|
|
3592
|
+
// resolution loop treats it identically), so it always meant *this
|
|
3593
|
+
// install's* default, not something the bundle carries. The
|
|
3594
|
+
// completeness fill (Wave 2 of docs/plans/theme-completeness.md) relies
|
|
3595
|
+
// on that fall-through: without it, `readComponentConfig(comp,
|
|
3596
|
+
// 'default')` answers undefined for every component (no bundle ever
|
|
3597
|
+
// carries a `<comp>/default` entry), the fill loop no-ops 25 times, and
|
|
3598
|
+
// an incomplete bundle stays incomplete forever — exactly the drift RJC
|
|
3599
|
+
// 10 exists to prevent.
|
|
3600
|
+
readComponentConfig: (comp, name) => bundle.componentConfigs?.[`${comp}/${name}`] ?? (name === "default" ? readComponentConfig(comp, "default") : void 0),
|
|
3601
|
+
// Installed components are a property of this install, not of the
|
|
3602
|
+
// bundle being imported, so the completeness fill (Wave 2) uses the
|
|
3603
|
+
// same list the disk resolver does.
|
|
3604
|
+
listComponentNames,
|
|
2492
3605
|
normalizeColorsAndType: (colorsAndType) => normalizeColorsAndType(colorsAndType)
|
|
2493
3606
|
};
|
|
2494
|
-
const { theme, dropped } = normalizeTheme(bundle.manifest, bundleResolvers);
|
|
3607
|
+
const { theme, dropped, filled } = normalizeTheme(bundle.manifest, bundleResolvers);
|
|
2495
3608
|
if (theme.colorsAndType) theme.colorsAndType = normalizeColorsAndType(theme.colorsAndType);
|
|
2496
3609
|
if (!theme.colorsAndType) {
|
|
2497
3610
|
jsonResponse(res, 400, { error: "Bundle carries no theme" });
|
|
@@ -2512,7 +3625,8 @@ ${lines.join("\n")}
|
|
|
2512
3625
|
ok: true,
|
|
2513
3626
|
theme: finalName,
|
|
2514
3627
|
renames,
|
|
2515
|
-
dropped
|
|
3628
|
+
dropped,
|
|
3629
|
+
filled
|
|
2516
3630
|
});
|
|
2517
3631
|
}
|
|
2518
3632
|
async function handleAdoptLook({ res }) {
|