@motion-proto/live-tokens 0.67.1 → 0.69.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 (138) hide show
  1. package/.claude/skills/live-tokens-build-page/SKILL.md +16 -5
  2. package/.claude/skills/live-tokens-create-component/SKILL.md +43 -8
  3. package/.claude/skills/live-tokens-create-component/references/token-naming.md +30 -1
  4. package/.claude/skills/live-tokens-fix-findings/SKILL.md +131 -0
  5. package/.claude/skills/live-tokens-pick-component/SKILL.md +2 -1
  6. package/CHANGELOG.md +239 -0
  7. package/README.md +11 -4
  8. package/bin/check-component.mjs +367 -63
  9. package/bin/check-page.mjs +409 -0
  10. package/bin/cli.mjs +57 -8
  11. package/bin/generate-theme.mjs +5 -4
  12. package/bin/lib/cssValues.mjs +50 -0
  13. package/bin/lib/findings.mjs +106 -0
  14. package/bin/lib/tokenVocabulary.mjs +213 -0
  15. package/dist-plugin/adjust/index.cjs +174 -23
  16. package/dist-plugin/adjust/index.d.cts +1 -1
  17. package/dist-plugin/adjust/index.d.ts +1 -1
  18. package/dist-plugin/adjust/index.js +68 -23
  19. package/dist-plugin/{chunk-J2JT4UEA.js → chunk-2YNERPXY.js} +26 -26
  20. package/dist-plugin/{chunk-NE6N66EE.js → chunk-GPIBU44G.js} +107 -1
  21. package/dist-plugin/{chunk-ZHPX7ZYQ.js → chunk-RFVYPNRO.js} +39 -1
  22. package/dist-plugin/{dataPaths-DZUzVv8H.d.ts → dataPaths-bJTCEO4H.d.cts} +1 -1
  23. package/dist-plugin/{dataPaths-DZUzVv8H.d.cts → dataPaths-bJTCEO4H.d.ts} +1 -1
  24. package/dist-plugin/fontPairing/index.d.cts +1 -1
  25. package/dist-plugin/fontPairing/index.d.ts +1 -1
  26. package/dist-plugin/generateColorsAndType/index.cjs +107 -1
  27. package/dist-plugin/generateColorsAndType/index.d.cts +1 -1
  28. package/dist-plugin/generateColorsAndType/index.d.ts +1 -1
  29. package/dist-plugin/generateColorsAndType/index.js +1 -1
  30. package/dist-plugin/index.cjs +173 -29
  31. package/dist-plugin/index.d.cts +1 -1
  32. package/dist-plugin/index.d.ts +1 -1
  33. package/dist-plugin/index.js +7 -7
  34. package/dist-plugin/migrateData/index.cjs +132 -26
  35. package/dist-plugin/migrateData/index.d.cts +1 -1
  36. package/dist-plugin/migrateData/index.d.ts +1 -1
  37. package/dist-plugin/migrateData/index.js +2 -2
  38. package/dist-plugin/tokensCssMigrations/index.cjs +39 -1
  39. package/dist-plugin/tokensCssMigrations/index.d.cts +1 -1
  40. package/dist-plugin/tokensCssMigrations/index.d.ts +1 -1
  41. package/dist-plugin/tokensCssMigrations/index.js +1 -1
  42. package/package.json +6 -5
  43. package/src/app/site.css +4 -4
  44. package/src/editor/bootstrap.ts +6 -6
  45. package/src/editor/component-editor/ButtonEditor.svelte +71 -4
  46. package/src/editor/component-editor/CardEditor.svelte +6 -6
  47. package/src/editor/component-editor/DialogEditor.svelte +3 -3
  48. package/src/editor/component-editor/IconButtonEditor.svelte +68 -3
  49. package/src/editor/component-editor/ImageEditor.svelte +8 -8
  50. package/src/editor/component-editor/ImageLightboxEditor.svelte +13 -2
  51. package/src/editor/component-editor/MenuSelectEditor.svelte +63 -3
  52. package/src/editor/component-editor/SegmentedControlEditor.svelte +63 -3
  53. package/src/editor/component-editor/SideNavigationEditor.svelte +67 -3
  54. package/src/editor/component-editor/SliderEditor.svelte +186 -0
  55. package/src/editor/component-editor/TabBarEditor.svelte +63 -3
  56. package/src/editor/component-editor/registry.ts +10 -0
  57. package/src/editor/component-editor/scaffolding/ComponentFileManager.svelte +4 -4
  58. package/src/editor/core/components/aliasKinds.ts +51 -28
  59. package/src/editor/core/fonts/fontLoader.ts +2 -2
  60. package/src/editor/core/preview/{lookPreview.ts → themePreview.ts} +27 -27
  61. package/src/editor/core/productionPulse.ts +3 -3
  62. package/src/editor/core/sketch/index.ts +52 -44
  63. package/src/editor/core/sketch/maskField.ts +9 -9
  64. package/src/editor/core/sketch/sketchLayer.ts +25 -9
  65. package/src/editor/core/sketch/sketchRegistry.ts +34 -34
  66. package/src/editor/core/sketch/sketchStore.ts +98 -83
  67. package/src/editor/core/sketch/sketchStyleService.ts +4 -4
  68. package/src/editor/core/sketch/sketchStyles.ts +28 -28
  69. package/src/editor/core/store/editorPersistence.ts +44 -1
  70. package/src/editor/core/store/editorRenderer.ts +2 -2
  71. package/src/editor/core/store/editorStore.ts +18 -18
  72. package/src/editor/core/store/editorTypes.ts +7 -6
  73. package/src/editor/core/themes/colorsAndTypeService.ts +1 -1
  74. package/src/editor/core/themes/loadRows.ts +8 -8
  75. package/src/editor/core/themes/migrations/2026-09-01-gate-suffix-enabled.ts +31 -0
  76. package/src/editor/core/themes/migrations/2026-09-01-scrim-rename.ts +52 -0
  77. package/src/editor/core/themes/migrations/2026-09-01-tabbar-active-tint.ts +27 -0
  78. package/src/editor/core/themes/migrations/2026-09-01-tint-rename.ts +42 -0
  79. package/src/editor/core/themes/migrations/index.ts +16 -0
  80. package/src/editor/core/themes/slices/domainVars.ts +2 -2
  81. package/src/editor/core/themes/slices/washes.ts +107 -0
  82. package/src/editor/core/themes/themeDocumentSync.ts +2 -2
  83. package/src/editor/core/themes/themeInit.ts +2 -2
  84. package/src/editor/core/themes/themeService.ts +17 -17
  85. package/src/editor/core/themes/{lookSummary.ts → themeSummary.ts} +9 -9
  86. package/src/editor/core/themes/themeTypes.ts +10 -6
  87. package/src/editor/docs/content/editing-tokens.md +5 -3
  88. package/src/editor/docs/content/getting-started.md +1 -1
  89. package/src/editor/docs/content/sketch-mode.md +22 -17
  90. package/src/editor/docs/content/themes-workflow.md +11 -11
  91. package/src/editor/docs/content/where-themes-live.md +6 -6
  92. package/src/editor/docs/content.generated.ts +5 -5
  93. package/src/editor/index.ts +2 -2
  94. package/src/editor/pages/EditorShell.svelte +1 -1
  95. package/src/editor/ui/SurfacesTab.svelte +3 -3
  96. package/src/editor/ui/ThemePanel.svelte +52 -52
  97. package/src/editor/ui/UITokenSelector.svelte +1 -0
  98. package/src/editor/ui/VariablesTab.svelte +2 -2
  99. package/src/editor/ui/sections/{OverlaysSection.svelte → WashesSection.svelte} +44 -43
  100. package/src/editor/ui/sketch/SketchPreview.svelte +2 -2
  101. package/src/editor/ui/sketch/SketchTab.svelte +64 -38
  102. package/src/live-tokens/data/colors-and-type/autumn.json +6 -6
  103. package/src/live-tokens/data/colors-and-type/default.json +6 -6
  104. package/src/live-tokens/data/colors-and-type/halloween.json +6 -6
  105. package/src/live-tokens/data/colors-and-type/midnight-study.json +6 -6
  106. package/src/live-tokens/data/colors-and-type/ocean.json +6 -6
  107. package/src/live-tokens/data/colors-and-type/royal-velvet.json +6 -6
  108. package/src/live-tokens/data/colors-and-type/sketchy.json +6 -6
  109. package/src/live-tokens/data/colors-and-type/spring-meadow.json +6 -6
  110. package/src/live-tokens/data/colors-and-type/sunset.json +6 -6
  111. package/src/live-tokens/data/sketch-styles/dry.json +5 -5
  112. package/src/live-tokens/data/sketch-styles/hatched.json +9 -9
  113. package/src/live-tokens/data/themes/autumn.json +82 -14
  114. package/src/live-tokens/data/themes/halloween.json +82 -14
  115. package/src/live-tokens/data/themes/midnight-study.json +82 -14
  116. package/src/live-tokens/data/themes/ocean.json +82 -14
  117. package/src/live-tokens/data/themes/royal-velvet.json +82 -14
  118. package/src/live-tokens/data/themes/sketchy.json +82 -14
  119. package/src/live-tokens/data/themes/spring-meadow.json +82 -14
  120. package/src/live-tokens/data/themes/sunset.json +82 -14
  121. package/src/live-tokens/data/tokens.generated.css +6 -6
  122. package/src/system/backdrop/backdrop.ts +1 -1
  123. package/src/system/components/Button.svelte +28 -10
  124. package/src/system/components/Card.svelte +6 -6
  125. package/src/system/components/Dialog.svelte +3 -3
  126. package/src/system/components/IconButton.svelte +23 -7
  127. package/src/system/components/Image.svelte +6 -6
  128. package/src/system/components/MenuSelect.svelte +17 -1
  129. package/src/system/components/SectionDivider.svelte +1 -1
  130. package/src/system/components/SegmentedControl.svelte +20 -2
  131. package/src/system/components/SideNavigation.svelte +22 -2
  132. package/src/system/components/Slider.svelte +348 -0
  133. package/src/system/components/TabBar.svelte +20 -2
  134. package/src/system/styles/CONVENTIONS.md +2 -2
  135. package/src/system/styles/tokens.css +12 -4
  136. package/template/package.json +3 -2
  137. package/template/src/pages/Home.svelte +1 -1
  138. package/src/editor/core/themes/slices/overlays.ts +0 -101
@@ -0,0 +1,106 @@
1
+ // Severity resolution and reporting shared by check-page and check-component.
2
+ //
3
+ // Every rule has a default severity. Three things can override it, last wins:
4
+ // `checks.rules` in live-tokens.config.json, then the CLI flags
5
+ // (--off/--warn/--error), then --strict, which promotes every warning.
6
+ //
7
+ // A checker returns findings; this module decides what they mean and how they
8
+ // print. `--json` output is the contract a skill iterates against, so the shape
9
+ // here is deliberately stable.
10
+
11
+ import { existsSync, readFileSync } from 'node:fs';
12
+ import { join } from 'node:path';
13
+
14
+ export const SEVERITIES = ['off', 'warn', 'error'];
15
+
16
+ /** Line number of `index` within `text`, 1-based. */
17
+ export function lineOf(text, index) {
18
+ let line = 1;
19
+ for (let i = 0; i < index && i < text.length; i++) if (text[i] === '\n') line++;
20
+ return line;
21
+ }
22
+
23
+ export function readChecksConfig(root) {
24
+ const path = join(root, 'live-tokens.config.json');
25
+ if (!existsSync(path)) return {};
26
+ try {
27
+ return JSON.parse(readFileSync(path, 'utf8')).checks ?? {};
28
+ } catch {
29
+ return {};
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Parse `--off=a,b --warn=c --error=d --strict --json` out of argv.
35
+ * Unrecognised flags are returned in `rest` for the caller to handle.
36
+ */
37
+ export function parseCheckFlags(argv) {
38
+ const opts = { off: [], warn: [], error: [], strict: false, json: false, rest: [] };
39
+ for (const arg of argv) {
40
+ const m = arg.match(/^--(off|warn|error)=(.+)$/);
41
+ if (m) {
42
+ opts[m[1]].push(...m[2].split(',').map((s) => s.trim()).filter(Boolean));
43
+ } else if (arg === '--strict') opts.strict = true;
44
+ else if (arg === '--json') opts.json = true;
45
+ else opts.rest.push(arg);
46
+ }
47
+ return opts;
48
+ }
49
+
50
+ /**
51
+ * Resolve each finding's severity and drop the ones turned off.
52
+ * `rules` maps rule id to its default severity.
53
+ */
54
+ export function applySeverity(findings, rules, opts = {}, config = {}) {
55
+ const configured = config.rules ?? {};
56
+ const resolve = (id) => {
57
+ let severity = rules[id] ?? 'error';
58
+ if (SEVERITIES.includes(configured[id])) severity = configured[id];
59
+ if (opts.off?.includes(id)) severity = 'off';
60
+ if (opts.warn?.includes(id)) severity = 'warn';
61
+ if (opts.error?.includes(id)) severity = 'error';
62
+ if (opts.strict && severity === 'warn') severity = 'error';
63
+ return severity;
64
+ };
65
+ return findings
66
+ .map((f) => ({ ...f, severity: resolve(f.rule) }))
67
+ .filter((f) => f.severity !== 'off');
68
+ }
69
+
70
+ export function countBySeverity(findings) {
71
+ return {
72
+ errors: findings.filter((f) => f.severity === 'error').length,
73
+ warnings: findings.filter((f) => f.severity === 'warn').length,
74
+ };
75
+ }
76
+
77
+ export function formatFindings(findings, { label, checked = 0 } = {}) {
78
+ const { errors, warnings } = countBySeverity(findings);
79
+ if (findings.length === 0) {
80
+ return `✓ ${label}: ${checked} file(s) clean.`;
81
+ }
82
+ const lines = [];
83
+ const byFile = new Map();
84
+ for (const f of findings) {
85
+ if (!byFile.has(f.file)) byFile.set(f.file, []);
86
+ byFile.get(f.file).push(f);
87
+ }
88
+ for (const [file, group] of byFile) {
89
+ lines.push(file);
90
+ for (const f of group.sort((a, b) => a.line - b.line)) {
91
+ const mark = f.severity === 'error' ? '✗' : '!';
92
+ lines.push(` ${mark} ${f.line}: ${f.message} [${f.rule}]`);
93
+ }
94
+ lines.push('');
95
+ }
96
+ lines.push(`${label}: ${errors} error(s), ${warnings} warning(s) across ${checked} file(s).`);
97
+ if (warnings > 0 && errors === 0) {
98
+ lines.push('Warnings do not fail the check. Re-run with --strict to treat them as errors.');
99
+ }
100
+ return lines.join('\n');
101
+ }
102
+
103
+ export function toJson(findings, { label, checked = 0 } = {}) {
104
+ const { errors, warnings } = countBySeverity(findings);
105
+ return JSON.stringify({ check: label, checked, errors, warnings, findings }, null, 2);
106
+ }
@@ -0,0 +1,213 @@
1
+ // The token and component vocabulary both static checkers validate against.
2
+ //
3
+ // One module so `check-page` and `check-component` can never disagree about
4
+ // what counts as a real token. Two sources feed it:
5
+ //
6
+ // 1. tokens.css — the developer-authored file (the consumer's, or the
7
+ // package's when a consumer has none yet). A theme token *is* a name
8
+ // declared here; there is no second register of tokens to consult.
9
+ // 2. Component tokens — every `--<id>-*` a component declares in its
10
+ // `:global(:root)` block, shipped or consumer-authored.
11
+ //
12
+ // A state word is not a token. `hover` is a segment inside a semantic property
13
+ // name (`--button-outline-hover-surface`), so `var(--hover)` names nothing and
14
+ // the checkers say so.
15
+ //
16
+ // Reads files only. Nothing here may import dist-plugin at module top: CI runs
17
+ // the suite before the plugin is built (see bin/engineLoadsLazily.test.ts).
18
+
19
+ import { existsSync, readFileSync, readdirSync, realpathSync, statSync } from 'node:fs';
20
+ import { dirname, join, resolve } from 'node:path';
21
+ import { fileURLToPath } from 'node:url';
22
+ import { resolveTokensCssPath } from '../migrate.mjs';
23
+
24
+ const PKG_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../..');
25
+
26
+ const SHIPPED_COMPONENTS_DIR = 'src/system/components';
27
+
28
+ /** Families whose names are governed by the token contract (see TOKENS.md). */
29
+ const CONTRACT_FAMILIES = [
30
+ 'surface', 'text', 'border', 'color', 'space', 'radius', 'font', 'line-height',
31
+ 'letter-spacing', 'shadow', 'blur', 'icon-size', 'scrim', 'tint', 'columns',
32
+ 'heading', 'body', 'editorial', 'eyebrow', 'code', 'easing', 'duration', 'zoom',
33
+ 'gradient', 'stroke',
34
+ ];
35
+
36
+ /** True when `name` belongs to a contract-governed family, so a miss is a typo. */
37
+ export function isContractToken(name) {
38
+ const stem = name.replace(/^--/, '');
39
+ return CONTRACT_FAMILIES.some((f) => stem === f || stem.startsWith(`${f}-`));
40
+ }
41
+
42
+ /** Every `--name:` declared anywhere in a stylesheet or style block. */
43
+ export function declaredCustomProperties(css) {
44
+ const out = new Set();
45
+ for (const m of css.matchAll(/(?:^|[;{])\s*(--[a-z0-9-]+)\s*:/gim)) out.add(m[1]);
46
+ return out;
47
+ }
48
+
49
+ /** Every `var(--name)` referenced in a stylesheet or style block. */
50
+ export function referencedCustomProperties(css) {
51
+ const out = new Set();
52
+ for (const m of css.matchAll(/var\(\s*(--[a-z0-9-]+)/g)) out.add(m[1]);
53
+ return out;
54
+ }
55
+
56
+ /**
57
+ * The body of every `:global(:root) { ... }` block, brace-balanced so a nested
58
+ * at-rule or an SCSS block inside it neither truncates the block nor leaks
59
+ * declarations from the rule after it.
60
+ */
61
+ export function extractGlobalRootBlocks(source) {
62
+ const out = [];
63
+ const re = /:global\(:root\)\s*\{/g;
64
+ let m;
65
+ while ((m = re.exec(source)) !== null) {
66
+ const start = m.index + m[0].length;
67
+ let depth = 1;
68
+ let i = start;
69
+ for (; i < source.length && depth > 0; i++) {
70
+ if (source[i] === '{') depth++;
71
+ else if (source[i] === '}') depth--;
72
+ }
73
+ out.push(source.slice(start, depth === 0 ? i - 1 : i));
74
+ re.lastIndex = i;
75
+ }
76
+ return out;
77
+ }
78
+
79
+ const STRING_UNION = /^(?:'[^']*'\s*\|?\s*)+$/;
80
+
81
+ function unionValues(text) {
82
+ return [...text.matchAll(/'([^']*)'/g)].map((m) => m[1]);
83
+ }
84
+
85
+ /**
86
+ * The public props of a component: every name its `interface Props` declares,
87
+ * and for each prop typed as a union of string literals (inline, via a `type`
88
+ * alias, or via `typeof <const array>[number]`), the values it accepts.
89
+ *
90
+ * Shipped components declare their props this way and none spreads a rest
91
+ * object onto the element, so an attribute outside this set is silently
92
+ * dropped at runtime. Returns null when the file declares no `interface Props`.
93
+ */
94
+ export function componentProps(source) {
95
+ const script = source.replace(/<style[^>]*>[\s\S]*?<\/style>/g, '');
96
+ const iface = script.match(/interface\s+Props\b[^{]*\{([\s\S]*?)\n\s*\}/);
97
+ if (!iface) return null;
98
+ const aliases = new Map();
99
+ for (const m of script.matchAll(/\btype\s+(\w+)\s*=\s*([^;]+);/g)) aliases.set(m[1], m[2].trim());
100
+ const arrays = new Map();
101
+ for (const m of script.matchAll(/\bconst\s+(\w+)\s*=\s*\[([\s\S]*?)\]\s*as\s+const/g)) arrays.set(m[1], unionValues(m[2]));
102
+
103
+ const resolveEnum = (type) => {
104
+ const t = type.replace(/\|\s*undefined\b/g, '').replace(/\bundefined\s*\|/g, '').trim();
105
+ if (STRING_UNION.test(t)) return unionValues(t);
106
+ const viaArray = t.match(/^typeof\s+(\w+)\[number\]$/);
107
+ if (viaArray) return arrays.get(viaArray[1]) ?? null;
108
+ if (/^\w+$/.test(t) && aliases.has(t)) return resolveEnum(aliases.get(t));
109
+ return null;
110
+ };
111
+
112
+ const props = new Set();
113
+ const enums = new Map();
114
+ const body = iface[1].replace(/\/\*[\s\S]*?\*\//g, '').replace(/^\s*\/\/.*$/gm, '');
115
+ for (const m of body.matchAll(/^\s*(?:readonly\s+)?(\w+)\??\s*:\s*([^;\n]+)/gm)) {
116
+ props.add(m[1]);
117
+ const values = resolveEnum(m[2]);
118
+ if (values) enums.set(m[1], new Set(values));
119
+ }
120
+ return { props, enums };
121
+ }
122
+
123
+ function walk(dir, exts, out = []) {
124
+ if (!existsSync(dir)) return out;
125
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
126
+ if (entry.name === 'node_modules' || entry.name.startsWith('.') || entry.name.startsWith('__')) continue;
127
+ const full = join(dir, entry.name);
128
+ if (entry.isDirectory()) walk(full, exts, out);
129
+ else if (exts.some((e) => entry.name.endsWith(e))) out.push(full);
130
+ }
131
+ return out;
132
+ }
133
+
134
+ function componentFiles(roots) {
135
+ const seen = new Set();
136
+ const files = [];
137
+ for (const dir of roots) {
138
+ for (const file of walk(dir, ['.svelte'])) {
139
+ if (file.endsWith('Editor.svelte')) continue;
140
+ let key = file;
141
+ try {
142
+ key = realpathSync(file);
143
+ } catch {
144
+ // unreadable link; fall back to the path itself
145
+ }
146
+ if (seen.has(key)) continue;
147
+ seen.add(key);
148
+ files.push(file);
149
+ }
150
+ }
151
+ return files;
152
+ }
153
+
154
+ function registeredIds(root) {
155
+ const ids = new Set();
156
+ for (const file of walk(join(root, 'src'), ['.ts', '.js', '.mjs', '.svelte'])) {
157
+ let src;
158
+ try {
159
+ src = readFileSync(file, 'utf8');
160
+ } catch {
161
+ continue;
162
+ }
163
+ if (!/registerComponent|bootLiveTokens/.test(src)) continue;
164
+ for (const m of src.matchAll(/id\s*:\s*['"]([a-z][a-z0-9]*)['"]/g)) ids.add(m[1]);
165
+ }
166
+ return ids;
167
+ }
168
+
169
+ /**
170
+ * Build the vocabulary for `root` (a consumer project, or this repo).
171
+ *
172
+ * Returns sets of names plus the paths they came from, so a checker can say
173
+ * *which* tokens.css a finding was judged against.
174
+ */
175
+ export function loadVocabulary({ root = process.cwd(), pkgRoot = PKG_ROOT } = {}) {
176
+ const tokensCssPath =
177
+ resolveTokensCssPath(null, null, root) ??
178
+ (existsSync(join(pkgRoot, 'src/system/styles/tokens.css'))
179
+ ? join(pkgRoot, 'src/system/styles/tokens.css')
180
+ : null);
181
+
182
+ const themeTokens = new Set();
183
+ if (tokensCssPath && existsSync(tokensCssPath)) {
184
+ for (const n of declaredCustomProperties(readFileSync(tokensCssPath, 'utf8'))) themeTokens.add(n);
185
+ }
186
+
187
+ const componentTokens = new Set();
188
+ const components = new Map();
189
+ const dirs = [join(pkgRoot, SHIPPED_COMPONENTS_DIR), join(root, SHIPPED_COMPONENTS_DIR)];
190
+ for (const file of componentFiles(dirs)) {
191
+ const Id = file.slice(file.lastIndexOf('/') + 1).replace('.svelte', '');
192
+ const src = readFileSync(file, 'utf8');
193
+ components.set(Id.toLowerCase(), { id: Id.toLowerCase(), name: Id, file, props: componentProps(src) });
194
+ for (const block of extractGlobalRootBlocks(src)) {
195
+ for (const n of declaredCustomProperties(block)) componentTokens.add(n);
196
+ }
197
+ }
198
+ const registered = registeredIds(root);
199
+
200
+ return {
201
+ themeTokens,
202
+ componentTokens,
203
+ components,
204
+ registered,
205
+ tokensCssPath,
206
+ /** True when `name` resolves to something real at runtime. */
207
+ knows(name) {
208
+ return themeTokens.has(name) || componentTokens.has(name);
209
+ },
210
+ };
211
+ }
212
+
213
+ export { PKG_ROOT, walk };
@@ -39,29 +39,74 @@ __export(adjust_exports, {
39
39
  module.exports = __toCommonJS(adjust_exports);
40
40
 
41
41
  // src/editor/core/components/aliasKinds.ts
42
- var KIND_PATTERNS = [
43
- { kind: "font-family", matches: (v) => v.endsWith("-font-family") },
44
- { kind: "font-weight", matches: (v) => v.endsWith("-font-weight") },
45
- { kind: "font-size", matches: (v) => v.endsWith("-font-size") || v.endsWith("-icon-size") || v.endsWith("-thumb-size") },
46
- { kind: "line-height", matches: (v) => v.endsWith("-line-height") },
47
- { kind: "letter-spacing", matches: (v) => v.endsWith("-letter-spacing") },
48
- { kind: "text-color", matches: (v) => v.endsWith("-text") || v.startsWith("--text-") },
49
- { kind: "radius", matches: (v) => v.endsWith("-radius") || v.startsWith("--radius-") },
50
- { kind: "divider-width", matches: (v) => v.endsWith("-divider-width") || v.endsWith("-divider-thickness") },
51
- { kind: "divider-height", matches: (v) => v.endsWith("-divider-height") || v.endsWith("-track-height") },
52
- { kind: "divider-inset", matches: (v) => v.endsWith("-divider-inset") },
53
- { kind: "dot-size", matches: (v) => v.endsWith("-dot-size") },
54
- { kind: "blur", matches: (v) => v.endsWith("-blur") || v.startsWith("--blur-") },
55
- { kind: "scale", matches: (v) => v.endsWith("-scale") || v.startsWith("--scale-") },
56
- { kind: "shadow", matches: (v) => v.endsWith("-shadow") || v.startsWith("--shadow-") },
57
- { kind: "padding", matches: (v) => v.endsWith("-padding") || v.endsWith("-margin") },
58
- { kind: "gap", matches: (v) => v.endsWith("-gap") },
59
- { kind: "duration", matches: (v) => v.endsWith("-duration") || v.startsWith("--duration-") },
60
- { kind: "easing", matches: (v) => v.endsWith("-easing") || v.startsWith("--ease-") },
61
- { kind: "border-width", matches: (v) => v.endsWith("-border-width") || v.endsWith("-accent-width") || v.endsWith("-hairline-thickness") || v.startsWith("--border-width-") },
62
- { kind: "border", matches: (v) => v.endsWith("-border") || v.startsWith("--border-") },
63
- { kind: "surface", matches: (v) => v.endsWith("-surface") || v.startsWith("--surface-") }
42
+ var KIND_RULES = [
43
+ { kind: "font-family", suffix: ["-font-family"] },
44
+ { kind: "font-weight", suffix: ["-font-weight"] },
45
+ { kind: "font-size", suffix: ["-font-size", "-icon-size", "-thumb-size"] },
46
+ { kind: "line-height", suffix: ["-line-height"] },
47
+ { kind: "letter-spacing", suffix: ["-letter-spacing"] },
48
+ // Element-named colour roles: the property *is* the element it paints.
49
+ {
50
+ kind: "text-color",
51
+ suffix: [
52
+ "-text",
53
+ "-label",
54
+ "-icon",
55
+ "-title",
56
+ "-body",
57
+ "-eyebrow",
58
+ "-description",
59
+ "-hint",
60
+ "-error",
61
+ "-placeholder",
62
+ "-value"
63
+ ],
64
+ prefix: ["--text-"]
65
+ },
66
+ { kind: "radius", suffix: ["-radius"], prefix: ["--radius-"] },
67
+ { kind: "divider-width", suffix: ["-divider-width", "-divider-thickness"] },
68
+ { kind: "divider-height", suffix: ["-divider-height", "-track-height"] },
69
+ { kind: "divider-inset", suffix: ["-divider-inset", "-inset"] },
70
+ { kind: "dot-size", suffix: ["-dot-size"] },
71
+ { kind: "blur", suffix: ["-blur"], prefix: ["--blur-"] },
72
+ { kind: "scale", suffix: ["-scale"], prefix: ["--scale-"] },
73
+ { kind: "shadow", suffix: ["-shadow"], prefix: ["--shadow-"] },
74
+ { kind: "padding", suffix: ["-padding", "-margin"] },
75
+ { kind: "gap", suffix: ["-gap"] },
76
+ { kind: "duration", suffix: ["-duration"], prefix: ["--duration-"] },
77
+ { kind: "easing", suffix: ["-easing"], prefix: ["--ease-"] },
78
+ {
79
+ kind: "border-width",
80
+ suffix: ["-border-width", "-accent-width", "-hairline-thickness", "-thickness"],
81
+ prefix: ["--border-width-"]
82
+ },
83
+ { kind: "border", suffix: ["-border"], prefix: ["--border-"] },
84
+ // Fills. A tint is a wash over a surface, so it takes the surface picker: the
85
+ // full palette with an alpha, not just the tint stops it defaults to.
86
+ {
87
+ kind: "surface",
88
+ suffix: [
89
+ "-surface",
90
+ "-fill",
91
+ "-divider",
92
+ "-background",
93
+ "-indicator",
94
+ "-thumb",
95
+ "-accent",
96
+ "-color",
97
+ "-tint",
98
+ "-opacity",
99
+ "-width",
100
+ "-height",
101
+ "-size"
102
+ ],
103
+ prefix: ["--surface-", "--tint", "--color-"]
104
+ }
64
105
  ];
106
+ var KIND_PATTERNS = KIND_RULES.map(({ kind, suffix = [], prefix = [] }) => ({
107
+ kind,
108
+ matches: (v) => suffix.some((s) => v.endsWith(s)) || prefix.some((p) => v.startsWith(p))
109
+ }));
65
110
  var MATCHER_BY_KIND = Object.fromEntries(
66
111
  KIND_PATTERNS.map((p) => [p.kind, p.matches])
67
112
  );
@@ -980,6 +1025,106 @@ var componentMigration_2026_08_15_lineHeightScaleRename = {
980
1025
  apply: renameValues
981
1026
  };
982
1027
 
1028
+ // src/editor/core/themes/migrations/2026-09-01-scrim-rename.ts
1029
+ var RENAMED2 = {
1030
+ "--overlay-low": "--scrim-low",
1031
+ "--overlay": "--scrim",
1032
+ "--overlay-high": "--scrim-high"
1033
+ };
1034
+ var RENAMED_COMPONENT_KEYS = {
1035
+ "--dialog-overlay-surface": "--dialog-scrim-surface"
1036
+ };
1037
+ var colorsAndTypeMigration_2026_09_01_scrimRename = {
1038
+ id: "2026-09-01-scrim-rename-theme",
1039
+ fromVersion: 5,
1040
+ toVersion: 6,
1041
+ appliesTo: "colors-and-type",
1042
+ apply(rawVars) {
1043
+ const out = {};
1044
+ for (const [key, value] of Object.entries(rawVars)) {
1045
+ out[RENAMED2[key] ?? key] = value;
1046
+ }
1047
+ return out;
1048
+ }
1049
+ };
1050
+ var componentMigration_2026_09_01_scrimRename = {
1051
+ id: "2026-09-01-scrim-rename-component",
1052
+ fromVersion: 21,
1053
+ toVersion: 22,
1054
+ appliesTo: "component-config",
1055
+ apply(rawVars) {
1056
+ const out = {};
1057
+ for (const [key, value] of Object.entries(rawVars)) {
1058
+ out[RENAMED_COMPONENT_KEYS[key] ?? key] = RENAMED2[value] ?? value;
1059
+ }
1060
+ return out;
1061
+ }
1062
+ };
1063
+
1064
+ // src/editor/core/themes/migrations/2026-09-01-tint-rename.ts
1065
+ var RENAMED3 = {
1066
+ "--hover-low": "--tint-low",
1067
+ "--hover": "--tint",
1068
+ "--hover-high": "--tint-high"
1069
+ };
1070
+ var colorsAndTypeMigration_2026_09_01_tintRename = {
1071
+ id: "2026-09-01-tint-rename-theme",
1072
+ fromVersion: 6,
1073
+ toVersion: 7,
1074
+ appliesTo: "colors-and-type",
1075
+ apply(rawVars) {
1076
+ const out = {};
1077
+ for (const [key, value] of Object.entries(rawVars)) out[RENAMED3[key] ?? key] = value;
1078
+ return out;
1079
+ }
1080
+ };
1081
+ var componentMigration_2026_09_01_tintRename = {
1082
+ id: "2026-09-01-tint-rename-component",
1083
+ fromVersion: 22,
1084
+ toVersion: 23,
1085
+ appliesTo: "component-config",
1086
+ apply(rawVars) {
1087
+ const out = {};
1088
+ for (const [key, value] of Object.entries(rawVars)) out[key] = RENAMED3[value] ?? value;
1089
+ return out;
1090
+ }
1091
+ };
1092
+
1093
+ // src/editor/core/themes/migrations/2026-09-01-tabbar-active-tint.ts
1094
+ var componentMigration_2026_09_01_tabbarActiveTint = {
1095
+ id: "2026-09-01-tabbar-active-tint",
1096
+ fromVersion: 23,
1097
+ toVersion: 24,
1098
+ appliesTo: "component-config",
1099
+ apply(rawVars, meta) {
1100
+ if (meta.component !== "tabbar") return { ...rawVars };
1101
+ const out = { ...rawVars };
1102
+ if (out["--tabbar-active-surface"] === "--scrim-low") {
1103
+ out["--tabbar-active-surface"] = "--tint-low";
1104
+ }
1105
+ return out;
1106
+ }
1107
+ };
1108
+
1109
+ // src/editor/core/themes/migrations/2026-09-01-gate-suffix-enabled.ts
1110
+ var RENAMED4 = {
1111
+ "--card-hover-border-active": "--card-hover-border-enabled",
1112
+ "--card-hover-shadow-active": "--card-hover-shadow-enabled",
1113
+ "--image-zoom-hover": "--image-zoom-enabled",
1114
+ "--image-grow-hover": "--image-grow-enabled"
1115
+ };
1116
+ var componentMigration_2026_09_01_gateSuffixEnabled = {
1117
+ id: "2026-09-01-gate-suffix-enabled",
1118
+ fromVersion: 24,
1119
+ toVersion: 25,
1120
+ appliesTo: "component-config",
1121
+ apply(rawVars) {
1122
+ const out = {};
1123
+ for (const [key, value] of Object.entries(rawVars)) out[RENAMED4[key] ?? key] = value;
1124
+ return out;
1125
+ }
1126
+ };
1127
+
983
1128
  // src/editor/core/themes/migrations/index.ts
984
1129
  var MIGRATIONS = [
985
1130
  colorsAndTypeMigration_2026_04_24_legacyKeysAndBgToCanvas,
@@ -1007,7 +1152,13 @@ var MIGRATIONS = [
1007
1152
  componentMigration_2026_05_29_toggleDeriveTrackFromThumb,
1008
1153
  colorsAndTypeMigration_2026_08_13_dropLegacyShapeSpaceKeys,
1009
1154
  colorsAndTypeMigration_2026_08_15_lineHeightScaleRename,
1010
- componentMigration_2026_08_15_lineHeightScaleRename
1155
+ componentMigration_2026_08_15_lineHeightScaleRename,
1156
+ colorsAndTypeMigration_2026_09_01_scrimRename,
1157
+ componentMigration_2026_09_01_scrimRename,
1158
+ colorsAndTypeMigration_2026_09_01_tintRename,
1159
+ componentMigration_2026_09_01_tintRename,
1160
+ componentMigration_2026_09_01_tabbarActiveTint,
1161
+ componentMigration_2026_09_01_gateSuffixEnabled
1011
1162
  ];
1012
1163
  function countFor(kind) {
1013
1164
  return MIGRATIONS.filter((m) => m.appliesTo === kind).length;
@@ -1,5 +1,5 @@
1
1
  import { A as AliasDiskValue, a as ComponentConfig } from '../themeTypes-DSV3Zisf.cjs';
2
- export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-DZUzVv8H.cjs';
2
+ export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-bJTCEO4H.cjs';
3
3
  export { C as CURRENT_COMPONENT_SCHEMA_VERSION } from '../index-4N-Orzzi.cjs';
4
4
 
5
5
  type AdjustKind = 'radius' | 'padding' | 'gap' | 'border-width';
@@ -1,5 +1,5 @@
1
1
  import { A as AliasDiskValue, a as ComponentConfig } from '../themeTypes-DSV3Zisf.js';
2
- export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-DZUzVv8H.js';
2
+ export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-bJTCEO4H.js';
3
3
  export { C as CURRENT_COMPONENT_SCHEMA_VERSION } from '../index-4N-Orzzi.js';
4
4
 
5
5
  type AdjustKind = 'radius' | 'padding' | 'gap' | 'border-width';
@@ -1,35 +1,80 @@
1
1
  import {
2
2
  CURRENT_COMPONENT_SCHEMA_VERSION
3
- } from "../chunk-NE6N66EE.js";
3
+ } from "../chunk-GPIBU44G.js";
4
4
  import {
5
5
  readLiveTokensConfig,
6
6
  resolveDataDirs
7
7
  } from "../chunk-RVE3MNKM.js";
8
8
 
9
9
  // src/editor/core/components/aliasKinds.ts
10
- var KIND_PATTERNS = [
11
- { kind: "font-family", matches: (v) => v.endsWith("-font-family") },
12
- { kind: "font-weight", matches: (v) => v.endsWith("-font-weight") },
13
- { kind: "font-size", matches: (v) => v.endsWith("-font-size") || v.endsWith("-icon-size") || v.endsWith("-thumb-size") },
14
- { kind: "line-height", matches: (v) => v.endsWith("-line-height") },
15
- { kind: "letter-spacing", matches: (v) => v.endsWith("-letter-spacing") },
16
- { kind: "text-color", matches: (v) => v.endsWith("-text") || v.startsWith("--text-") },
17
- { kind: "radius", matches: (v) => v.endsWith("-radius") || v.startsWith("--radius-") },
18
- { kind: "divider-width", matches: (v) => v.endsWith("-divider-width") || v.endsWith("-divider-thickness") },
19
- { kind: "divider-height", matches: (v) => v.endsWith("-divider-height") || v.endsWith("-track-height") },
20
- { kind: "divider-inset", matches: (v) => v.endsWith("-divider-inset") },
21
- { kind: "dot-size", matches: (v) => v.endsWith("-dot-size") },
22
- { kind: "blur", matches: (v) => v.endsWith("-blur") || v.startsWith("--blur-") },
23
- { kind: "scale", matches: (v) => v.endsWith("-scale") || v.startsWith("--scale-") },
24
- { kind: "shadow", matches: (v) => v.endsWith("-shadow") || v.startsWith("--shadow-") },
25
- { kind: "padding", matches: (v) => v.endsWith("-padding") || v.endsWith("-margin") },
26
- { kind: "gap", matches: (v) => v.endsWith("-gap") },
27
- { kind: "duration", matches: (v) => v.endsWith("-duration") || v.startsWith("--duration-") },
28
- { kind: "easing", matches: (v) => v.endsWith("-easing") || v.startsWith("--ease-") },
29
- { kind: "border-width", matches: (v) => v.endsWith("-border-width") || v.endsWith("-accent-width") || v.endsWith("-hairline-thickness") || v.startsWith("--border-width-") },
30
- { kind: "border", matches: (v) => v.endsWith("-border") || v.startsWith("--border-") },
31
- { kind: "surface", matches: (v) => v.endsWith("-surface") || v.startsWith("--surface-") }
10
+ var KIND_RULES = [
11
+ { kind: "font-family", suffix: ["-font-family"] },
12
+ { kind: "font-weight", suffix: ["-font-weight"] },
13
+ { kind: "font-size", suffix: ["-font-size", "-icon-size", "-thumb-size"] },
14
+ { kind: "line-height", suffix: ["-line-height"] },
15
+ { kind: "letter-spacing", suffix: ["-letter-spacing"] },
16
+ // Element-named colour roles: the property *is* the element it paints.
17
+ {
18
+ kind: "text-color",
19
+ suffix: [
20
+ "-text",
21
+ "-label",
22
+ "-icon",
23
+ "-title",
24
+ "-body",
25
+ "-eyebrow",
26
+ "-description",
27
+ "-hint",
28
+ "-error",
29
+ "-placeholder",
30
+ "-value"
31
+ ],
32
+ prefix: ["--text-"]
33
+ },
34
+ { kind: "radius", suffix: ["-radius"], prefix: ["--radius-"] },
35
+ { kind: "divider-width", suffix: ["-divider-width", "-divider-thickness"] },
36
+ { kind: "divider-height", suffix: ["-divider-height", "-track-height"] },
37
+ { kind: "divider-inset", suffix: ["-divider-inset", "-inset"] },
38
+ { kind: "dot-size", suffix: ["-dot-size"] },
39
+ { kind: "blur", suffix: ["-blur"], prefix: ["--blur-"] },
40
+ { kind: "scale", suffix: ["-scale"], prefix: ["--scale-"] },
41
+ { kind: "shadow", suffix: ["-shadow"], prefix: ["--shadow-"] },
42
+ { kind: "padding", suffix: ["-padding", "-margin"] },
43
+ { kind: "gap", suffix: ["-gap"] },
44
+ { kind: "duration", suffix: ["-duration"], prefix: ["--duration-"] },
45
+ { kind: "easing", suffix: ["-easing"], prefix: ["--ease-"] },
46
+ {
47
+ kind: "border-width",
48
+ suffix: ["-border-width", "-accent-width", "-hairline-thickness", "-thickness"],
49
+ prefix: ["--border-width-"]
50
+ },
51
+ { kind: "border", suffix: ["-border"], prefix: ["--border-"] },
52
+ // Fills. A tint is a wash over a surface, so it takes the surface picker: the
53
+ // full palette with an alpha, not just the tint stops it defaults to.
54
+ {
55
+ kind: "surface",
56
+ suffix: [
57
+ "-surface",
58
+ "-fill",
59
+ "-divider",
60
+ "-background",
61
+ "-indicator",
62
+ "-thumb",
63
+ "-accent",
64
+ "-color",
65
+ "-tint",
66
+ "-opacity",
67
+ "-width",
68
+ "-height",
69
+ "-size"
70
+ ],
71
+ prefix: ["--surface-", "--tint", "--color-"]
72
+ }
32
73
  ];
74
+ var KIND_PATTERNS = KIND_RULES.map(({ kind, suffix = [], prefix = [] }) => ({
75
+ kind,
76
+ matches: (v) => suffix.some((s) => v.endsWith(s)) || prefix.some((p) => v.startsWith(p))
77
+ }));
33
78
  var MATCHER_BY_KIND = Object.fromEntries(
34
79
  KIND_PATTERNS.map((p) => [p.kind, p.matches])
35
80
  );