@motion-proto/live-tokens 0.78.0 → 0.80.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 (172) hide show
  1. package/.claude/skills/live-tokens-check-compliance/SKILL.md +49 -38
  2. package/.claude/skills/live-tokens-create-component/SKILL.md +23 -28
  3. package/.claude/skills/live-tokens-create-component/references/contract-tests.md +61 -0
  4. package/.claude/skills/live-tokens-create-component/references/sketch-mode.md +2 -2
  5. package/.claude/skills/live-tokens-create-component/references/token-naming.md +6 -15
  6. package/.claude/skills/live-tokens-create-page/SKILL.md +6 -4
  7. package/.claude/skills/live-tokens-create-theme/references/design-directions.md +1 -1
  8. package/.claude/skills/live-tokens-pick-component/SKILL.md +3 -3
  9. package/.claude/skills/live-tokens-set-colors/references/color-anchors.md +1 -1
  10. package/.claude/skills/live-tokens-set-geometry/SKILL.md +1 -1
  11. package/.claude/skills/live-tokens-set-geometry/references/geometry-anchors.md +1 -1
  12. package/CHANGELOG.md +271 -0
  13. package/README.md +10 -16
  14. package/bin/check-component.mjs +154 -551
  15. package/bin/check-page.mjs +57 -541
  16. package/bin/cli.mjs +93 -16
  17. package/bin/contractRunner.mjs +37 -91
  18. package/bin/lib/buildChecks.mjs +32 -0
  19. package/bin/lib/catalogue.mjs +161 -34
  20. package/bin/lib/componentSource.mjs +152 -0
  21. package/bin/lib/cssValues.mjs +9 -0
  22. package/bin/lib/dataDir.mjs +126 -0
  23. package/bin/lib/findings.mjs +103 -12
  24. package/bin/lib/fixers.mjs +64 -0
  25. package/bin/lib/geometry.mjs +92 -0
  26. package/bin/lib/pageSource.mjs +230 -0
  27. package/bin/lib/report.mjs +57 -59
  28. package/bin/lib/tokenVocabulary.mjs +104 -34
  29. package/bin/migrate-build-script.mjs +66 -0
  30. package/bin/migrate.mjs +5 -0
  31. package/bin/rules/componentStructure.mjs +344 -0
  32. package/bin/rules/componentUse.mjs +313 -0
  33. package/bin/rules/importsAndRoutes.mjs +136 -0
  34. package/bin/rules/testRuns.mjs +122 -0
  35. package/bin/rules/tokens.mjs +426 -0
  36. package/bin/setup-claude.mjs +1 -2
  37. package/dist-plugin/{chunk-PDNL4NC5.js → chunk-D4WRIKEZ.js} +7 -2
  38. package/dist-plugin/{chunk-SWXRVZKT.js → chunk-REBHE3ZM.js} +414 -1
  39. package/dist-plugin/index.cjs +470 -19
  40. package/dist-plugin/index.d.cts +1 -0
  41. package/dist-plugin/index.d.ts +1 -0
  42. package/dist-plugin/index.js +87 -55
  43. package/dist-plugin/migrateData/index.cjs +422 -4
  44. package/dist-plugin/migrateData/index.js +2 -2
  45. package/dist-plugin/setColors/index.cjs +414 -1
  46. package/dist-plugin/setColors/index.d.cts +1 -1
  47. package/dist-plugin/setColors/index.d.ts +1 -1
  48. package/dist-plugin/setColors/index.js +1 -1
  49. package/dist-plugin/setGeometry/index.cjs +423 -13
  50. package/dist-plugin/setGeometry/index.d.cts +3 -3
  51. package/dist-plugin/setGeometry/index.d.ts +3 -3
  52. package/dist-plugin/setGeometry/index.js +10 -13
  53. package/dist-plugin/setType/index.d.cts +1 -1
  54. package/dist-plugin/setType/index.d.ts +1 -1
  55. package/dist-plugin/{themeTypes-BxRtuN5V.d.cts → themeTypes-B8_Idrp4.d.cts} +2 -2
  56. package/dist-plugin/{themeTypes-BxRtuN5V.d.ts → themeTypes-B8_Idrp4.d.ts} +2 -2
  57. package/package.json +2 -2
  58. package/src/editor/component-editor/CalloutEditor.svelte +2 -2
  59. package/src/editor/component-editor/CollapsibleSectionEditor.svelte +14 -15
  60. package/src/editor/component-editor/CornerBadgeEditor.svelte +14 -14
  61. package/src/editor/component-editor/DialogEditor.svelte +5 -5
  62. package/src/editor/component-editor/InlineEditActionsEditor.svelte +2 -2
  63. package/src/editor/component-editor/RadioButtonEditor.svelte +21 -21
  64. package/src/editor/component-editor/SectionDividerEditor.svelte +7 -7
  65. package/src/editor/component-editor/SegmentedControlEditor.svelte +5 -5
  66. package/src/editor/component-editor/SideNavigationEditor.svelte +25 -25
  67. package/src/editor/component-editor/TabBarEditor.svelte +6 -6
  68. package/src/editor/component-editor/TableEditor.svelte +6 -6
  69. package/src/editor/component-editor/ToggleEditor.svelte +2 -2
  70. package/src/editor/component-editor/index.ts +3 -0
  71. package/src/editor/component-editor/registry.ts +57 -1
  72. package/src/editor/component-editor/scaffolding/TokenLayout.svelte +14 -14
  73. package/src/editor/component-editor/scaffolding/VariantGroup.svelte +3 -0
  74. package/src/editor/component-editor/scaffolding/types.ts +15 -0
  75. package/src/editor/core/components/adjustAliases.ts +4 -4
  76. package/src/editor/core/components/aliasKinds.ts +20 -19
  77. package/src/editor/core/sketch/sketchLayer.ts +3 -3
  78. package/src/editor/core/themes/migrateComponentConfig.ts +14 -6
  79. package/src/editor/core/themes/migrations/2026-09-13-badge-brand.ts +42 -0
  80. package/src/editor/core/themes/migrations/2026-09-13-collapsiblesection-open.ts +33 -0
  81. package/src/editor/core/themes/migrations/2026-09-13-cornerbadge-prefix.ts +70 -0
  82. package/src/editor/core/themes/migrations/2026-09-13-hairline.ts +92 -0
  83. package/src/editor/core/themes/migrations/2026-09-13-indicator.ts +54 -0
  84. package/src/editor/core/themes/migrations/2026-09-13-sectiondivider-surface.ts +36 -0
  85. package/src/editor/core/themes/migrations/2026-09-13-selected-state.ts +124 -0
  86. package/src/editor/core/themes/migrations/2026-09-13-toggle-label.ts +31 -0
  87. package/src/editor/core/themes/migrations/index.ts +16 -0
  88. package/src/editor/core/themes/themeService.ts +3 -3
  89. package/src/editor/core/themes/themeTypes.ts +13 -15
  90. package/src/editor/docs/Docs.svelte +1 -1
  91. package/src/editor/docs/content/light-and-dark.md +3 -3
  92. package/src/editor/docs/content.generated.ts +1 -1
  93. package/src/editor/index.ts +1 -0
  94. package/src/editor/overlay/LiveEditorOverlay.svelte +15 -0
  95. package/src/editor/skill-atlas/SkillAtlas.svelte +4 -4
  96. package/src/editor/skill-atlas/TreeNodeCard.svelte +4 -4
  97. package/src/editor/skill-atlas/skillSources.generated.ts +11 -14
  98. package/src/editor/skill-atlas/skillTrees.ts +1 -3
  99. package/src/editor/skill-atlas/trees/check-compliance.ts +37 -149
  100. package/src/editor/skill-atlas/trees/create-component.ts +62 -64
  101. package/src/editor/skill-atlas/trees/create-page.ts +38 -17
  102. package/src/editor/skill-atlas/trees/pick-component.ts +3 -3
  103. package/src/editor/skill-atlas/trees/set-geometry.ts +1 -1
  104. package/src/editor/ui/UIPaletteSelector.svelte +11 -15
  105. package/src/editor/ui/variantScales.ts +8 -8
  106. package/src/live-tokens/data/themes/autumn.json +188 -188
  107. package/src/live-tokens/data/themes/halloween.json +188 -188
  108. package/src/live-tokens/data/themes/midnight-study.json +245 -245
  109. package/src/live-tokens/data/themes/ocean.json +188 -188
  110. package/src/live-tokens/data/themes/royal-velvet.json +188 -188
  111. package/src/live-tokens/data/themes/sketchy.json +188 -188
  112. package/src/live-tokens/data/themes/spring-meadow.json +188 -188
  113. package/src/live-tokens/data/themes/sunset.json +188 -188
  114. package/src/system/components/Badge.svelte +27 -23
  115. package/src/system/components/Button.svelte +13 -7
  116. package/src/system/components/Callout.svelte +16 -11
  117. package/src/system/components/Card.svelte +22 -15
  118. package/src/system/components/CodeSnippet.svelte +10 -6
  119. package/src/system/components/CollapsibleSection.svelte +81 -76
  120. package/src/system/components/CornerBadge.svelte +78 -72
  121. package/src/system/components/Dialog.svelte +21 -18
  122. package/src/system/components/IconButton.svelte +13 -9
  123. package/src/system/components/Image.svelte +14 -8
  124. package/src/system/components/ImageLightbox.svelte +10 -6
  125. package/src/system/components/InlineEditActions.svelte +17 -14
  126. package/src/system/components/Input.svelte +13 -7
  127. package/src/system/components/MenuSelect.svelte +13 -7
  128. package/src/system/components/Notification.svelte +17 -11
  129. package/src/system/components/Panel.svelte +13 -6
  130. package/src/system/components/ProgressBar.svelte +10 -5
  131. package/src/system/components/RadioButton.svelte +33 -30
  132. package/src/system/components/SectionDivider.svelte +28 -21
  133. package/src/system/components/SegmentedControl.svelte +27 -23
  134. package/src/system/components/SideNavigation.svelte +175 -171
  135. package/src/system/components/Slider.svelte +11 -7
  136. package/src/system/components/TabBar.svelte +53 -49
  137. package/src/system/components/Table.svelte +20 -15
  138. package/src/system/components/Toggle.svelte +14 -10
  139. package/src/system/components/Tooltip.svelte +10 -6
  140. package/src/system/styles/CONVENTIONS.md +3 -4
  141. package/src/testing-js/chunk-3UKGXCDL.js +48 -0
  142. package/src/testing-js/chunk-3UKGXCDL.js.map +1 -0
  143. package/src/testing-js/{chunk-FAFOAWYL.js → chunk-Q3YIAAG3.js} +17 -3
  144. package/src/testing-js/chunk-Q3YIAAG3.js.map +1 -0
  145. package/src/testing-js/{chunk-GNIUPIU2.js → chunk-U7OJE5DU.js} +18 -18
  146. package/src/testing-js/chunk-U7OJE5DU.js.map +1 -0
  147. package/src/testing-js/{chunk-4JQX6WWL.js → chunk-ZMZQZ33J.js} +474 -166
  148. package/src/testing-js/chunk-ZMZQZ33J.js.map +1 -0
  149. package/src/testing-js/component-behavior.contract.js +155 -0
  150. package/src/testing-js/component-behavior.contract.js.map +1 -0
  151. package/src/testing-js/component-editor.contract.js +6 -4
  152. package/src/testing-js/component-editor.contract.js.map +1 -1
  153. package/src/testing-js/component-render.contract.js +14 -10
  154. package/src/testing-js/component-render.contract.js.map +1 -1
  155. package/src/testing-js/index.d.ts +44 -4
  156. package/src/testing-js/index.js +13 -7
  157. package/src/testing-js/index.js.map +1 -1
  158. package/src/testing-js/page-compliance.contract.js +48 -10
  159. package/src/testing-js/page-compliance.contract.js.map +1 -1
  160. package/src/testing-js/registry.contract.js +5 -3
  161. package/src/testing-js/registry.contract.js.map +1 -1
  162. package/src/testing-js/{vitest-C-wNWcoA.d.ts → vitest-BMLIbDs2.d.ts} +8 -2
  163. package/src/testing-js/vitest.d.ts +1 -1
  164. package/src/testing-js/vitest.js +2 -1
  165. package/template/package.json +1 -2
  166. package/template/vite.config.ts +3 -2
  167. package/.claude/skills/live-tokens-create-component/SKILL copy.md +0 -196
  168. package/.claude/skills/live-tokens-fix-findings/SKILL.md +0 -105
  169. package/src/editor/skill-atlas/trees/fix-findings.ts +0 -504
  170. package/src/testing-js/chunk-4JQX6WWL.js.map +0 -1
  171. package/src/testing-js/chunk-FAFOAWYL.js.map +0 -1
  172. package/src/testing-js/chunk-GNIUPIU2.js.map +0 -1
@@ -0,0 +1,70 @@
1
+ import type { Migration } from './index';
2
+
3
+ /**
4
+ * CornerBadge's prefix is its id (2026-09-13).
5
+ *
6
+ * CornerBadge was registered `cornerbadge` but named its forty properties
7
+ * `--corner-badge-*`, the one shipped component whose prefix was not its id
8
+ * verbatim. They read `--cornerbadge-*`. Values are unchanged, so this is a
9
+ * pure key rename.
10
+ */
11
+ const RENAMES: Record<string, Record<string, string>> = {
12
+ cornerbadge: {
13
+ '--corner-badge-margin': '--cornerbadge-margin',
14
+ '--corner-badge-outer-radius': '--cornerbadge-outer-radius',
15
+ '--corner-badge-inner-radius': '--cornerbadge-inner-radius',
16
+ '--corner-badge-h-axis-radius': '--cornerbadge-h-axis-radius',
17
+ '--corner-badge-v-axis-radius': '--cornerbadge-v-axis-radius',
18
+ '--corner-badge-padding': '--cornerbadge-padding',
19
+ '--corner-badge-text-font-family': '--cornerbadge-text-font-family',
20
+ '--corner-badge-text-font-size': '--cornerbadge-text-font-size',
21
+ '--corner-badge-text-font-weight': '--cornerbadge-text-font-weight',
22
+ '--corner-badge-text-line-height': '--cornerbadge-text-line-height',
23
+ '--corner-badge-primary-surface': '--cornerbadge-primary-surface',
24
+ '--corner-badge-primary-border': '--cornerbadge-primary-border',
25
+ '--corner-badge-primary-text': '--cornerbadge-primary-text',
26
+ '--corner-badge-accent-surface': '--cornerbadge-accent-surface',
27
+ '--corner-badge-accent-border': '--cornerbadge-accent-border',
28
+ '--corner-badge-accent-text': '--cornerbadge-accent-text',
29
+ '--corner-badge-neutral-surface': '--cornerbadge-neutral-surface',
30
+ '--corner-badge-neutral-border': '--cornerbadge-neutral-border',
31
+ '--corner-badge-neutral-text': '--cornerbadge-neutral-text',
32
+ '--corner-badge-alternate-surface': '--cornerbadge-alternate-surface',
33
+ '--corner-badge-alternate-border': '--cornerbadge-alternate-border',
34
+ '--corner-badge-alternate-text': '--cornerbadge-alternate-text',
35
+ '--corner-badge-canvas-surface': '--cornerbadge-canvas-surface',
36
+ '--corner-badge-canvas-border': '--cornerbadge-canvas-border',
37
+ '--corner-badge-canvas-text': '--cornerbadge-canvas-text',
38
+ '--corner-badge-special-surface': '--cornerbadge-special-surface',
39
+ '--corner-badge-special-border': '--cornerbadge-special-border',
40
+ '--corner-badge-special-text': '--cornerbadge-special-text',
41
+ '--corner-badge-success-surface': '--cornerbadge-success-surface',
42
+ '--corner-badge-success-border': '--cornerbadge-success-border',
43
+ '--corner-badge-success-text': '--cornerbadge-success-text',
44
+ '--corner-badge-warning-surface': '--cornerbadge-warning-surface',
45
+ '--corner-badge-warning-border': '--cornerbadge-warning-border',
46
+ '--corner-badge-warning-text': '--cornerbadge-warning-text',
47
+ '--corner-badge-danger-surface': '--cornerbadge-danger-surface',
48
+ '--corner-badge-danger-border': '--cornerbadge-danger-border',
49
+ '--corner-badge-danger-text': '--cornerbadge-danger-text',
50
+ '--corner-badge-info-surface': '--cornerbadge-info-surface',
51
+ '--corner-badge-info-border': '--cornerbadge-info-border',
52
+ '--corner-badge-info-text': '--cornerbadge-info-text',
53
+ },
54
+ };
55
+
56
+ export const componentMigration_2026_09_13_cornerbadgePrefix: Migration = {
57
+ id: '2026-09-13-cornerbadge-prefix',
58
+ fromVersion: 31,
59
+ toVersion: 32,
60
+ appliesTo: 'component-config',
61
+ apply(rawVars, meta) {
62
+ const renames = meta.component ? RENAMES[meta.component] : undefined;
63
+ if (!renames) return { ...rawVars };
64
+ const out: Record<string, string> = {};
65
+ for (const [key, value] of Object.entries(rawVars)) {
66
+ out[renames[key] ?? key] = value;
67
+ }
68
+ return out;
69
+ },
70
+ };
@@ -0,0 +1,92 @@
1
+ import type { Migration } from './index';
2
+
3
+ /**
4
+ * One hairline (2026-09-13).
5
+ *
6
+ * The graphic line a component draws between its parts was `-divider` on
7
+ * Dialog, Table and TabBar, `-divider-color` on SegmentedControl, and
8
+ * `-hairline-color` on SectionDivider and CollapsibleSection; its width was
9
+ * `-divider-width` on two components and `-thickness` on four. Both now read
10
+ * `-hairline-color` and `-hairline-width`, and SegmentedControl's inset reads
11
+ * `-hairline-inset`. CollapsibleSection's `divider` variant is `hairline`, so
12
+ * its whole variant namespace moves with it. Values are unchanged, so this is
13
+ * a pure key rename.
14
+ */
15
+ const COLLAPSIBLESECTION_SUFFIXES = [
16
+ 'surface',
17
+ 'hairline-color',
18
+ 'padding',
19
+ 'label',
20
+ 'label-font-family',
21
+ 'label-font-size',
22
+ 'label-font-weight',
23
+ 'label-line-height',
24
+ 'icon',
25
+ 'icon-size',
26
+ ];
27
+
28
+ const COLLAPSIBLESECTION_STATES = ['default', 'hover'];
29
+
30
+ const RENAMES: Record<string, Record<string, string>> = {
31
+ dialog: {
32
+ '--dialog-header-divider': '--dialog-header-hairline-color',
33
+ '--dialog-header-divider-width': '--dialog-header-hairline-width',
34
+ '--dialog-footer-divider': '--dialog-footer-hairline-color',
35
+ '--dialog-footer-divider-width': '--dialog-footer-hairline-width',
36
+ },
37
+ table: {
38
+ '--table-default-header-divider': '--table-default-header-hairline-color',
39
+ '--table-default-header-divider-width': '--table-default-header-hairline-width',
40
+ '--table-default-row-divider': '--table-default-row-hairline-color',
41
+ '--table-default-row-divider-width': '--table-default-row-hairline-width',
42
+ '--table-default-column-divider': '--table-default-column-hairline-color',
43
+ '--table-default-column-divider-width': '--table-default-column-hairline-width',
44
+ },
45
+ tabbar: {
46
+ '--tabbar-bar-divider': '--tabbar-bar-hairline-color',
47
+ '--tabbar-bar-divider-thickness': '--tabbar-bar-hairline-width',
48
+ },
49
+ segmentedcontrol: {
50
+ '--segmentedcontrol-divider-color': '--segmentedcontrol-hairline-color',
51
+ '--segmentedcontrol-divider-thickness': '--segmentedcontrol-hairline-width',
52
+ '--segmentedcontrol-divider-inset': '--segmentedcontrol-hairline-inset',
53
+ '--segmentedcontrol-small-divider-thickness': '--segmentedcontrol-small-hairline-width',
54
+ '--segmentedcontrol-small-divider-inset': '--segmentedcontrol-small-hairline-inset',
55
+ },
56
+ collapsiblesection: {
57
+ ...Object.fromEntries(
58
+ COLLAPSIBLESECTION_STATES.flatMap((state) => [
59
+ ...COLLAPSIBLESECTION_SUFFIXES.map((s) => [
60
+ `--collapsiblesection-divider-${state}-${s}`,
61
+ `--collapsiblesection-hairline-${state}-${s}`,
62
+ ]),
63
+ [
64
+ `--collapsiblesection-divider-${state}-hairline-thickness`,
65
+ `--collapsiblesection-hairline-${state}-hairline-width`,
66
+ ],
67
+ ]),
68
+ ),
69
+ '--collapsiblesection-divider-expanded-padding': '--collapsiblesection-hairline-expanded-padding',
70
+ },
71
+ sectiondivider: {
72
+ '--sectiondivider-lg-hairline-thickness': '--sectiondivider-lg-hairline-width',
73
+ '--sectiondivider-md-hairline-thickness': '--sectiondivider-md-hairline-width',
74
+ '--sectiondivider-sm-hairline-thickness': '--sectiondivider-sm-hairline-width',
75
+ },
76
+ };
77
+
78
+ export const componentMigration_2026_09_13_hairline: Migration = {
79
+ id: '2026-09-13-hairline',
80
+ fromVersion: 28,
81
+ toVersion: 29,
82
+ appliesTo: 'component-config',
83
+ apply(rawVars, meta) {
84
+ const renames = meta.component ? RENAMES[meta.component] : undefined;
85
+ if (!renames) return { ...rawVars };
86
+ const out: Record<string, string> = {};
87
+ for (const [key, value] of Object.entries(rawVars)) {
88
+ out[renames[key] ?? key] = value;
89
+ }
90
+ return out;
91
+ },
92
+ };
@@ -0,0 +1,54 @@
1
+ import type { Migration } from './index';
2
+
3
+ /**
4
+ * One indicator (2026-09-13).
5
+ *
6
+ * `accent` named three different things: the accent color family on Badge and
7
+ * CornerBadge, the bar beside SideNavigation's current item, and the stripe on
8
+ * Callout's leading edge. The bar and the stripe are indicators, the word
9
+ * MenuSelect and TabBar already use, so the color reads `-indicator` and the
10
+ * width `-indicator-width`. Values are unchanged, so this is a pure key
11
+ * rename.
12
+ */
13
+ const SIDENAVIGATION_PARTS = ['title', 'section', 'item', 'footer'];
14
+ const SIDENAVIGATION_STATES = ['default', 'hover', 'selected'];
15
+ const CALLOUT_VARIANTS = ['info', 'success', 'warning', 'danger'];
16
+
17
+ const RENAMES: Record<string, Record<string, string>> = {
18
+ sidenavigation: Object.fromEntries(
19
+ SIDENAVIGATION_PARTS.flatMap((part) =>
20
+ SIDENAVIGATION_STATES.flatMap((state) => [
21
+ [
22
+ `--sidenavigation-${part}-${state}-accent`,
23
+ `--sidenavigation-${part}-${state}-indicator`,
24
+ ],
25
+ [
26
+ `--sidenavigation-${part}-${state}-accent-width`,
27
+ `--sidenavigation-${part}-${state}-indicator-width`,
28
+ ],
29
+ ]),
30
+ ),
31
+ ),
32
+ callout: Object.fromEntries(
33
+ CALLOUT_VARIANTS.map((v) => [
34
+ `--callout-${v}-accent-width`,
35
+ `--callout-${v}-indicator-width`,
36
+ ]),
37
+ ),
38
+ };
39
+
40
+ export const componentMigration_2026_09_13_indicator: Migration = {
41
+ id: '2026-09-13-indicator',
42
+ fromVersion: 29,
43
+ toVersion: 30,
44
+ appliesTo: 'component-config',
45
+ apply(rawVars, meta) {
46
+ const renames = meta.component ? RENAMES[meta.component] : undefined;
47
+ if (!renames) return { ...rawVars };
48
+ const out: Record<string, string> = {};
49
+ for (const [key, value] of Object.entries(rawVars)) {
50
+ out[renames[key] ?? key] = value;
51
+ }
52
+ return out;
53
+ },
54
+ };
@@ -0,0 +1,36 @@
1
+ import type { Migration } from './index';
2
+
3
+ /**
4
+ * SectionDivider's fill reads surface (2026-09-13).
5
+ *
6
+ * SectionDivider said `-background` for its container fill where every other
7
+ * component says `-surface`. The three `--sectiondivider-{lg,md,sm}-background`
8
+ * properties read `-surface`. Values are unchanged, so this is a pure key
9
+ * rename.
10
+ */
11
+ const SECTIONDIVIDER_VARIANTS = ['lg', 'md', 'sm'];
12
+
13
+ const RENAMES: Record<string, Record<string, string>> = {
14
+ sectiondivider: Object.fromEntries(
15
+ SECTIONDIVIDER_VARIANTS.map((v) => [
16
+ `--sectiondivider-${v}-background`,
17
+ `--sectiondivider-${v}-surface`,
18
+ ]),
19
+ ),
20
+ };
21
+
22
+ export const componentMigration_2026_09_13_sectiondividerSurface: Migration = {
23
+ id: '2026-09-13-sectiondivider-surface',
24
+ fromVersion: 30,
25
+ toVersion: 31,
26
+ appliesTo: 'component-config',
27
+ apply(rawVars, meta) {
28
+ const renames = meta.component ? RENAMES[meta.component] : undefined;
29
+ if (!renames) return { ...rawVars };
30
+ const out: Record<string, string> = {};
31
+ for (const [key, value] of Object.entries(rawVars)) {
32
+ out[renames[key] ?? key] = value;
33
+ }
34
+ return out;
35
+ },
36
+ };
@@ -0,0 +1,124 @@
1
+ import type { Migration } from './index';
2
+
3
+ /**
4
+ * Selection says selected (2026-09-13).
5
+ *
6
+ * `active` carried two senses: pressed, from `:active`, on Button and
7
+ * IconButton, and selected on RadioButton, TabBar, and SideNavigation. These
8
+ * three components hold a selection, so their state segment now reads
9
+ * `selected` and `active` survives as the pressed state only. Button's and
10
+ * IconButton's `--*-active-*` are pressed and never move. Values are
11
+ * unchanged, so this is a pure key rename.
12
+ */
13
+ const RADIOBUTTON_SUFFIXES = [
14
+ 'dot-border-color',
15
+ 'dot-border-width',
16
+ 'dot-fill',
17
+ 'dot-size',
18
+ 'label',
19
+ 'label-font-family',
20
+ 'label-font-size',
21
+ 'label-font-weight',
22
+ 'label-line-height',
23
+ ];
24
+
25
+ const TABBAR_SUFFIXES = [
26
+ 'border',
27
+ 'icon-size',
28
+ 'indicator-width',
29
+ 'padding',
30
+ 'surface',
31
+ 'tab-border-color',
32
+ 'tab-border-width',
33
+ 'tab-bottom-radius',
34
+ 'tab-top-radius',
35
+ 'text',
36
+ 'text-font-family',
37
+ 'text-font-size',
38
+ 'text-font-weight',
39
+ 'text-line-height',
40
+ ];
41
+
42
+ const SIDENAVIGATION_SUFFIXES: Record<string, string[]> = {
43
+ title: [
44
+ 'accent',
45
+ 'accent-width',
46
+ 'border',
47
+ 'border-width',
48
+ 'label',
49
+ 'label-font-family',
50
+ 'label-font-size',
51
+ 'label-font-weight',
52
+ 'label-line-height',
53
+ 'padding',
54
+ 'surface',
55
+ ],
56
+ section: [
57
+ 'accent',
58
+ 'accent-width',
59
+ 'surface',
60
+ 'text',
61
+ 'text-font-family',
62
+ 'text-font-size',
63
+ 'text-font-weight',
64
+ 'text-line-height',
65
+ ],
66
+ item: [
67
+ 'accent',
68
+ 'accent-width',
69
+ 'padding',
70
+ 'surface',
71
+ 'text',
72
+ 'text-font-family',
73
+ 'text-font-size',
74
+ 'text-font-weight',
75
+ 'text-line-height',
76
+ ],
77
+ footer: [
78
+ 'accent',
79
+ 'accent-width',
80
+ 'gap',
81
+ 'icon',
82
+ 'icon-size',
83
+ 'padding',
84
+ 'surface',
85
+ 'text',
86
+ 'text-font-family',
87
+ 'text-font-size',
88
+ 'text-font-weight',
89
+ 'text-line-height',
90
+ ],
91
+ };
92
+
93
+ const RENAMES: Record<string, Record<string, string>> = {
94
+ radiobutton: Object.fromEntries(
95
+ RADIOBUTTON_SUFFIXES.map((s) => [`--radiobutton-active-${s}`, `--radiobutton-selected-${s}`]),
96
+ ),
97
+ tabbar: Object.fromEntries(
98
+ TABBAR_SUFFIXES.map((s) => [`--tabbar-active-${s}`, `--tabbar-selected-${s}`]),
99
+ ),
100
+ sidenavigation: Object.fromEntries(
101
+ Object.entries(SIDENAVIGATION_SUFFIXES).flatMap(([part, suffixes]) =>
102
+ suffixes.map((s) => [
103
+ `--sidenavigation-${part}-active-${s}`,
104
+ `--sidenavigation-${part}-selected-${s}`,
105
+ ]),
106
+ ),
107
+ ),
108
+ };
109
+
110
+ export const componentMigration_2026_09_13_selectedState: Migration = {
111
+ id: '2026-09-13-selected-state',
112
+ fromVersion: 27,
113
+ toVersion: 28,
114
+ appliesTo: 'component-config',
115
+ apply(rawVars, meta) {
116
+ const renames = meta.component ? RENAMES[meta.component] : undefined;
117
+ if (!renames) return { ...rawVars };
118
+ const out: Record<string, string> = {};
119
+ for (const [key, value] of Object.entries(rawVars)) {
120
+ out[renames[key] ?? key] = value;
121
+ }
122
+ return out;
123
+ },
124
+ };
@@ -0,0 +1,31 @@
1
+ import type { Migration } from './index';
2
+
3
+ /**
4
+ * Toggle's label color drops the redundant `-text` suffix (2026-09-13).
5
+ *
6
+ * The bare part already names the color everywhere else; `-font-*` carries
7
+ * the type. Toggle was the one component still saying `-label-text`. Values
8
+ * are unchanged, so this is a pure key rename.
9
+ */
10
+ const RENAMES: Record<string, Record<string, string>> = {
11
+ toggle: {
12
+ '--toggle-label-text': '--toggle-label',
13
+ '--toggle-disabled-label-text': '--toggle-disabled-label',
14
+ },
15
+ };
16
+
17
+ export const componentMigration_2026_09_13_toggleLabel: Migration = {
18
+ id: '2026-09-13-toggle-label',
19
+ fromVersion: 32,
20
+ toVersion: 33,
21
+ appliesTo: 'component-config',
22
+ apply(rawVars, meta) {
23
+ const renames = meta.component ? RENAMES[meta.component] : undefined;
24
+ if (!renames) return { ...rawVars };
25
+ const out: Record<string, string> = {};
26
+ for (const [key, value] of Object.entries(rawVars)) {
27
+ out[renames[key] ?? key] = value;
28
+ }
29
+ return out;
30
+ },
31
+ };
@@ -75,6 +75,14 @@ import { componentMigration_2026_09_01_gateSuffixEnabled } from './2026-09-01-ga
75
75
  import { componentMigration_2026_09_02_sectiondividerDropTitleOutline } from './2026-09-02-sectiondivider-drop-title-outline';
76
76
  import { colorsAndTypeMigration_2026_09_03_dropLegacyComponentKeys } from './2026-09-03-drop-legacy-component-keys';
77
77
  import { componentMigration_2026_09_07_strokeRoleRenames } from './2026-09-07-stroke-role-renames';
78
+ import { componentMigration_2026_09_13_selectedState } from './2026-09-13-selected-state';
79
+ import { componentMigration_2026_09_13_hairline } from './2026-09-13-hairline';
80
+ import { componentMigration_2026_09_13_indicator } from './2026-09-13-indicator';
81
+ import { componentMigration_2026_09_13_sectiondividerSurface } from './2026-09-13-sectiondivider-surface';
82
+ import { componentMigration_2026_09_13_cornerbadgePrefix } from './2026-09-13-cornerbadge-prefix';
83
+ import { componentMigration_2026_09_13_toggleLabel } from './2026-09-13-toggle-label';
84
+ import { componentMigration_2026_09_13_collapsiblesectionOpen } from './2026-09-13-collapsiblesection-open';
85
+ import { componentMigration_2026_09_13_badgeBrand } from './2026-09-13-badge-brand';
78
86
 
79
87
  /**
80
88
  * Registered migrations. Order in this array does not matter — the runner
@@ -116,6 +124,14 @@ export const MIGRATIONS: Migration[] = [
116
124
  componentMigration_2026_09_02_sectiondividerDropTitleOutline,
117
125
  colorsAndTypeMigration_2026_09_03_dropLegacyComponentKeys,
118
126
  componentMigration_2026_09_07_strokeRoleRenames,
127
+ componentMigration_2026_09_13_selectedState,
128
+ componentMigration_2026_09_13_hairline,
129
+ componentMigration_2026_09_13_indicator,
130
+ componentMigration_2026_09_13_sectiondividerSurface,
131
+ componentMigration_2026_09_13_cornerbadgePrefix,
132
+ componentMigration_2026_09_13_toggleLabel,
133
+ componentMigration_2026_09_13_collapsiblesectionOpen,
134
+ componentMigration_2026_09_13_badgeBrand,
119
135
  ];
120
136
 
121
137
  function countFor(kind: 'colors-and-type' | 'component-config'): number {
@@ -144,8 +144,8 @@ function withoutLiveMarkers<T extends { _fileName?: string; _source?: unknown }>
144
144
  /**
145
145
  * The content as it stands: the live colors and type plus the live config of
146
146
  * every component this install has, all by value. A theme is a complete
147
- * document (`docs/plans/theme-completeness.md`), so the capture carries every
148
- * component, not just the ones off their default.
147
+ * document, so the capture carries every component, not just the ones off
148
+ * their default.
149
149
  *
150
150
  * Everything comes from the live read doors, so a capture takes the buffers
151
151
  * over the open theme's own copies. The colors and type are normalised on the
@@ -164,7 +164,7 @@ async function captureThemeContent(): Promise<Pick<Theme, 'colorsAndType' | 'com
164
164
  const config = configs[i];
165
165
  if (config) componentConfigs[c.name] = withoutLiveMarkers(config);
166
166
  });
167
- // Sketchstyle has no server door of its own (RJC 8): the live buffer, not a
167
+ // Sketchstyle has no server door of its own: the live buffer, not a
168
168
  // fetch, is the source of truth for what the dials currently say.
169
169
  return { colorsAndType: withoutLiveMarkers(liveColorsAndType), componentConfigs, sketchSettings: liveSketchSettings() };
170
170
  }
@@ -3,8 +3,7 @@ import type { GradientValue } from './parsers/gradient';
3
3
  import type { Oklch } from '../palettes/oklch';
4
4
  import type { HarmonyAxis } from '../palettes/colorHarmony';
5
5
  import type { SketchStyleSettings } from '../sketch/sketchStyles';
6
- /** Single source of truth for the theme schema version
7
- * (docs/plans/theme-completeness.md, Wave 2 step 5). It lives here, on the
6
+ /** Single source of truth for the theme schema version. It lives here, on the
8
7
  * shipped side: `vite-plugin/` is build tooling and is not in the tarball, so
9
8
  * anything under `src/` that reaches into it resolves in this repo and
10
9
  * nowhere else. `normalizeTheme.ts` re-exports this. */
@@ -160,8 +159,8 @@ export type LiveSource = 'working' | 'theme';
160
159
  /**
161
160
  * Where a live colors-and-type read resolved from. Unlike `LiveSource`, this
162
161
  * keeps a third value: colors-and-type resolution is unchanged by the theme
163
- * completeness work (docs/plans/theme-completeness.md Wave 4), so `default`
164
- * still answers the one case completeness can't reach — the open theme's
162
+ * completeness work, so `default` still answers the one case completeness
163
+ * can't reach — the open theme's
165
164
  * file itself is unreadable (a stale pointer, or deleted mid-session), so
166
165
  * there is no document to resolve `working` or `theme` against.
167
166
  */
@@ -258,24 +257,23 @@ export interface Theme {
258
257
  updatedAt: string;
259
258
  /** Migration stamp. 1 was the pointer form (colors-and-type + config
260
259
  * basenames); 2 encapsulated it under a `theme` key; 3 spells that key
261
- * `colorsAndType`; 4 makes the theme complete (`docs/plans/
262
- * theme-completeness.md`, Wave 2) — every known component and every alias
263
- * key its `default.json` declares, by value. The server rewrites older
264
- * files at boot. */
260
+ * `colorsAndType`; 4 makes the theme complete — every known component and
261
+ * every alias key its `default.json` declares, by value. The server
262
+ * rewrites older files at boot. */
265
263
  schemaVersion: typeof THEME_SCHEMA_VERSION;
266
264
  /** Full colors-and-type content. */
267
265
  colorsAndType: ColorsAndType;
268
266
  /** Component id → its config, by value, one entry per component this
269
267
  * install has and every alias key that component's `default.json`
270
268
  * declares. `normalizeTheme` migrates each embedded config to the current
271
- * component schema and then fills any gap from the local default, on every
272
- * read (Waves 1 and 2 of `docs/plans/theme-completeness.md`); both the
273
- * migration and the fill are persisted on the next write, so a theme is a
274
- * whole-theme document rather than a diff against a moving baseline.
269
+ * component schema and then fills any gap from the local default, on
270
+ * every read; both the migration and the fill are persisted on the next
271
+ * write, so a theme is a whole-theme document rather than a diff against
272
+ * a moving baseline.
275
273
  * `component-configs/<id>/default.json` is the derivation product of that
276
274
  * component's `:global(:root)`, not a resolution layer this map defers to
277
275
  * — a config for a component this install does not have, or an alias key
278
- * its current default no longer declares, is kept exactly as read (RJC 3)
276
+ * its current default no longer declares, is kept exactly as read
279
277
  * rather than dropped. */
280
278
  componentConfigs: Record<string, ComponentConfig>;
281
279
  /** Migration stamp for every embedded component config in this theme, one
@@ -286,7 +284,7 @@ export interface Theme {
286
284
  componentSchemaVersion: number;
287
285
  /** The sketchstyle this theme paints, by value. Absent means the theme is
288
286
  * crisp: presence is the on state, so there is no separate flag that can
289
- * disagree with the dials beside it (RJC 1). */
287
+ * disagree with the dials beside it. */
290
288
  sketchSettings?: SketchStyleSettings;
291
289
  /** Server-attached file-name marker. Same role as `ColorsAndType._fileName`. */
292
290
  _fileName?: string;
@@ -307,7 +305,7 @@ export interface ThemeBundle {
307
305
  /** Tracks the enclosed theme's schema. Import still accepts 1, where the
308
306
  * envelope carried a pointer theme plus separately inlined colors and type
309
307
  * and `${component}/${configName}`-keyed configs, and 3, from before the
310
- * Wave 2 completeness bump — `normalizeTheme` fills either on the way in. */
308
+ * completeness bump — `normalizeTheme` fills either on the way in. */
311
309
  schemaVersion: typeof THEME_SCHEMA_VERSION;
312
310
  /** Sender's `@motion-proto/live-tokens` package version. Receiver can
313
311
  * compare to its own to warn about compatibility drift. */
@@ -256,7 +256,7 @@
256
256
  <SideNavigation
257
257
  class="docs-sidebar"
258
258
  sections={navSections}
259
- titleLabel="LiveTokens"
259
+ title="LiveTokens"
260
260
  titleHref="#01-overview"
261
261
  currentPath={parsedHash.chapter}
262
262
  open={sidebarOpen}
@@ -20,7 +20,7 @@ selects, so a rule can key on it, and it sets `color-scheme`, so every
20
20
  ```
21
21
 
22
22
  That line is right on both sides of the theme, and it is right inside a dark
23
- band on a pale page, because the nearest `color-scheme` wins.
23
+ section on a pale page, because the nearest `color-scheme` wins.
24
24
 
25
25
  ## Stating it
26
26
 
@@ -86,5 +86,5 @@ a stop function. `cssColorToHex` resolves any CSS colour — including the
86
86
  Polarity is a property of a surface, not of a component, so nothing is stamped
87
87
  for you below `<html>`: a section that needs an answer either states one or asks
88
88
  for one. And a measurement reads the paint at the moment it runs — an element
89
- that scrolls from a pale band onto a dark one keeps the answer it was given.
90
- State the tone on each band instead.
89
+ that scrolls from a pale section onto a dark one keeps the answer it was given.
90
+ State the tone on each section instead.