@motion-proto/live-tokens 0.71.0 → 0.72.1

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 (70) hide show
  1. package/.claude/skills/live-tokens-adjust-geometry/SKILL.md +1 -1
  2. package/.claude/skills/live-tokens-build-page/SKILL.md +3 -3
  3. package/.claude/skills/live-tokens-check-compliance/SKILL.md +18 -40
  4. package/.claude/skills/live-tokens-create-component/SKILL.md +40 -98
  5. package/.claude/skills/live-tokens-create-component/references/contract-tests.md +99 -0
  6. package/.claude/skills/live-tokens-create-component/references/sketch-mode.md +9 -3
  7. package/.claude/skills/live-tokens-create-component/references/token-naming.md +6 -0
  8. package/.claude/skills/live-tokens-fix-findings/SKILL.md +33 -80
  9. package/.claude/skills/live-tokens-generate-theme/SKILL.md +2 -2
  10. package/.claude/skills/live-tokens-pick-component/SKILL.md +3 -3
  11. package/CHANGELOG.md +109 -0
  12. package/README.md +1 -1
  13. package/bin/check-component.mjs +2 -11
  14. package/bin/check-page.mjs +3 -2
  15. package/bin/cli.mjs +2 -1
  16. package/bin/lib/catalogue.mjs +6 -2
  17. package/bin/lib/findings.mjs +17 -0
  18. package/bin/lib/report.mjs +1 -1
  19. package/bin/lib/tokenVocabulary.mjs +20 -0
  20. package/dist-plugin/adjust/index.cjs +33 -6
  21. package/dist-plugin/adjust/index.d.cts +2 -2
  22. package/dist-plugin/adjust/index.d.ts +2 -2
  23. package/dist-plugin/adjust/index.js +7 -6
  24. package/dist-plugin/{chunk-2YNERPXY.js → chunk-RIXO2E55.js} +1 -1
  25. package/dist-plugin/{chunk-RVE3MNKM.js → chunk-W6Y4BWFB.js} +3 -1
  26. package/dist-plugin/{chunk-GPIBU44G.js → chunk-YLCOIGQC.js} +25 -1
  27. package/dist-plugin/{dataPaths-bJTCEO4H.d.ts → dataPaths-BhWzd5cL.d.cts} +4 -0
  28. package/dist-plugin/{dataPaths-bJTCEO4H.d.cts → dataPaths-BhWzd5cL.d.ts} +4 -0
  29. package/dist-plugin/fontPairing/index.cjs +3 -1
  30. package/dist-plugin/fontPairing/index.d.cts +1 -1
  31. package/dist-plugin/fontPairing/index.d.ts +1 -1
  32. package/dist-plugin/fontPairing/index.js +1 -1
  33. package/dist-plugin/generateColorsAndType/index.cjs +28 -2
  34. package/dist-plugin/generateColorsAndType/index.d.cts +1 -1
  35. package/dist-plugin/generateColorsAndType/index.d.ts +1 -1
  36. package/dist-plugin/generateColorsAndType/index.js +2 -2
  37. package/dist-plugin/index.cjs +28 -2
  38. package/dist-plugin/index.d.cts +1 -1
  39. package/dist-plugin/index.d.ts +1 -1
  40. package/dist-plugin/index.js +3 -3
  41. package/dist-plugin/migrateData/index.cjs +28 -2
  42. package/dist-plugin/migrateData/index.d.cts +1 -1
  43. package/dist-plugin/migrateData/index.d.ts +1 -1
  44. package/dist-plugin/migrateData/index.js +3 -3
  45. package/dist-plugin/tokensCssMigrations/index.cjs +3 -1
  46. package/dist-plugin/tokensCssMigrations/index.d.cts +1 -1
  47. package/dist-plugin/tokensCssMigrations/index.d.ts +1 -1
  48. package/dist-plugin/tokensCssMigrations/index.js +1 -1
  49. package/package.json +5 -1
  50. package/src/editor/component-editor/SectionDividerEditor.svelte +1 -11
  51. package/src/editor/component-editor/contract.ts +175 -0
  52. package/src/editor/component-editor/scaffolding/StateBlock.svelte +0 -8
  53. package/src/editor/component-editor/scaffolding/TokenLayout.svelte +5 -0
  54. package/src/editor/component-editor/scaffolding/TypeEditor.svelte +0 -21
  55. package/src/editor/component-editor/scaffolding/VariantGroup.svelte +2 -2
  56. package/src/editor/component-editor/scaffolding/types.ts +1 -7
  57. package/src/editor/core/components/aliasKinds.ts +6 -2
  58. package/src/editor/core/themes/migrations/2026-09-02-sectiondivider-drop-title-outline.ts +39 -0
  59. package/src/editor/core/themes/migrations/index.ts +2 -0
  60. package/src/live-tokens/data/themes/autumn.json +1 -7
  61. package/src/live-tokens/data/themes/halloween.json +1 -7
  62. package/src/live-tokens/data/themes/midnight-study.json +1 -7
  63. package/src/live-tokens/data/themes/ocean.json +1 -7
  64. package/src/live-tokens/data/themes/royal-velvet.json +1 -7
  65. package/src/live-tokens/data/themes/sketchy.json +1 -7
  66. package/src/live-tokens/data/themes/spring-meadow.json +1 -7
  67. package/src/live-tokens/data/themes/sunset.json +1 -7
  68. package/src/system/components/SectionDivider.svelte +3 -143
  69. package/src/system/components/FloatingTokenTags.css +0 -284
  70. package/src/system/components/FloatingTokenTags.svelte +0 -570
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  CURRENT_COMPONENT_SCHEMA_VERSION,
3
3
  runMigrations
4
- } from "./chunk-GPIBU44G.js";
4
+ } from "./chunk-YLCOIGQC.js";
5
5
 
6
6
  // vite-plugin/files/versionedFileResourceServer.ts
7
7
  import fs from "fs";
@@ -8,7 +8,9 @@ var KNOWN_CONFIG_KEYS = /* @__PURE__ */ new Set([
8
8
  "componentConfigsDir",
9
9
  "themesDir",
10
10
  "manifestsDir",
11
- "tokensCssPath"
11
+ "tokensCssPath",
12
+ "componentDirs",
13
+ "checks"
12
14
  ]);
13
15
  var cached = null;
14
16
  function readLiveTokensConfig() {
@@ -803,6 +803,29 @@ var componentMigration_2026_09_01_gateSuffixEnabled = {
803
803
  }
804
804
  };
805
805
 
806
+ // src/editor/core/themes/migrations/2026-09-02-sectiondivider-drop-title-outline.ts
807
+ var DROPPED2 = new Set(
808
+ ["lg", "md", "sm"].flatMap((v) => [
809
+ `--sectiondivider-${v}-title-outline-width`,
810
+ `--sectiondivider-${v}-title-outline-color`
811
+ ])
812
+ );
813
+ var componentMigration_2026_09_02_sectiondividerDropTitleOutline = {
814
+ id: "2026-09-02-sectiondivider-drop-title-outline",
815
+ fromVersion: 25,
816
+ toVersion: 26,
817
+ appliesTo: "component-config",
818
+ apply(rawVars, meta) {
819
+ if (meta.component !== "sectiondivider") return { ...rawVars };
820
+ const out = {};
821
+ for (const [key, value] of Object.entries(rawVars)) {
822
+ if (DROPPED2.has(key)) continue;
823
+ out[key] = value;
824
+ }
825
+ return out;
826
+ }
827
+ };
828
+
806
829
  // src/editor/core/themes/migrations/index.ts
807
830
  var MIGRATIONS = [
808
831
  colorsAndTypeMigration_2026_04_24_legacyKeysAndBgToCanvas,
@@ -836,7 +859,8 @@ var MIGRATIONS = [
836
859
  colorsAndTypeMigration_2026_09_01_tintRename,
837
860
  componentMigration_2026_09_01_tintRename,
838
861
  componentMigration_2026_09_01_tabbarActiveTint,
839
- componentMigration_2026_09_01_gateSuffixEnabled
862
+ componentMigration_2026_09_01_gateSuffixEnabled,
863
+ componentMigration_2026_09_02_sectiondividerDropTitleOutline
840
864
  ];
841
865
  function countFor(kind) {
842
866
  return MIGRATIONS.filter((m) => m.appliesTo === kind).length;
@@ -16,6 +16,10 @@ interface LiveTokensFileConfig {
16
16
  * migrate` CLI has no plugin options, so it reads this key to locate the file.
17
17
  */
18
18
  tokensCssPath?: string;
19
+ /** Extra directories the component checkers and the registry query discover. */
20
+ componentDirs?: string[];
21
+ /** Checker settings: `rules` per-rule severities, `exclude` paths to skip. */
22
+ checks?: Record<string, unknown>;
19
23
  }
20
24
  interface ResolveDataDirsInput {
21
25
  dataDir?: string;
@@ -16,6 +16,10 @@ interface LiveTokensFileConfig {
16
16
  * migrate` CLI has no plugin options, so it reads this key to locate the file.
17
17
  */
18
18
  tokensCssPath?: string;
19
+ /** Extra directories the component checkers and the registry query discover. */
20
+ componentDirs?: string[];
21
+ /** Checker settings: `rules` per-rule severities, `exclude` paths to skip. */
22
+ checks?: Record<string, unknown>;
19
23
  }
20
24
  interface ResolveDataDirsInput {
21
25
  dataDir?: string;
@@ -382,7 +382,9 @@ var KNOWN_CONFIG_KEYS = /* @__PURE__ */ new Set([
382
382
  "componentConfigsDir",
383
383
  "themesDir",
384
384
  "manifestsDir",
385
- "tokensCssPath"
385
+ "tokensCssPath",
386
+ "componentDirs",
387
+ "checks"
386
388
  ]);
387
389
  var cached = null;
388
390
  function readLiveTokensConfig() {
@@ -1,5 +1,5 @@
1
1
  import { c as FontStackVariable, C as ColorsAndType, b as FontStack, F as FontSource } from '../themeTypes-DSV3Zisf.cjs';
2
- export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-bJTCEO4H.cjs';
2
+ export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-BhWzd5cL.cjs';
3
3
 
4
4
  type PairingSlot = 'display' | 'body' | 'serif' | 'mono' | 'editorial';
5
5
  interface PairingFace {
@@ -1,5 +1,5 @@
1
1
  import { c as FontStackVariable, C as ColorsAndType, b as FontStack, F as FontSource } from '../themeTypes-DSV3Zisf.js';
2
- export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-bJTCEO4H.js';
2
+ export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-BhWzd5cL.js';
3
3
 
4
4
  type PairingSlot = 'display' | 'body' | 'serif' | 'mono' | 'editorial';
5
5
  interface PairingFace {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  readLiveTokensConfig,
3
3
  resolveDataDirs
4
- } from "../chunk-RVE3MNKM.js";
4
+ } from "../chunk-W6Y4BWFB.js";
5
5
 
6
6
  // src/editor/core/fonts/fontParse.ts
7
7
  function parseGoogleFontsUrl(url2) {
@@ -1651,6 +1651,29 @@ var componentMigration_2026_09_01_gateSuffixEnabled = {
1651
1651
  }
1652
1652
  };
1653
1653
 
1654
+ // src/editor/core/themes/migrations/2026-09-02-sectiondivider-drop-title-outline.ts
1655
+ var DROPPED2 = new Set(
1656
+ ["lg", "md", "sm"].flatMap((v) => [
1657
+ `--sectiondivider-${v}-title-outline-width`,
1658
+ `--sectiondivider-${v}-title-outline-color`
1659
+ ])
1660
+ );
1661
+ var componentMigration_2026_09_02_sectiondividerDropTitleOutline = {
1662
+ id: "2026-09-02-sectiondivider-drop-title-outline",
1663
+ fromVersion: 25,
1664
+ toVersion: 26,
1665
+ appliesTo: "component-config",
1666
+ apply(rawVars, meta) {
1667
+ if (meta.component !== "sectiondivider") return { ...rawVars };
1668
+ const out = {};
1669
+ for (const [key, value] of Object.entries(rawVars)) {
1670
+ if (DROPPED2.has(key)) continue;
1671
+ out[key] = value;
1672
+ }
1673
+ return out;
1674
+ }
1675
+ };
1676
+
1654
1677
  // src/editor/core/themes/migrations/index.ts
1655
1678
  var MIGRATIONS = [
1656
1679
  colorsAndTypeMigration_2026_04_24_legacyKeysAndBgToCanvas,
@@ -1684,7 +1707,8 @@ var MIGRATIONS = [
1684
1707
  colorsAndTypeMigration_2026_09_01_tintRename,
1685
1708
  componentMigration_2026_09_01_tintRename,
1686
1709
  componentMigration_2026_09_01_tabbarActiveTint,
1687
- componentMigration_2026_09_01_gateSuffixEnabled
1710
+ componentMigration_2026_09_01_gateSuffixEnabled,
1711
+ componentMigration_2026_09_02_sectiondividerDropTitleOutline
1688
1712
  ];
1689
1713
  function countFor(kind) {
1690
1714
  return MIGRATIONS.filter((m) => m.appliesTo === kind).length;
@@ -1999,7 +2023,9 @@ var KNOWN_CONFIG_KEYS = /* @__PURE__ */ new Set([
1999
2023
  "componentConfigsDir",
2000
2024
  "themesDir",
2001
2025
  "manifestsDir",
2002
- "tokensCssPath"
2026
+ "tokensCssPath",
2027
+ "componentDirs",
2028
+ "checks"
2003
2029
  ]);
2004
2030
  var cached = null;
2005
2031
  function readLiveTokensConfig() {
@@ -1,5 +1,5 @@
1
1
  import { F as FontSource, b as FontStack, G as GradientDiskToken, O as Oklch, H as HarmonyMode, C as ColorsAndType } from '../themeTypes-DSV3Zisf.cjs';
2
- export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-bJTCEO4H.cjs';
2
+ export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-BhWzd5cL.cjs';
3
3
  export { C as CURRENT_COMPONENT_SCHEMA_VERSION } from '../index-4N-Orzzi.cjs';
4
4
 
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  import { F as FontSource, b as FontStack, G as GradientDiskToken, O as Oklch, H as HarmonyMode, C as ColorsAndType } from '../themeTypes-DSV3Zisf.js';
2
- export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-bJTCEO4H.js';
2
+ export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-BhWzd5cL.js';
3
3
  export { C as CURRENT_COMPONENT_SCHEMA_VERSION } from '../index-4N-Orzzi.js';
4
4
 
5
5
  /**
@@ -19,7 +19,7 @@ import {
19
19
  import {
20
20
  CURRENT_COLORS_AND_TYPE_SCHEMA_VERSION,
21
21
  CURRENT_COMPONENT_SCHEMA_VERSION
22
- } from "../chunk-GPIBU44G.js";
22
+ } from "../chunk-YLCOIGQC.js";
23
23
  import {
24
24
  cssColorToOklch,
25
25
  gamutClamp,
@@ -30,7 +30,7 @@ import {
30
30
  import {
31
31
  readLiveTokensConfig,
32
32
  resolveDataDirs
33
- } from "../chunk-RVE3MNKM.js";
33
+ } from "../chunk-W6Y4BWFB.js";
34
34
 
35
35
  // src/editor/core/store/editorCore.ts
36
36
  import { writable, derived, get } from "svelte/store";
@@ -1587,6 +1587,29 @@ var componentMigration_2026_09_01_gateSuffixEnabled = {
1587
1587
  }
1588
1588
  };
1589
1589
 
1590
+ // src/editor/core/themes/migrations/2026-09-02-sectiondivider-drop-title-outline.ts
1591
+ var DROPPED2 = new Set(
1592
+ ["lg", "md", "sm"].flatMap((v) => [
1593
+ `--sectiondivider-${v}-title-outline-width`,
1594
+ `--sectiondivider-${v}-title-outline-color`
1595
+ ])
1596
+ );
1597
+ var componentMigration_2026_09_02_sectiondividerDropTitleOutline = {
1598
+ id: "2026-09-02-sectiondivider-drop-title-outline",
1599
+ fromVersion: 25,
1600
+ toVersion: 26,
1601
+ appliesTo: "component-config",
1602
+ apply(rawVars, meta) {
1603
+ if (meta.component !== "sectiondivider") return { ...rawVars };
1604
+ const out = {};
1605
+ for (const [key, value] of Object.entries(rawVars)) {
1606
+ if (DROPPED2.has(key)) continue;
1607
+ out[key] = value;
1608
+ }
1609
+ return out;
1610
+ }
1611
+ };
1612
+
1590
1613
  // src/editor/core/themes/migrations/index.ts
1591
1614
  var MIGRATIONS = [
1592
1615
  colorsAndTypeMigration_2026_04_24_legacyKeysAndBgToCanvas,
@@ -1620,7 +1643,8 @@ var MIGRATIONS = [
1620
1643
  colorsAndTypeMigration_2026_09_01_tintRename,
1621
1644
  componentMigration_2026_09_01_tintRename,
1622
1645
  componentMigration_2026_09_01_tabbarActiveTint,
1623
- componentMigration_2026_09_01_gateSuffixEnabled
1646
+ componentMigration_2026_09_01_gateSuffixEnabled,
1647
+ componentMigration_2026_09_02_sectiondividerDropTitleOutline
1624
1648
  ];
1625
1649
  function countFor(kind) {
1626
1650
  return MIGRATIONS.filter((m) => m.appliesTo === kind).length;
@@ -2601,7 +2625,9 @@ var KNOWN_CONFIG_KEYS = /* @__PURE__ */ new Set([
2601
2625
  "componentConfigsDir",
2602
2626
  "themesDir",
2603
2627
  "manifestsDir",
2604
- "tokensCssPath"
2628
+ "tokensCssPath",
2629
+ "componentDirs",
2630
+ "checks"
2605
2631
  ]);
2606
2632
  var cached = null;
2607
2633
  function readLiveTokensConfig() {
@@ -1,6 +1,6 @@
1
1
  import { Plugin } from 'vite';
2
2
  export { ComponentSource, MissingToken, RunResult, TOKENS_CSS_MIGRATIONS, TokensCssMigration, ValidateInput, runTokensCssMigrations, validateTokensCss } from './tokensCssMigrations/index.cjs';
3
- import './dataPaths-bJTCEO4H.cjs';
3
+ import './dataPaths-BhWzd5cL.cjs';
4
4
 
5
5
  interface ThemeFileApiOptions {
6
6
  tokensCssPath: string;
@@ -1,6 +1,6 @@
1
1
  import { Plugin } from 'vite';
2
2
  export { ComponentSource, MissingToken, RunResult, TOKENS_CSS_MIGRATIONS, TokensCssMigration, ValidateInput, runTokensCssMigrations, validateTokensCss } from './tokensCssMigrations/index.js';
3
- import './dataPaths-bJTCEO4H.js';
3
+ import './dataPaths-BhWzd5cL.js';
4
4
 
5
5
  interface ThemeFileApiOptions {
6
6
  tokensCssPath: string;
@@ -13,10 +13,10 @@ import {
13
13
  nextAvailableName,
14
14
  normalizeTheme,
15
15
  versionedFileResourceServer
16
- } from "./chunk-2YNERPXY.js";
16
+ } from "./chunk-RIXO2E55.js";
17
17
  import {
18
18
  CURRENT_COMPONENT_SCHEMA_VERSION
19
- } from "./chunk-GPIBU44G.js";
19
+ } from "./chunk-YLCOIGQC.js";
20
20
  import {
21
21
  TOKENS_CSS_MIGRATIONS,
22
22
  extractGlobalRootBody,
@@ -31,7 +31,7 @@ import {
31
31
  } from "./chunk-7TQQTHI6.js";
32
32
  import {
33
33
  resolveDataDirs
34
- } from "./chunk-RVE3MNKM.js";
34
+ } from "./chunk-W6Y4BWFB.js";
35
35
 
36
36
  // vite-plugin/themeFileApi.ts
37
37
  import fs from "fs";
@@ -976,6 +976,29 @@ var componentMigration_2026_09_01_gateSuffixEnabled = {
976
976
  }
977
977
  };
978
978
 
979
+ // src/editor/core/themes/migrations/2026-09-02-sectiondivider-drop-title-outline.ts
980
+ var DROPPED2 = new Set(
981
+ ["lg", "md", "sm"].flatMap((v) => [
982
+ `--sectiondivider-${v}-title-outline-width`,
983
+ `--sectiondivider-${v}-title-outline-color`
984
+ ])
985
+ );
986
+ var componentMigration_2026_09_02_sectiondividerDropTitleOutline = {
987
+ id: "2026-09-02-sectiondivider-drop-title-outline",
988
+ fromVersion: 25,
989
+ toVersion: 26,
990
+ appliesTo: "component-config",
991
+ apply(rawVars, meta) {
992
+ if (meta.component !== "sectiondivider") return { ...rawVars };
993
+ const out = {};
994
+ for (const [key, value] of Object.entries(rawVars)) {
995
+ if (DROPPED2.has(key)) continue;
996
+ out[key] = value;
997
+ }
998
+ return out;
999
+ }
1000
+ };
1001
+
979
1002
  // src/editor/core/themes/migrations/index.ts
980
1003
  var MIGRATIONS = [
981
1004
  colorsAndTypeMigration_2026_04_24_legacyKeysAndBgToCanvas,
@@ -1009,7 +1032,8 @@ var MIGRATIONS = [
1009
1032
  colorsAndTypeMigration_2026_09_01_tintRename,
1010
1033
  componentMigration_2026_09_01_tintRename,
1011
1034
  componentMigration_2026_09_01_tabbarActiveTint,
1012
- componentMigration_2026_09_01_gateSuffixEnabled
1035
+ componentMigration_2026_09_01_gateSuffixEnabled,
1036
+ componentMigration_2026_09_02_sectiondividerDropTitleOutline
1013
1037
  ];
1014
1038
  function countFor(kind) {
1015
1039
  return MIGRATIONS.filter((m) => m.appliesTo === kind).length;
@@ -2178,7 +2202,9 @@ var KNOWN_CONFIG_KEYS = /* @__PURE__ */ new Set([
2178
2202
  "componentConfigsDir",
2179
2203
  "themesDir",
2180
2204
  "manifestsDir",
2181
- "tokensCssPath"
2205
+ "tokensCssPath",
2206
+ "componentDirs",
2207
+ "checks"
2182
2208
  ]);
2183
2209
  var cached = null;
2184
2210
  function readLiveTokensConfig() {
@@ -1,4 +1,4 @@
1
- export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-bJTCEO4H.cjs';
1
+ export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-BhWzd5cL.cjs';
2
2
 
3
3
  interface LegacyRename {
4
4
  from: string;
@@ -1,4 +1,4 @@
1
- export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-bJTCEO4H.js';
1
+ export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-BhWzd5cL.js';
2
2
 
3
3
  interface LegacyRename {
4
4
  from: string;
@@ -7,14 +7,14 @@ import {
7
7
  normalizeTheme,
8
8
  planLegacyRenames,
9
9
  versionedFileResourceServer
10
- } from "../chunk-2YNERPXY.js";
10
+ } from "../chunk-RIXO2E55.js";
11
11
  import {
12
12
  CURRENT_COMPONENT_SCHEMA_VERSION
13
- } from "../chunk-GPIBU44G.js";
13
+ } from "../chunk-YLCOIGQC.js";
14
14
  import {
15
15
  readLiveTokensConfig,
16
16
  resolveDataDirs
17
- } from "../chunk-RVE3MNKM.js";
17
+ } from "../chunk-W6Y4BWFB.js";
18
18
 
19
19
  // vite-plugin/migrateData/migrateData.ts
20
20
  import fs from "fs";
@@ -648,7 +648,9 @@ var KNOWN_CONFIG_KEYS = /* @__PURE__ */ new Set([
648
648
  "componentConfigsDir",
649
649
  "themesDir",
650
650
  "manifestsDir",
651
- "tokensCssPath"
651
+ "tokensCssPath",
652
+ "componentDirs",
653
+ "checks"
652
654
  ]);
653
655
  var cached = null;
654
656
  function readLiveTokensConfig() {
@@ -1,4 +1,4 @@
1
- export { r as readLiveTokensConfig } from '../dataPaths-bJTCEO4H.cjs';
1
+ export { r as readLiveTokensConfig } from '../dataPaths-BhWzd5cL.cjs';
2
2
 
3
3
  /**
4
4
  * A `tokens-css` migration: a pure, idempotent transform on the text of a
@@ -1,4 +1,4 @@
1
- export { r as readLiveTokensConfig } from '../dataPaths-bJTCEO4H.js';
1
+ export { r as readLiveTokensConfig } from '../dataPaths-BhWzd5cL.js';
2
2
 
3
3
  /**
4
4
  * A `tokens-css` migration: a pure, idempotent transform on the text of a
@@ -17,7 +17,7 @@ import {
17
17
  import "../chunk-7TQQTHI6.js";
18
18
  import {
19
19
  readLiveTokensConfig
20
- } from "../chunk-RVE3MNKM.js";
20
+ } from "../chunk-W6Y4BWFB.js";
21
21
  export {
22
22
  TOKENS_CSS_MIGRATIONS,
23
23
  collectDefinedTokens,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@motion-proto/live-tokens",
3
- "version": "0.71.0",
3
+ "version": "0.72.1",
4
4
  "type": "module",
5
5
  "description": "Design token editor with live CSS variable editing. Svelte 5 + Vite 8.",
6
6
  "keywords": [
@@ -72,6 +72,10 @@
72
72
  "types": "./src/editor/component-editor/index.ts",
73
73
  "default": "./src/editor/component-editor/index.ts"
74
74
  },
75
+ "./component-editor/contract": {
76
+ "types": "./src/editor/component-editor/contract.ts",
77
+ "default": "./src/editor/component-editor/contract.ts"
78
+ },
75
79
  "./ui": {
76
80
  "svelte": "./src/editor/ui/index.ts",
77
81
  "types": "./src/editor/ui/index.ts",
@@ -36,25 +36,18 @@
36
36
  { label: 'hairline thickness', canBeLinked: true, groupKey: 'hairline-thickness', variable: `--sectiondivider-${v}-hairline-thickness`, element: 'hairline' },
37
37
  ];
38
38
  }
39
- function titleOutlineTokens(v: Variant): Token[] {
40
- return [
41
- { label: 'outline thickness', canBeLinked: true, groupKey: 'title-outline-width', variable: `--sectiondivider-${v}-title-outline-width`, element: 'title' },
42
- { label: 'outline color', canBeLinked: true, groupKey: 'title-outline-color', variable: `--sectiondivider-${v}-title-outline-color`, element: 'title' },
43
- ];
44
- }
45
39
  function backgroundTokens(v: Variant): Token[] {
46
40
  return [
47
41
  { label: 'background', groupKey: 'background', variable: `--sectiondivider-${v}-background`, kind: 'gradient', family: variants.find((x) => x.key === v)!.family },
48
42
  ];
49
43
  }
50
44
  function variantTokens(v: Variant): Token[] {
51
- return [...containerTokens(v), ...hairlineTokens(v), ...titleOutlineTokens(v), ...backgroundTokens(v), ...typePaddingTokens(v)];
45
+ return [...containerTokens(v), ...hairlineTokens(v), ...backgroundTokens(v), ...typePaddingTokens(v)];
52
46
  }
53
47
  function stateTokens(v: Variant): Token[] {
54
48
  return [
55
49
  ...containerTokens(v),
56
50
  ...hairlineTokens(v),
57
- ...titleOutlineTokens(v).map((t) => ({ ...t, hidden: true })),
58
51
  ...backgroundTokens(v).map((t) => ({ ...t, hidden: true })),
59
52
  ...typePaddingTokens(v),
60
53
  ];
@@ -72,8 +65,6 @@
72
65
  weightVariable: `--sectiondivider-${v}-title-font-weight`,
73
66
  lineHeightVariable: `--sectiondivider-${v}-title-line-height`,
74
67
  letterSpacingVariable: `--sectiondivider-${v}-title-letter-spacing`,
75
- outlineWidthVariable: `--sectiondivider-${v}-title-outline-width`,
76
- outlineColorVariable: `--sectiondivider-${v}-title-outline-color`,
77
68
  },
78
69
  {
79
70
  legend: '',
@@ -127,7 +118,6 @@
127
118
  const LINKED_GROUP_KEYS = [
128
119
  'container-padding', 'radius', 'border', 'border-width', 'shadow',
129
120
  'hairline-color', 'hairline-thickness',
130
- 'title-outline-width', 'title-outline-color',
131
121
  'title-color', 'description-color', 'eyebrow-color',
132
122
  'title-padding', 'description-padding', 'eyebrow-padding',
133
123
  'title-font-family', 'title-font-weight', 'title-line-height', 'title-letter-spacing',
@@ -0,0 +1,175 @@
1
+ /**
2
+ * The registry contract, as a function a project outside this package can run.
3
+ *
4
+ * Node-only: it reads the runtime `.svelte` file and the component's
5
+ * `default.json` off disk, so it lives behind its own subpath export
6
+ * (`@motion-proto/live-tokens/component-editor/contract`) rather than in the
7
+ * browser barrel. A consumer's whole suite is a `describe.each` over their own
8
+ * registrations and one call:
9
+ *
10
+ * ```ts
11
+ * // @vitest-environment happy-dom
12
+ * import { describe, it, expect } from 'vitest';
13
+ * import { getComponentRegistryEntries, registerComponent } from '@motion-proto/live-tokens';
14
+ * import { checkRegistryEntry } from '@motion-proto/live-tokens/component-editor/contract';
15
+ * import MyWidgetEditor, { allTokens } from '../src/system/components/MyWidgetEditor.svelte';
16
+ *
17
+ * registerComponent({ id: 'mywidget', label: 'My Widget', icon: 'fas fa-magic',
18
+ * sourceFile: 'src/system/components/MyWidget.svelte',
19
+ * editorComponent: MyWidgetEditor, schema: allTokens });
20
+ *
21
+ * const mine = getComponentRegistryEntries().filter((e) => e.origin === 'custom');
22
+ *
23
+ * describe.each(mine.map((e) => [e.id, e] as const))('%s', (_id, entry) => {
24
+ * it('meets the registry contract', () => {
25
+ * expect(checkRegistryEntry(entry)).toEqual([]);
26
+ * });
27
+ * });
28
+ * ```
29
+ *
30
+ * The `origin` filter is load-bearing outside this package: the registry always
31
+ * carries the shipped components too, and their `sourceFile` paths are relative
32
+ * to the package root, not the consumer's.
33
+ */
34
+ import { readFileSync, existsSync } from 'node:fs';
35
+ import path from 'node:path';
36
+ import { get } from 'svelte/store';
37
+ import type { RegistryEntry } from './registry';
38
+ import type { Token } from './scaffolding/types';
39
+ import { parseColorOpacity } from '../core/themes/parsers/colorOpacity';
40
+ import { editorState, setComponentAlias, clearComponentAlias } from '../core/store/editorStore';
41
+
42
+ export interface RegistryContractOptions {
43
+ /** Root that `entry.sourceFile` is relative to. Defaults to `process.cwd()`,
44
+ which is the project root under both vitest and `npm test`. */
45
+ projectRoot?: string;
46
+ /** Directory holding `<id>/default.json`. Defaults to
47
+ `<projectRoot>/src/live-tokens/data/component-configs`. Pass the
48
+ `componentConfigsDir` from `live-tokens.config.json` when a project moved it. */
49
+ componentConfigsDir?: string;
50
+ }
51
+
52
+ const PADDING_SIDE_RE = /-padding-(top|right|bottom|left)$/;
53
+ const PROBE = { kind: 'token', name: '--space-8' } as const;
54
+
55
+ /**
56
+ * Tokens excluded from the runtime-declaration and default-seed checks:
57
+ * - `hidden: true` (vestigial or hidden by design),
58
+ * - `kind: 'gradient'` (structured payloads, stored as gradient objects, not vars),
59
+ * - `-padding-(top|right|bottom|left)` (written on demand by the split-padding
60
+ * UI and consumed through the `themed-padding` mixin's fallback chain, so
61
+ * they exist as neither `:root` declarations nor default seeds).
62
+ */
63
+ function isEditableSurfaceToken(t: Token): boolean {
64
+ if (t.hidden) return false;
65
+ if (t.kind === 'gradient') return false;
66
+ if (PADDING_SIDE_RE.test(t.variable)) return false;
67
+ return true;
68
+ }
69
+
70
+ /** Every `--xxx:` declaration in every `<style>` block of a Svelte file. */
71
+ function extractRuntimeDeclarations(source: string): Set<string> {
72
+ const out = new Set<string>();
73
+ const blocks = [...source.matchAll(/<style[^>]*>([\s\S]*?)<\/style>/g)].map((m) => m[1]);
74
+ for (const block of blocks) {
75
+ for (const m of block.matchAll(/(?:^|[{;\n])\s*(--[a-z0-9-]+)\s*:/g)) {
76
+ out.add(m[1]);
77
+ }
78
+ }
79
+ return out;
80
+ }
81
+
82
+ /** Opacity a seeded alias resolves to. A plain token alias is fully opaque; a
83
+ gradient payload or `transparent` carries no guarantee, so it reads as 0. */
84
+ function seededOpacity(raw: unknown): number {
85
+ if (typeof raw !== 'string' || raw === 'transparent') return 0;
86
+ return parseColorOpacity(raw)?.opacity ?? 100;
87
+ }
88
+
89
+ /**
90
+ * Run the registry contract against one entry and return a violation line per
91
+ * failure. An empty array is the pass.
92
+ *
93
+ * The contract:
94
+ * 1. Registration — `sourceFile` resolves to a real file, the schema is non-empty.
95
+ * 2. Uniqueness — no schema variable is declared twice.
96
+ * 3. Editor ↔ runtime — every editable token's CSS var is declared in the
97
+ * runtime's `<style>` block, so an edit has something to repaint.
98
+ * 4. Editor ↔ default config — every editable token has a seed alias in
99
+ * `<id>/default.json`, so a consumer adopts with full defaults. A component
100
+ * with no `default.json` is editor-only; the seed and floor checks skip it.
101
+ * 5. Opacity floors — a token declaring `minOpacity` ships a default at or
102
+ * above it, so a floating panel starts out legible over page content.
103
+ * 6. Round-trip — `setComponentAlias` persists into the slice under the same key.
104
+ */
105
+ export function checkRegistryEntry(
106
+ entry: RegistryEntry,
107
+ options: RegistryContractOptions = {},
108
+ ): string[] {
109
+ const projectRoot = options.projectRoot ?? process.cwd();
110
+ const configsDir =
111
+ options.componentConfigsDir ??
112
+ path.resolve(projectRoot, 'src/live-tokens/data/component-configs');
113
+
114
+ const violations: string[] = [];
115
+ const schema = entry.schema ?? [];
116
+ const runtimePath = path.resolve(projectRoot, entry.sourceFile);
117
+
118
+ if (schema.length === 0) violations.push('registration: schema is empty');
119
+ if (!existsSync(runtimePath)) {
120
+ violations.push(`registration: sourceFile does not resolve to a file (${runtimePath})`);
121
+ }
122
+
123
+ const seen = new Set<string>();
124
+ for (const t of schema) {
125
+ if (seen.has(t.variable)) violations.push(`uniqueness: ${t.variable} is declared twice`);
126
+ seen.add(t.variable);
127
+ }
128
+
129
+ const editable = schema.filter(isEditableSurfaceToken);
130
+
131
+ if (existsSync(runtimePath)) {
132
+ const runtimeVars = extractRuntimeDeclarations(readFileSync(runtimePath, 'utf-8'));
133
+ for (const t of editable) {
134
+ if (!runtimeVars.has(t.variable)) {
135
+ violations.push(`runtime: ${t.variable} is not declared in ${entry.sourceFile}`);
136
+ }
137
+ }
138
+ }
139
+
140
+ const configPath = path.join(configsDir, entry.id, 'default.json');
141
+ if (existsSync(configPath)) {
142
+ const config = JSON.parse(readFileSync(configPath, 'utf-8')) as {
143
+ aliases?: Record<string, unknown>;
144
+ };
145
+ const aliases = config.aliases ?? {};
146
+ for (const t of editable) {
147
+ if (!(t.variable in aliases)) {
148
+ violations.push(`default config: ${t.variable} has no seed in ${entry.id}/default.json`);
149
+ }
150
+ }
151
+ for (const t of schema) {
152
+ if (t.minOpacity === undefined) continue;
153
+ const opacity = seededOpacity(aliases[t.variable]);
154
+ if (opacity < t.minOpacity) {
155
+ violations.push(
156
+ `opacity floor: ${t.variable} seeds at ${opacity}%, below its ${t.minOpacity}% floor`,
157
+ );
158
+ }
159
+ }
160
+ }
161
+
162
+ const sample = editable[0];
163
+ if (sample) {
164
+ setComponentAlias(entry.id, sample.variable, PROBE);
165
+ const stored = get(editorState).components[entry.id]?.aliases?.[sample.variable];
166
+ if (JSON.stringify(stored) !== JSON.stringify(PROBE)) {
167
+ violations.push(
168
+ `round-trip: setComponentAlias(${entry.id}, ${sample.variable}) stored ${JSON.stringify(stored)}`,
169
+ );
170
+ }
171
+ clearComponentAlias(entry.id, sample.variable);
172
+ }
173
+
174
+ return violations;
175
+ }