@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.
- package/.claude/skills/live-tokens-check-compliance/SKILL.md +49 -38
- package/.claude/skills/live-tokens-create-component/SKILL.md +23 -28
- package/.claude/skills/live-tokens-create-component/references/contract-tests.md +61 -0
- package/.claude/skills/live-tokens-create-component/references/sketch-mode.md +2 -2
- package/.claude/skills/live-tokens-create-component/references/token-naming.md +6 -15
- package/.claude/skills/live-tokens-create-page/SKILL.md +6 -4
- package/.claude/skills/live-tokens-create-theme/references/design-directions.md +1 -1
- package/.claude/skills/live-tokens-pick-component/SKILL.md +3 -3
- package/.claude/skills/live-tokens-set-colors/references/color-anchors.md +1 -1
- package/.claude/skills/live-tokens-set-geometry/SKILL.md +1 -1
- package/.claude/skills/live-tokens-set-geometry/references/geometry-anchors.md +1 -1
- package/CHANGELOG.md +271 -0
- package/README.md +10 -16
- package/bin/check-component.mjs +154 -551
- package/bin/check-page.mjs +57 -541
- package/bin/cli.mjs +93 -16
- package/bin/contractRunner.mjs +37 -91
- package/bin/lib/buildChecks.mjs +32 -0
- package/bin/lib/catalogue.mjs +161 -34
- package/bin/lib/componentSource.mjs +152 -0
- package/bin/lib/cssValues.mjs +9 -0
- package/bin/lib/dataDir.mjs +126 -0
- package/bin/lib/findings.mjs +103 -12
- package/bin/lib/fixers.mjs +64 -0
- package/bin/lib/geometry.mjs +92 -0
- package/bin/lib/pageSource.mjs +230 -0
- package/bin/lib/report.mjs +57 -59
- package/bin/lib/tokenVocabulary.mjs +104 -34
- package/bin/migrate-build-script.mjs +66 -0
- package/bin/migrate.mjs +5 -0
- package/bin/rules/componentStructure.mjs +344 -0
- package/bin/rules/componentUse.mjs +313 -0
- package/bin/rules/importsAndRoutes.mjs +136 -0
- package/bin/rules/testRuns.mjs +122 -0
- package/bin/rules/tokens.mjs +426 -0
- package/bin/setup-claude.mjs +1 -2
- package/dist-plugin/{chunk-PDNL4NC5.js → chunk-D4WRIKEZ.js} +7 -2
- package/dist-plugin/{chunk-SWXRVZKT.js → chunk-REBHE3ZM.js} +414 -1
- package/dist-plugin/index.cjs +470 -19
- package/dist-plugin/index.d.cts +1 -0
- package/dist-plugin/index.d.ts +1 -0
- package/dist-plugin/index.js +87 -55
- package/dist-plugin/migrateData/index.cjs +422 -4
- package/dist-plugin/migrateData/index.js +2 -2
- package/dist-plugin/setColors/index.cjs +414 -1
- package/dist-plugin/setColors/index.d.cts +1 -1
- package/dist-plugin/setColors/index.d.ts +1 -1
- package/dist-plugin/setColors/index.js +1 -1
- package/dist-plugin/setGeometry/index.cjs +423 -13
- package/dist-plugin/setGeometry/index.d.cts +3 -3
- package/dist-plugin/setGeometry/index.d.ts +3 -3
- package/dist-plugin/setGeometry/index.js +10 -13
- package/dist-plugin/setType/index.d.cts +1 -1
- package/dist-plugin/setType/index.d.ts +1 -1
- package/dist-plugin/{themeTypes-BxRtuN5V.d.cts → themeTypes-B8_Idrp4.d.cts} +2 -2
- package/dist-plugin/{themeTypes-BxRtuN5V.d.ts → themeTypes-B8_Idrp4.d.ts} +2 -2
- package/package.json +2 -2
- package/src/editor/component-editor/CalloutEditor.svelte +2 -2
- package/src/editor/component-editor/CollapsibleSectionEditor.svelte +14 -15
- package/src/editor/component-editor/CornerBadgeEditor.svelte +14 -14
- package/src/editor/component-editor/DialogEditor.svelte +5 -5
- package/src/editor/component-editor/InlineEditActionsEditor.svelte +2 -2
- package/src/editor/component-editor/RadioButtonEditor.svelte +21 -21
- package/src/editor/component-editor/SectionDividerEditor.svelte +7 -7
- package/src/editor/component-editor/SegmentedControlEditor.svelte +5 -5
- package/src/editor/component-editor/SideNavigationEditor.svelte +25 -25
- package/src/editor/component-editor/TabBarEditor.svelte +6 -6
- package/src/editor/component-editor/TableEditor.svelte +6 -6
- package/src/editor/component-editor/ToggleEditor.svelte +2 -2
- package/src/editor/component-editor/index.ts +3 -0
- package/src/editor/component-editor/registry.ts +57 -1
- package/src/editor/component-editor/scaffolding/TokenLayout.svelte +14 -14
- package/src/editor/component-editor/scaffolding/VariantGroup.svelte +3 -0
- package/src/editor/component-editor/scaffolding/types.ts +15 -0
- package/src/editor/core/components/adjustAliases.ts +4 -4
- package/src/editor/core/components/aliasKinds.ts +20 -19
- package/src/editor/core/sketch/sketchLayer.ts +3 -3
- package/src/editor/core/themes/migrateComponentConfig.ts +14 -6
- package/src/editor/core/themes/migrations/2026-09-13-badge-brand.ts +42 -0
- package/src/editor/core/themes/migrations/2026-09-13-collapsiblesection-open.ts +33 -0
- package/src/editor/core/themes/migrations/2026-09-13-cornerbadge-prefix.ts +70 -0
- package/src/editor/core/themes/migrations/2026-09-13-hairline.ts +92 -0
- package/src/editor/core/themes/migrations/2026-09-13-indicator.ts +54 -0
- package/src/editor/core/themes/migrations/2026-09-13-sectiondivider-surface.ts +36 -0
- package/src/editor/core/themes/migrations/2026-09-13-selected-state.ts +124 -0
- package/src/editor/core/themes/migrations/2026-09-13-toggle-label.ts +31 -0
- package/src/editor/core/themes/migrations/index.ts +16 -0
- package/src/editor/core/themes/themeService.ts +3 -3
- package/src/editor/core/themes/themeTypes.ts +13 -15
- package/src/editor/docs/Docs.svelte +1 -1
- package/src/editor/docs/content/light-and-dark.md +3 -3
- package/src/editor/docs/content.generated.ts +1 -1
- package/src/editor/index.ts +1 -0
- package/src/editor/overlay/LiveEditorOverlay.svelte +15 -0
- package/src/editor/skill-atlas/SkillAtlas.svelte +4 -4
- package/src/editor/skill-atlas/TreeNodeCard.svelte +4 -4
- package/src/editor/skill-atlas/skillSources.generated.ts +11 -14
- package/src/editor/skill-atlas/skillTrees.ts +1 -3
- package/src/editor/skill-atlas/trees/check-compliance.ts +37 -149
- package/src/editor/skill-atlas/trees/create-component.ts +62 -64
- package/src/editor/skill-atlas/trees/create-page.ts +38 -17
- package/src/editor/skill-atlas/trees/pick-component.ts +3 -3
- package/src/editor/skill-atlas/trees/set-geometry.ts +1 -1
- package/src/editor/ui/UIPaletteSelector.svelte +11 -15
- package/src/editor/ui/variantScales.ts +8 -8
- package/src/live-tokens/data/themes/autumn.json +188 -188
- package/src/live-tokens/data/themes/halloween.json +188 -188
- package/src/live-tokens/data/themes/midnight-study.json +245 -245
- package/src/live-tokens/data/themes/ocean.json +188 -188
- package/src/live-tokens/data/themes/royal-velvet.json +188 -188
- package/src/live-tokens/data/themes/sketchy.json +188 -188
- package/src/live-tokens/data/themes/spring-meadow.json +188 -188
- package/src/live-tokens/data/themes/sunset.json +188 -188
- package/src/system/components/Badge.svelte +27 -23
- package/src/system/components/Button.svelte +13 -7
- package/src/system/components/Callout.svelte +16 -11
- package/src/system/components/Card.svelte +22 -15
- package/src/system/components/CodeSnippet.svelte +10 -6
- package/src/system/components/CollapsibleSection.svelte +81 -76
- package/src/system/components/CornerBadge.svelte +78 -72
- package/src/system/components/Dialog.svelte +21 -18
- package/src/system/components/IconButton.svelte +13 -9
- package/src/system/components/Image.svelte +14 -8
- package/src/system/components/ImageLightbox.svelte +10 -6
- package/src/system/components/InlineEditActions.svelte +17 -14
- package/src/system/components/Input.svelte +13 -7
- package/src/system/components/MenuSelect.svelte +13 -7
- package/src/system/components/Notification.svelte +17 -11
- package/src/system/components/Panel.svelte +13 -6
- package/src/system/components/ProgressBar.svelte +10 -5
- package/src/system/components/RadioButton.svelte +33 -30
- package/src/system/components/SectionDivider.svelte +28 -21
- package/src/system/components/SegmentedControl.svelte +27 -23
- package/src/system/components/SideNavigation.svelte +175 -171
- package/src/system/components/Slider.svelte +11 -7
- package/src/system/components/TabBar.svelte +53 -49
- package/src/system/components/Table.svelte +20 -15
- package/src/system/components/Toggle.svelte +14 -10
- package/src/system/components/Tooltip.svelte +10 -6
- package/src/system/styles/CONVENTIONS.md +3 -4
- package/src/testing-js/chunk-3UKGXCDL.js +48 -0
- package/src/testing-js/chunk-3UKGXCDL.js.map +1 -0
- package/src/testing-js/{chunk-FAFOAWYL.js → chunk-Q3YIAAG3.js} +17 -3
- package/src/testing-js/chunk-Q3YIAAG3.js.map +1 -0
- package/src/testing-js/{chunk-GNIUPIU2.js → chunk-U7OJE5DU.js} +18 -18
- package/src/testing-js/chunk-U7OJE5DU.js.map +1 -0
- package/src/testing-js/{chunk-4JQX6WWL.js → chunk-ZMZQZ33J.js} +474 -166
- package/src/testing-js/chunk-ZMZQZ33J.js.map +1 -0
- package/src/testing-js/component-behavior.contract.js +155 -0
- package/src/testing-js/component-behavior.contract.js.map +1 -0
- package/src/testing-js/component-editor.contract.js +6 -4
- package/src/testing-js/component-editor.contract.js.map +1 -1
- package/src/testing-js/component-render.contract.js +14 -10
- package/src/testing-js/component-render.contract.js.map +1 -1
- package/src/testing-js/index.d.ts +44 -4
- package/src/testing-js/index.js +13 -7
- package/src/testing-js/index.js.map +1 -1
- package/src/testing-js/page-compliance.contract.js +48 -10
- package/src/testing-js/page-compliance.contract.js.map +1 -1
- package/src/testing-js/registry.contract.js +5 -3
- package/src/testing-js/registry.contract.js.map +1 -1
- package/src/testing-js/{vitest-C-wNWcoA.d.ts → vitest-BMLIbDs2.d.ts} +8 -2
- package/src/testing-js/vitest.d.ts +1 -1
- package/src/testing-js/vitest.js +2 -1
- package/template/package.json +1 -2
- package/template/vite.config.ts +3 -2
- package/.claude/skills/live-tokens-create-component/SKILL copy.md +0 -196
- package/.claude/skills/live-tokens-fix-findings/SKILL.md +0 -105
- package/src/editor/skill-atlas/trees/fix-findings.ts +0 -504
- package/src/testing-js/chunk-4JQX6WWL.js.map +0 -1
- package/src/testing-js/chunk-FAFOAWYL.js.map +0 -1
- 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
|
|
148
|
-
*
|
|
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
|
|
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
|
|
164
|
-
*
|
|
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
|
|
262
|
-
*
|
|
263
|
-
*
|
|
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
|
|
272
|
-
* read
|
|
273
|
-
*
|
|
274
|
-
*
|
|
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
|
|
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
|
|
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
|
-
*
|
|
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. */
|
|
@@ -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
|
-
|
|
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
|
|
90
|
-
State the tone on each
|
|
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.
|