@motion-proto/live-tokens 0.52.1 → 0.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/.claude/skills/live-tokens-adjust-shape-space/SKILL.md +7 -1
  2. package/CHANGELOG.md +63 -0
  3. package/bin/adjust.mjs +16 -39
  4. package/bin/generate-theme.mjs +20 -6
  5. package/dist-plugin/adjust/index.cjs +781 -21
  6. package/dist-plugin/adjust/index.d.cts +2 -1
  7. package/dist-plugin/adjust/index.d.ts +2 -1
  8. package/dist-plugin/adjust/index.js +43 -21
  9. package/dist-plugin/{chunk-6OZFXIQI.js → chunk-232GZGQU.js} +207 -12
  10. package/dist-plugin/chunk-NE6N66EE.js +753 -0
  11. package/dist-plugin/{chunk-JIGIIE5P.js → chunk-PB2JTK2H.js} +123 -0
  12. package/dist-plugin/generateColorsAndType/index.cjs +48 -32
  13. package/dist-plugin/generateColorsAndType/index.d.cts +2 -1
  14. package/dist-plugin/generateColorsAndType/index.d.ts +2 -1
  15. package/dist-plugin/generateColorsAndType/index.js +7 -773
  16. package/dist-plugin/{themeTypes-Dky03HL9.d.cts → index-DpTIRZ2H.d.cts} +49 -21
  17. package/dist-plugin/{themeTypes-Dky03HL9.d.ts → index-DpTIRZ2H.d.ts} +49 -21
  18. package/dist-plugin/index.cjs +1159 -85
  19. package/dist-plugin/index.js +102 -80
  20. package/dist-plugin/migrateData/index.cjs +956 -14
  21. package/dist-plugin/migrateData/index.js +10 -3
  22. package/package.json +6 -4
  23. package/src/editor/component-editor/scaffolding/ComponentFileManager.svelte +9 -23
  24. package/src/editor/component-editor/scaffolding/LinkedBlock.svelte +8 -8
  25. package/src/editor/core/components/adjustAliases.ts +49 -22
  26. package/src/editor/core/components/aliasKinds.ts +7 -2
  27. package/src/editor/core/components/componentConfigService.ts +1 -1
  28. package/src/editor/core/store/editorStore.ts +7 -197
  29. package/src/editor/core/store/editorTypes.ts +9 -30
  30. package/src/editor/core/themes/lookSummary.ts +3 -25
  31. package/src/editor/core/themes/migrateComponentConfig.ts +205 -0
  32. package/src/editor/core/themes/migrations/2026-05-19-sectiondivider-rich-gradient.ts +1 -1
  33. package/src/editor/core/themes/migrations/2026-05-20-sectiondivider-slim-variants.ts +1 -1
  34. package/src/editor/core/themes/migrations/2026-05-22-sectiondivider-intrinsics-to-css.ts +1 -1
  35. package/src/editor/core/themes/parsers/gradient.ts +211 -0
  36. package/src/editor/core/themes/slices/gradients.ts +5 -58
  37. package/src/editor/core/themes/themeService.ts +22 -9
  38. package/src/editor/core/themes/themeTypes.ts +71 -21
  39. package/src/editor/docs/content/themes-workflow.md +9 -11
  40. package/src/editor/docs/content/where-themes-live.md +2 -2
  41. package/src/editor/docs/content.generated.ts +2 -2
  42. package/src/editor/index.ts +1 -0
  43. package/src/editor/styles/ui-editor.css +5 -2
  44. package/src/editor/ui/PaletteEditor.svelte +30 -15
  45. package/src/editor/ui/ThemePanel.svelte +24 -15
  46. package/src/editor/ui/Toggle.svelte +22 -22
  47. package/src/editor/ui/UIPillButton.svelte +1 -1
  48. package/src/editor/ui/UIReveal.svelte +47 -0
  49. package/src/editor/ui/UISquareButton.svelte +1 -1
  50. package/src/editor/ui/colors/ColorsTab.svelte +4 -5
  51. package/src/editor/ui/palette/OverridesPanel.svelte +4 -3
  52. package/src/editor/ui/palette/PaletteJumpButton.svelte +3 -3
  53. package/src/editor/ui/palette/ScaleCurveEditor.svelte +3 -2
  54. package/src/live-tokens/data/themes/autumn.json +77 -41
  55. package/src/live-tokens/data/themes/halloween.json +53 -52
  56. package/src/live-tokens/data/themes/midnight-study.json +136 -68
  57. package/src/live-tokens/data/themes/ocean.json +77 -41
  58. package/src/live-tokens/data/themes/royal-velvet.json +43 -42
  59. package/src/live-tokens/data/themes/spring-meadow.json +86 -52
  60. package/src/live-tokens/data/themes/sunset.json +101 -40
@@ -1,4 +1,5 @@
1
- import { A as AliasDiskValue, a as ComponentConfig } from '../themeTypes-Dky03HL9.cjs';
1
+ import { A as AliasDiskValue, b as ComponentConfig } from '../index-DpTIRZ2H.cjs';
2
+ export { C as CURRENT_COMPONENT_SCHEMA_VERSION } from '../index-DpTIRZ2H.cjs';
2
3
  export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-DBN0RPuT.cjs';
3
4
 
4
5
  type AdjustKind = 'radius' | 'padding' | 'gap' | 'border-width';
@@ -1,4 +1,5 @@
1
- import { A as AliasDiskValue, a as ComponentConfig } from '../themeTypes-Dky03HL9.js';
1
+ import { A as AliasDiskValue, b as ComponentConfig } from '../index-DpTIRZ2H.js';
2
+ export { C as CURRENT_COMPONENT_SCHEMA_VERSION } from '../index-DpTIRZ2H.js';
2
3
  export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-DBN0RPuT.js';
3
4
 
4
5
  type AdjustKind = 'radius' | 'padding' | 'gap' | 'border-width';
@@ -1,3 +1,6 @@
1
+ import {
2
+ CURRENT_COMPONENT_SCHEMA_VERSION
3
+ } from "../chunk-NE6N66EE.js";
1
4
  import {
2
5
  readLiveTokensConfig,
3
6
  resolveDataDirs
@@ -31,9 +34,12 @@ var MATCHER_BY_KIND = Object.fromEntries(
31
34
  KIND_PATTERNS.map((p) => [p.kind, p.matches])
32
35
  );
33
36
  var SIDE_SUFFIXES = ["-top", "-right", "-bottom", "-left"];
34
- function matchesKind(variable, kind) {
37
+ function stripSide(variable) {
35
38
  const side = SIDE_SUFFIXES.find((s) => variable.endsWith(s));
36
- return MATCHER_BY_KIND[kind](side ? variable.slice(0, -side.length) : variable);
39
+ return side ? variable.slice(0, -side.length) : variable;
40
+ }
41
+ function matchesKind(variable, kind) {
42
+ return MATCHER_BY_KIND[kind](stripSide(variable));
37
43
  }
38
44
 
39
45
  // src/editor/core/components/adjustAliases.ts
@@ -48,7 +54,7 @@ var RADIUS_RUNGS = [
48
54
  "--radius-3xl",
49
55
  "--radius-4xl"
50
56
  ];
51
- var SPACE_RUNGS = [
57
+ var SPACE_SETTABLE = [
52
58
  "--space-0",
53
59
  "--space-2",
54
60
  "--space-4",
@@ -62,7 +68,9 @@ var SPACE_RUNGS = [
62
68
  "--space-32",
63
69
  "--space-48"
64
70
  ];
65
- var SPACE_FAMILY = [...SPACE_RUNGS, "--space-40", "--space-64", "--space-96", "--space-128"];
71
+ var SPACE_RUNGS = SPACE_SETTABLE;
72
+ var INSET_RUNGS = SPACE_SETTABLE.slice(SPACE_SETTABLE.indexOf("--space-4"));
73
+ var SPACE_FAMILY = [...SPACE_SETTABLE, "--space-40", "--space-64", "--space-96", "--space-128"];
66
74
  var BORDER_WIDTH_RUNGS = [
67
75
  "--border-width-0",
68
76
  "--border-width-1",
@@ -79,37 +87,50 @@ var BORDER_WIDTH_RUNGS = [
79
87
  "--border-width-24"
80
88
  ];
81
89
  var LADDERS = {
82
- radius: { rungs: RADIUS_RUNGS, family: [...RADIUS_RUNGS, RADIUS_FULL] },
83
- padding: { rungs: SPACE_RUNGS, family: SPACE_FAMILY },
84
- gap: { rungs: SPACE_RUNGS, family: SPACE_FAMILY },
85
- "border-width": { rungs: BORDER_WIDTH_RUNGS, family: BORDER_WIDTH_RUNGS }
90
+ radius: {
91
+ rungs: RADIUS_RUNGS,
92
+ settable: [...RADIUS_RUNGS, RADIUS_FULL],
93
+ family: [...RADIUS_RUNGS, RADIUS_FULL]
94
+ },
95
+ padding: { rungs: SPACE_RUNGS, settable: SPACE_SETTABLE, family: SPACE_FAMILY },
96
+ gap: { rungs: SPACE_RUNGS, settable: SPACE_SETTABLE, family: SPACE_FAMILY },
97
+ "border-width": {
98
+ rungs: BORDER_WIDTH_RUNGS,
99
+ settable: BORDER_WIDTH_RUNGS,
100
+ family: BORDER_WIDTH_RUNGS
101
+ }
86
102
  };
87
103
  var TOKEN_NAME = /^--[a-z0-9-]+$/;
88
- function rungsFor(op) {
89
- return op.kind === "radius" && op.full ? [...RADIUS_RUNGS, RADIUS_FULL] : LADDERS[op.kind].rungs;
104
+ function rungsFor(op, variable) {
105
+ if (op.kind === "radius") return op.full ? [...RADIUS_RUNGS, RADIUS_FULL] : RADIUS_RUNGS;
106
+ if (op.kind === "padding" && stripSide(variable).endsWith("-padding")) return INSET_RUNGS;
107
+ return LADDERS[op.kind].rungs;
90
108
  }
91
109
  function spaceStep(token) {
92
110
  return Number(token.slice("--space-".length));
93
111
  }
94
- function nearestSpaceRung(token, rungs) {
112
+ function snapRung(token, rungs, direction) {
95
113
  const step = spaceStep(token);
96
- let best = 0;
97
- for (let i = 1; i < rungs.length; i++) {
98
- if (Math.abs(spaceStep(rungs[i]) - step) <= Math.abs(spaceStep(rungs[best]) - step)) best = i;
114
+ if (direction > 0) return rungs.findIndex((rung) => spaceStep(rung) > step);
115
+ for (let index = rungs.length - 1; index >= 0; index--) {
116
+ if (spaceStep(rungs[index]) < step) return index;
99
117
  }
100
- return best;
118
+ return -1;
101
119
  }
102
- function resolve(op, value) {
120
+ function resolve(op, variable, value) {
103
121
  if (typeof value !== "string" || !TOKEN_NAME.test(value)) return { skip: "raw-value" };
104
122
  if (!LADDERS[op.kind].family.includes(value)) return { skip: "off-ladder" };
105
123
  if (op.set !== void 0) return { from: value, to: op.set };
106
- const rungs = rungsFor(op);
124
+ const rungs = rungsFor(op, variable);
107
125
  let index = rungs.indexOf(value);
126
+ let shift = op.shift;
108
127
  if (index < 0) {
109
128
  if (value === RADIUS_FULL) return { skip: "pill-preserved" };
110
- index = nearestSpaceRung(value, rungs);
129
+ index = snapRung(value, rungs, shift);
130
+ if (index < 0) return { skip: "clamped" };
131
+ shift -= Math.sign(shift);
111
132
  }
112
- const wanted = index + op.shift;
133
+ const wanted = index + shift;
113
134
  const landed = Math.min(Math.max(wanted, 0), rungs.length - 1);
114
135
  if (landed !== wanted && rungs[landed] === value) return { skip: "clamped" };
115
136
  return { from: value, to: rungs[landed] };
@@ -123,7 +144,7 @@ function validateOp(op, configs) {
123
144
  const hasSet = op.set !== void 0;
124
145
  const hasShift = op.shift !== void 0;
125
146
  if (hasSet === hasShift) throw new Error(`A ${op.kind} op needs exactly one of "set" or "shift"`);
126
- const settable = op.kind === "radius" ? ladder.family : ladder.rungs;
147
+ const settable = ladder.settable;
127
148
  if (hasSet && !settable.includes(op.set)) {
128
149
  throw new Error(`"${op.set}" is not on the ${op.kind} ladder`);
129
150
  }
@@ -153,7 +174,7 @@ function adjustAliases(configs, ops, now) {
153
174
  let changed = false;
154
175
  for (const [variable, value] of Object.entries(config.aliases)) {
155
176
  if (!matchesKind(variable, op.kind)) continue;
156
- const outcome = resolve(op, value);
177
+ const outcome = resolve(op, variable, value);
157
178
  if ("skip" in outcome) {
158
179
  reportFor(component).skips.push({ variable, value, reason: outcome.skip });
159
180
  continue;
@@ -169,6 +190,7 @@ function adjustAliases(configs, ops, now) {
169
190
  return { configs: next, report: { components: [...reports.values()] } };
170
191
  }
171
192
  export {
193
+ CURRENT_COMPONENT_SCHEMA_VERSION,
172
194
  adjustAliases,
173
195
  matchesKind,
174
196
  readLiveTokensConfig,
@@ -1,3 +1,8 @@
1
+ import {
2
+ CURRENT_COMPONENT_SCHEMA_VERSION,
3
+ runMigrations
4
+ } from "./chunk-NE6N66EE.js";
5
+
1
6
  // vite-plugin/files/versionedFileResourceServer.ts
2
7
  import fs from "fs";
3
8
  import path from "path";
@@ -129,8 +134,141 @@ function versionedFileResourceServer(opts) {
129
134
  };
130
135
  }
131
136
 
137
+ // src/editor/core/themes/themeTypes.ts
138
+ var THEME_SCHEMA_VERSION = 4;
139
+
140
+ // src/editor/core/themes/migrateComponentConfig.ts
141
+ function migrateComponentConfig(component, aliasesIn, rawConfig, fileVersion) {
142
+ const stringPart = {};
143
+ const objectPart = {};
144
+ for (const [k, v] of Object.entries(aliasesIn)) {
145
+ if (typeof v === "string") stringPart[k] = v;
146
+ else objectPart[k] = v;
147
+ }
148
+ const configOut = {};
149
+ for (const [k, v] of Object.entries(rawConfig ?? {})) {
150
+ if (typeof v === "string") stringPart[k] = v;
151
+ else configOut[k] = v;
152
+ }
153
+ if (component === "sectiondivider") {
154
+ synthesizeSectionDividerGradients(stringPart, objectPart);
155
+ }
156
+ const migratedString = runMigrations("component-config", fileVersion, stringPart, { component });
157
+ const migratedObject = component === "sectiondivider" ? renameSectionDividerObjectSlots(objectPart) : objectPart;
158
+ return {
159
+ aliases: { ...migratedString, ...migratedObject },
160
+ config: configOut
161
+ };
162
+ }
163
+ var FAMILIES = ["canvas", "neutral", "alternate", "primary", "accent", "special"];
164
+ var SIZE_VARIANTS = ["lg", "md", "sm"];
165
+ function renameSectionDividerObjectSlots(objectPart) {
166
+ const canvasSourceKeys = [
167
+ "--sectiondivider-canvas-background",
168
+ "--sectiondivider-canvas-gradient",
169
+ "--sectiondivider-color-canvas-background"
170
+ ];
171
+ let canvasGradient;
172
+ for (const key of canvasSourceKeys) {
173
+ if (objectPart[key] !== void 0) {
174
+ canvasGradient = objectPart[key];
175
+ break;
176
+ }
177
+ }
178
+ const out = {};
179
+ for (const [key, value] of Object.entries(objectPart)) {
180
+ let isFamilyGradient = false;
181
+ for (const f of FAMILIES) {
182
+ if (key === `--sectiondivider-${f}-background` || key === `--sectiondivider-${f}-gradient` || key === `--sectiondivider-color-${f}-background`) {
183
+ isFamilyGradient = true;
184
+ break;
185
+ }
186
+ }
187
+ if (isFamilyGradient) continue;
188
+ out[key] = value;
189
+ }
190
+ if (canvasGradient !== void 0) {
191
+ for (const v of SIZE_VARIANTS) {
192
+ out[`--sectiondivider-${v}-background`] = canvasGradient;
193
+ }
194
+ }
195
+ return out;
196
+ }
197
+ var SECTIONDIVIDER_VARIANTS = ["canvas", "neutral", "alternate", "primary", "accent", "special"];
198
+ function synthesizeSectionDividerGradients(stringPart, objectPart) {
199
+ const GRADIENT_ANGLE_TOKENS = {
200
+ "--gradient-angle-horizontal": 90,
201
+ "--gradient-angle-vertical": 180,
202
+ "--gradient-angle-diagonal": 135,
203
+ "--gradient-angle-counter-diagonal": 45
204
+ };
205
+ const GRADIENT_STOP_POSITIONS = {
206
+ "--gradient-stop-start": 0,
207
+ "--gradient-stop-mid": 50,
208
+ "--gradient-stop-end": 100
209
+ };
210
+ const parseAngle = (raw) => {
211
+ if (!raw) return 135;
212
+ if (raw.startsWith("--")) return GRADIENT_ANGLE_TOKENS[raw] ?? 135;
213
+ const m = raw.match(/^(-?\d+(?:\.\d+)?)\s*deg$/i);
214
+ return m ? parseFloat(m[1]) : 135;
215
+ };
216
+ const parsePosition = (raw, fallback) => {
217
+ if (!raw) return fallback;
218
+ if (raw.startsWith("--")) return GRADIENT_STOP_POSITIONS[raw] ?? fallback;
219
+ const m = raw.match(/^(-?\d+(?:\.\d+)?)\s*%$/);
220
+ return m ? parseFloat(m[1]) : fallback;
221
+ };
222
+ const parseStopColor = (raw) => {
223
+ if (!raw) return null;
224
+ if (raw.startsWith("--")) return { color: raw };
225
+ const mix = raw.match(/^color-mix\(\s*in\s+srgb\s*,\s*var\((--[a-z0-9-]+)\)\s+([\d.]+)%\s*,\s*transparent\s*\)$/i);
226
+ if (mix) return { color: mix[1], opacity: parseFloat(mix[2]) };
227
+ return null;
228
+ };
229
+ for (const v of SECTIONDIVIDER_VARIANTS) {
230
+ const slot = `--sectiondivider-${v}-gradient`;
231
+ if (slot in objectPart) continue;
232
+ const angleKey = `${slot}-angle`;
233
+ const has1 = stringPart[`${slot}-stop-1-color`] !== void 0;
234
+ const has2 = stringPart[`${slot}-stop-2-color`] !== void 0;
235
+ const has3 = stringPart[`${slot}-stop-3-color`] !== void 0;
236
+ if (!has1 && !has2 && !has3) continue;
237
+ const stops = [];
238
+ const positionDefaults = [0, 50, 100];
239
+ for (let i = 1; i <= 3; i++) {
240
+ const c = parseStopColor(stringPart[`${slot}-stop-${i}-color`]);
241
+ if (!c) continue;
242
+ const pos = parsePosition(stringPart[`${slot}-stop-${i}-position`], positionDefaults[i - 1]);
243
+ stops.push({ position: pos, color: c.color, ...c.opacity !== void 0 ? { opacity: c.opacity } : {} });
244
+ }
245
+ if (stops.length < 2) continue;
246
+ objectPart[slot] = {
247
+ kind: "gradient",
248
+ value: {
249
+ type: "linear",
250
+ angle: parseAngle(stringPart[angleKey]),
251
+ stops
252
+ }
253
+ };
254
+ }
255
+ }
256
+
257
+ // src/editor/core/components/componentConfigKeys.ts
258
+ var KNOWN_COMPONENT_CONFIG_KEYS = /* @__PURE__ */ new Set([
259
+ "--dialog-confirm-variant",
260
+ "--dialog-cancel-variant",
261
+ // SectionDivider per-variant `color-family` is editor metadata that drives
262
+ // the family-swap rewrite on aliases. It is not a runtime CSS value, so it
263
+ // stays in the config bucket. The other intrinsics (align, hairline,
264
+ // eyebrow/description visibility, eyebrow text-transform) now flow through
265
+ // the alias bucket as cascading CSS vars — see the 2026-05-22 migration.
266
+ "--sectiondivider-lg-color-family",
267
+ "--sectiondivider-md-color-family",
268
+ "--sectiondivider-sm-color-family"
269
+ ]);
270
+
132
271
  // vite-plugin/themes/normalizeTheme.ts
133
- var THEME_SCHEMA_VERSION = 3;
134
272
  function asObject(value) {
135
273
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
136
274
  }
@@ -152,10 +290,41 @@ function migrateEmbeddedKey(src) {
152
290
  const { theme, ...rest } = src;
153
291
  return { ...rest, colorsAndType: theme };
154
292
  }
293
+ function routeKnownConfigKeys(aliases, config) {
294
+ const outAliases = { ...aliases };
295
+ const outConfig = { ...config };
296
+ for (const key of Object.keys(outAliases)) {
297
+ if (!KNOWN_COMPONENT_CONFIG_KEYS.has(key)) continue;
298
+ if (outConfig[key] === void 0) outConfig[key] = outAliases[key];
299
+ delete outAliases[key];
300
+ }
301
+ return { aliases: outAliases, config: outConfig };
302
+ }
303
+ function migrateEmbeddedComponentConfig(comp, config, fileVersion) {
304
+ const { schemaVersion: _entryStamp, aliases: rawAliases, config: rawConfig, ...rest } = config;
305
+ const aliasesIn = asObject(rawAliases);
306
+ if (!aliasesIn) {
307
+ return rawConfig !== void 0 ? { ...rest, config: rawConfig } : rest;
308
+ }
309
+ const migratedConfig = migrateComponentConfig(
310
+ comp,
311
+ aliasesIn,
312
+ asObject(rawConfig) ?? void 0,
313
+ fileVersion
314
+ );
315
+ const split = routeKnownConfigKeys(migratedConfig.aliases, migratedConfig.config);
316
+ const out = { ...rest, aliases: split.aliases };
317
+ if (rawConfig !== void 0 || Object.keys(split.config).length > 0) {
318
+ out.config = split.config;
319
+ }
320
+ return out;
321
+ }
155
322
  function normalizeTheme(raw, resolvers) {
156
323
  const input = asObject(raw) ?? {};
157
324
  const migrated = input.schemaVersion !== THEME_SCHEMA_VERSION;
158
- const src = migrated ? migrateEmbeddedKey(input) : input;
325
+ const inputVersion = typeof input.schemaVersion === "number" ? input.schemaVersion : 0;
326
+ const src = inputVersion < 3 ? migrateEmbeddedKey(input) : input;
327
+ const componentSchemaVersion = typeof input.componentSchemaVersion === "number" ? input.componentSchemaVersion : 0;
159
328
  const dropped = [];
160
329
  const now = (/* @__PURE__ */ new Date()).toISOString();
161
330
  const embeddedColorsAndType = asObject(src.colorsAndType);
@@ -174,18 +343,42 @@ function normalizeTheme(raw, resolvers) {
174
343
  const componentConfigs = {};
175
344
  for (const [comp, value] of Object.entries(asObject(src.componentConfigs) ?? {})) {
176
345
  const embedded = asObject(value);
346
+ let resolvedConfig;
177
347
  if (embedded) {
178
- componentConfigs[comp] = stripFileMarker(embedded);
179
- continue;
348
+ resolvedConfig = stripFileMarker(embedded);
349
+ } else {
350
+ const configName = asString(value, "default");
351
+ const resolved = asObject(resolvers.readComponentConfig(comp, configName));
352
+ if (!resolved) {
353
+ dropped.push(`${comp}/${configName}`);
354
+ continue;
355
+ }
356
+ resolvedConfig = stripFileMarker(resolved);
180
357
  }
181
- const configName = asString(value, "default");
182
- if (configName === "default") continue;
183
- const resolved = asObject(resolvers.readComponentConfig(comp, configName));
184
- if (!resolved) {
185
- dropped.push(`${comp}/${configName}`);
358
+ componentConfigs[comp] = migrateEmbeddedComponentConfig(comp, resolvedConfig, componentSchemaVersion);
359
+ }
360
+ const filled = { components: [], aliases: 0, orphans: 0 };
361
+ for (const comp of resolvers.listComponentNames()) {
362
+ const base = asObject(resolvers.readComponentConfig(comp, "default"));
363
+ const baseAliases = base ? asObject(base.aliases) : null;
364
+ if (!base || !baseAliases) continue;
365
+ const entry = componentConfigs[comp];
366
+ if (!entry) {
367
+ const { schemaVersion: _standaloneStamp, ...rest } = stripFileMarker(base);
368
+ componentConfigs[comp] = structuredClone(rest);
369
+ filled.components.push(comp);
186
370
  continue;
187
371
  }
188
- componentConfigs[comp] = stripFileMarker(resolved);
372
+ const entryAliases = asObject(entry.aliases) ?? {};
373
+ for (const key of Object.keys(baseAliases)) {
374
+ if (key in entryAliases) continue;
375
+ entryAliases[key] = structuredClone(baseAliases[key]);
376
+ filled.aliases++;
377
+ }
378
+ entry.aliases = entryAliases;
379
+ for (const key of Object.keys(entryAliases)) {
380
+ if (!(key in baseAliases)) filled.orphans++;
381
+ }
189
382
  }
190
383
  return {
191
384
  theme: {
@@ -194,10 +387,12 @@ function normalizeTheme(raw, resolvers) {
194
387
  updatedAt: asString(src.updatedAt, now),
195
388
  schemaVersion: THEME_SCHEMA_VERSION,
196
389
  colorsAndType,
197
- componentConfigs
390
+ componentConfigs,
391
+ componentSchemaVersion: CURRENT_COMPONENT_SCHEMA_VERSION
198
392
  },
199
393
  dropped,
200
- migrated
394
+ migrated,
395
+ filled
201
396
  };
202
397
  }
203
398