@motion-proto/live-tokens 0.1.1 → 0.3.2
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/README.md +168 -21
- package/dist-plugin/index.cjs +823 -336
- package/dist-plugin/index.d.cts +9 -7
- package/dist-plugin/index.d.ts +9 -7
- package/dist-plugin/index.js +822 -335
- package/package.json +46 -20
- package/src/assets/newspaper.webp +0 -0
- package/src/assets/offering.webp +0 -0
- package/src/component-editor/BadgeEditor.svelte +170 -0
- package/src/component-editor/CalloutEditor.svelte +103 -0
- package/src/component-editor/CardEditor.svelte +184 -0
- package/src/component-editor/CollapsibleSectionEditor.svelte +167 -0
- package/src/component-editor/CornerBadgeEditor.svelte +207 -0
- package/src/component-editor/DialogEditor.svelte +172 -0
- package/src/component-editor/ImageEditor.svelte +72 -0
- package/src/component-editor/InlineEditActionsEditor.svelte +83 -0
- package/src/component-editor/NotificationEditor.svelte +160 -0
- package/src/component-editor/ProgressBarEditor.svelte +124 -0
- package/src/component-editor/RadioButtonEditor.svelte +140 -0
- package/src/component-editor/SectionDividerEditor.svelte +263 -0
- package/src/component-editor/SegmentedControlEditor.svelte +154 -0
- package/src/component-editor/StandardButtonsEditor.svelte +178 -0
- package/src/component-editor/TabBarEditor.svelte +137 -0
- package/src/component-editor/TableEditor.svelte +128 -0
- package/src/component-editor/TooltipEditor.svelte +122 -0
- package/src/component-editor/editorTokens.test.ts +93 -0
- package/src/component-editor/groupKeySlots.test.ts +67 -0
- package/src/component-editor/groupKeySnapshot.test.ts +52 -0
- package/src/component-editor/index.ts +5 -0
- package/src/component-editor/registry.ts +246 -0
- package/src/component-editor/scaffolding/AngleDial.svelte +185 -0
- package/src/component-editor/scaffolding/ComponentEditorBase.svelte +96 -0
- package/src/component-editor/scaffolding/ComponentFileManager.svelte +682 -0
- package/src/component-editor/scaffolding/ComponentFileMenu.svelte +312 -0
- package/src/component-editor/scaffolding/ComponentsTab.svelte +69 -0
- package/src/component-editor/scaffolding/CopyFromMenu.svelte +246 -0
- package/src/component-editor/scaffolding/DemoHeader.svelte +21 -0
- package/src/component-editor/scaffolding/DividerEditor.svelte +81 -0
- package/src/component-editor/scaffolding/FieldsetWrapper.svelte +46 -0
- package/src/component-editor/scaffolding/GradientCard.svelte +291 -0
- package/src/component-editor/scaffolding/LinkageChart.svelte +297 -0
- package/src/component-editor/scaffolding/LinkedBlock.svelte +418 -0
- package/src/component-editor/scaffolding/NonStylableConfig.svelte +57 -0
- package/src/component-editor/scaffolding/SaveAsDialog.svelte +177 -0
- package/src/component-editor/scaffolding/ShadowBackdrop.svelte +25 -0
- package/src/component-editor/scaffolding/ShadowBackdropControls.svelte +56 -0
- package/src/component-editor/scaffolding/StateBlock.svelte +115 -0
- package/src/component-editor/scaffolding/TokenLayout.svelte +511 -0
- package/src/component-editor/scaffolding/TypeEditor.svelte +82 -0
- package/src/component-editor/scaffolding/VariantGroup.svelte +277 -0
- package/src/component-editor/scaffolding/buildTypeGroupTokens.ts +97 -0
- package/src/component-editor/scaffolding/componentSectionType.ts +8 -0
- package/src/component-editor/scaffolding/componentSources.ts +9 -0
- package/src/component-editor/scaffolding/defaultSections.ts +16 -0
- package/src/component-editor/scaffolding/editorContext.ts +44 -0
- package/src/component-editor/scaffolding/linkedBlock.ts +226 -0
- package/src/component-editor/scaffolding/siblings.ts +33 -0
- package/src/component-editor/scaffolding/types.ts +39 -0
- package/src/components/Badge.svelte +231 -42
- package/src/components/Button.svelte +324 -124
- package/src/components/Callout.svelte +145 -0
- package/src/components/Card.svelte +123 -25
- package/src/components/CollapsibleSection.svelte +213 -35
- package/src/components/CornerBadge.svelte +224 -0
- package/src/components/Dialog.svelte +137 -114
- package/src/components/Image.svelte +43 -0
- package/src/components/InlineEditActions.svelte +74 -14
- package/src/components/Notification.svelte +184 -163
- package/src/components/ProgressBar.svelte +216 -22
- package/src/components/RadioButton.svelte +110 -40
- package/src/components/SectionDivider.svelte +428 -74
- package/src/components/SegmentedControl.svelte +203 -0
- package/src/components/TabBar.svelte +146 -21
- package/src/components/Table.svelte +102 -0
- package/src/components/Tooltip.svelte +45 -19
- package/src/components/types.ts +51 -0
- package/src/data/google-fonts.json +75 -0
- package/src/lib/ColumnsOverlay.svelte +20 -7
- package/src/lib/LiveEditorOverlay.svelte +257 -78
- package/src/lib/columnsOverlay.ts +21 -17
- package/src/lib/componentConfig.test.ts +204 -0
- package/src/lib/componentConfigKeys.ts +19 -0
- package/src/lib/componentConfigService.ts +88 -0
- package/src/lib/copyPopover.ts +30 -0
- package/src/lib/cssVarSync.ts +59 -7
- package/src/lib/editorConfigStore.ts +0 -10
- package/src/lib/editorCore.ts +402 -0
- package/src/lib/editorKeybindings.ts +52 -0
- package/src/lib/editorPersistence.ts +106 -0
- package/src/lib/editorRenderer.ts +74 -0
- package/src/lib/editorStore.test.ts +328 -0
- package/src/lib/editorStore.ts +412 -0
- package/src/lib/editorTypes.ts +100 -0
- package/src/lib/editorViewStore.ts +55 -0
- package/src/lib/files/versionedFileResource.ts +140 -0
- package/src/lib/fontLoader.ts +130 -0
- package/src/lib/fontMigration.ts +140 -0
- package/src/lib/fontParse.ts +168 -0
- package/src/lib/index.ts +48 -30
- package/src/lib/lazyConfig.test.ts +54 -0
- package/src/lib/migrations/2026-04-24-component-prefix-and-suffix-renames.ts +64 -0
- package/src/lib/migrations/2026-04-24-legacy-keys-and-bg-to-canvas.ts +71 -0
- package/src/lib/migrations/2026-04-27-segmentedcontrol-disabled-flatten.ts +43 -0
- package/src/lib/migrations/2026-05-08-collapsiblesection-frame-and-cleanup.ts +68 -0
- package/src/lib/migrations/2026-05-08-collapsiblesection-variant-namespace.ts +35 -0
- package/src/lib/migrations/2026-05-10-sectiondivider-gradient-stops.ts +50 -0
- package/src/lib/migrations/2026-05-13-primary-to-brand.ts +90 -0
- package/src/lib/migrations/index.ts +93 -0
- package/src/lib/migrations/migrations.test.ts +341 -0
- package/src/lib/navLinkTypes.ts +1 -0
- package/src/lib/overlayState.ts +3 -0
- package/src/lib/paletteDerivation.ts +300 -0
- package/src/lib/parentRouteStore.ts +42 -0
- package/src/lib/parsers/globalRootBlock.ts +32 -0
- package/src/lib/presetService.ts +94 -0
- package/src/lib/router.ts +42 -10
- package/src/lib/scrollSection.ts +45 -0
- package/src/lib/slices/columns.ts +59 -0
- package/src/lib/slices/components.ts +362 -0
- package/src/lib/slices/domainVars.ts +15 -0
- package/src/lib/slices/fonts.ts +30 -0
- package/src/lib/slices/gradients.ts +153 -0
- package/src/lib/slices/overlays.ts +132 -0
- package/src/lib/slices/palettes.ts +26 -0
- package/src/lib/slices/shadows.ts +123 -0
- package/src/lib/storage.ts +88 -0
- package/src/lib/themeInit.ts +74 -0
- package/src/lib/themeService.ts +101 -0
- package/src/lib/themeTypes.ts +146 -0
- package/src/lib/tokenRegistry.ts +148 -0
- package/src/pages/ComponentEditorPage.svelte +384 -0
- package/src/pages/ComponentEditorPage.svelte.d.ts +2 -0
- package/src/pages/Editor.svelte +98 -0
- package/src/pages/Editor.svelte.d.ts +2 -0
- package/src/pages/EditorShell.svelte +348 -0
- package/src/styles/_padding.scss +34 -0
- package/src/styles/fonts/Fraunces/Fraunces-italic-latin-ext.woff2 +0 -0
- package/src/styles/fonts/Fraunces/Fraunces-italic-latin.woff2 +0 -0
- package/src/styles/fonts/Fraunces/Fraunces-roman-latin-ext.woff2 +0 -0
- package/src/styles/fonts/Fraunces/Fraunces-roman-latin.woff2 +0 -0
- package/src/styles/fonts/Manrope/Manrope-latin-ext.woff2 +0 -0
- package/src/styles/fonts/Manrope/Manrope-latin.woff2 +0 -0
- package/src/styles/fonts.css +22 -10
- package/src/styles/form-controls.css +14 -16
- package/src/styles/tokens.css +1322 -0
- package/src/styles/ui-editor.css +126 -0
- package/src/{showcase → ui}/BezierCurveEditor.svelte +14 -14
- package/src/{showcase → ui}/ColorEditPanel.svelte +42 -36
- package/src/ui/EditorViewSwitcher.svelte +180 -0
- package/src/ui/FontStackEditor.svelte +360 -0
- package/src/ui/GradientEditor.svelte +461 -0
- package/src/ui/GradientStopPicker.svelte +74 -0
- package/src/ui/PaletteEditor.svelte +1590 -0
- package/src/ui/PaletteEditor.test.ts +108 -0
- package/src/ui/PresetFileManager.svelte +567 -0
- package/src/ui/ProjectFontsSection.svelte +645 -0
- package/src/{showcase → ui}/SurfacesTab.svelte +39 -39
- package/src/{showcase → ui}/TextTab.svelte +27 -27
- package/src/{showcase/TokenFileManager.svelte → ui/ThemeFileManager.svelte} +196 -112
- package/src/ui/Toggle.svelte +108 -0
- package/src/ui/UICopyPopover.svelte +78 -0
- package/src/{showcase/EditorDialog.svelte → ui/UIDialog.svelte} +66 -25
- package/src/ui/UIFontFamilySelector.svelte +309 -0
- package/src/ui/UIFontSizeSelector.svelte +165 -0
- package/src/ui/UIFontWeightSelector.svelte +52 -0
- package/src/ui/UILineHeightSelector.svelte +47 -0
- package/src/ui/UILinkToggle.svelte +60 -0
- package/src/ui/UIOptionItem.svelte +74 -0
- package/src/ui/UIOptionList.svelte +27 -0
- package/src/ui/UIPaddingSelector.svelte +661 -0
- package/src/ui/UIPaletteSelector.svelte +1084 -0
- package/src/ui/UIRadio.svelte +72 -0
- package/src/ui/UIRadioGroup.svelte +59 -0
- package/src/ui/UIRelinkConfirmPopover.svelte +235 -0
- package/src/ui/UITokenSelector.svelte +509 -0
- package/src/ui/UIVariantSelector.svelte +145 -0
- package/src/ui/VariablesTab.svelte +252 -0
- package/src/ui/index.ts +31 -0
- package/src/ui/keepInViewport.ts +84 -0
- package/src/ui/palette/GradientStopEditor.svelte +482 -0
- package/src/ui/palette/OverridesPanel.svelte +526 -0
- package/src/ui/palette/PaletteBase.svelte +165 -0
- package/src/ui/palette/ScaleCurveEditor.svelte +38 -0
- package/src/ui/palette/paletteEditorState.ts +89 -0
- package/src/ui/sections/ColumnsSection.svelte +273 -0
- package/src/ui/sections/GradientsSection.svelte +147 -0
- package/src/ui/sections/OverlaysSection.svelte +670 -0
- package/src/ui/sections/ShadowsSection.svelte +1250 -0
- package/src/ui/sections/TokenScaleTable.svelte +332 -0
- package/src/ui/sections/tokenScales.ts +81 -0
- package/src/ui/variantScales.ts +108 -0
- package/src/components/DetailNav.svelte +0 -78
- package/src/components/Toggle.svelte +0 -86
- package/src/lib/tokenInit.ts +0 -29
- package/src/lib/tokenService.ts +0 -144
- package/src/lib/tokenTypes.ts +0 -45
- package/src/pages/Admin.svelte +0 -100
- package/src/pages/ShowcasePage.svelte +0 -144
- package/src/showcase/BackupBrowser.svelte +0 -617
- package/src/showcase/ComponentsTab.svelte +0 -105
- package/src/showcase/PaletteEditor.svelte +0 -2579
- package/src/showcase/PaletteSelector.svelte +0 -627
- package/src/showcase/TokenMap.svelte +0 -54
- package/src/showcase/VariablesTab.svelte +0 -2655
- package/src/showcase/VisualsTab.svelte +0 -231
- package/src/showcase/demos/BadgeDemo.svelte +0 -56
- package/src/showcase/demos/CardDemo.svelte +0 -50
- package/src/showcase/demos/ChoiceButtonsDemo.svelte +0 -192
- package/src/showcase/demos/CollapsibleSectionDemo.svelte +0 -54
- package/src/showcase/demos/DialogDemo.svelte +0 -42
- package/src/showcase/demos/InlineEditActionsDemo.svelte +0 -25
- package/src/showcase/demos/NotificationDemo.svelte +0 -147
- package/src/showcase/demos/ProgressBarDemo.svelte +0 -54
- package/src/showcase/demos/RadioButtonDemo.svelte +0 -56
- package/src/showcase/demos/SectionDividerDemo.svelte +0 -77
- package/src/showcase/demos/StandardButtonsDemo.svelte +0 -455
- package/src/showcase/demos/TabBarDemo.svelte +0 -58
- package/src/showcase/demos/TooltipDemo.svelte +0 -52
- package/src/showcase/editor.css +0 -93
- package/src/showcase/index.ts +0 -17
- package/src/styles/fonts/Domine/Domine-VariableFont_wght.ttf +0 -0
- package/src/styles/fonts/Domine/OFL.txt +0 -97
- package/src/styles/fonts/Domine/README.txt +0 -66
- /package/src/{showcase → ui}/curveEngine.ts +0 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { Migration } from './index';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Theme migration (2026-04-24): rename legacy CSS-var keys to their
|
|
5
|
+
* current names, drop a few orphaned tokens, and convert the entire
|
|
6
|
+
* `-bg`/`-bg-*` family to the `-canvas` namespace.
|
|
7
|
+
*
|
|
8
|
+
* Old themes saved before the rename keep loading; the migrated bag flows
|
|
9
|
+
* through the normal domain routing.
|
|
10
|
+
*/
|
|
11
|
+
const LEGACY_KEY_RENAMES: Record<string, string | null> = {
|
|
12
|
+
'--empty': '--page-bg',
|
|
13
|
+
'--empty-attachment': '--page-bg-attachment',
|
|
14
|
+
// Orphan exports dropped from tokens.css; no new home — silently discard.
|
|
15
|
+
'--border-neutral': null,
|
|
16
|
+
// Shadow cleanup: these five tokens were removed (low/zero consumers,
|
|
17
|
+
// aesthetic drift). Dialog migrated onto --shadow-2xl; focus rings moved
|
|
18
|
+
// to their own --ring-focus-* namespace, which themes don't carry by
|
|
19
|
+
// default — tokens.css provides the canonical values.
|
|
20
|
+
'--shadow-app': null,
|
|
21
|
+
'--shadow-card': null,
|
|
22
|
+
'--shadow-overlay': null,
|
|
23
|
+
'--shadow-focus': null,
|
|
24
|
+
'--shadow-glow-green': null,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// bg → canvas: rename every key in the --color-bg-*, --surface-bg(-*)?,
|
|
28
|
+
// --border-bg(-*)?, --text-bg(-*)? families to their canvas equivalents.
|
|
29
|
+
// Pattern match (rather than static entries in LEGACY_KEY_RENAMES) because
|
|
30
|
+
// the families carry ~28 keys between them and listing each is noise.
|
|
31
|
+
const BG_TO_CANVAS_PREFIXES = ['--color-bg-', '--surface-bg', '--border-bg', '--text-bg'] as const;
|
|
32
|
+
|
|
33
|
+
function migrateBgToCanvas(rawVars: Record<string, string>): void {
|
|
34
|
+
for (const oldKey of Object.keys(rawVars)) {
|
|
35
|
+
for (const prefix of BG_TO_CANVAS_PREFIXES) {
|
|
36
|
+
if (!oldKey.startsWith(prefix)) continue;
|
|
37
|
+
// Only the -bg boundary should swap; don't accidentally rename
|
|
38
|
+
// --text-bgthing or similar.
|
|
39
|
+
const suffix = oldKey.slice(prefix.length);
|
|
40
|
+
if (suffix && !suffix.startsWith('-')) continue;
|
|
41
|
+
const newKey = prefix.replace('-bg', '-canvas') + suffix;
|
|
42
|
+
if (newKey === oldKey) continue;
|
|
43
|
+
const value = rawVars[oldKey];
|
|
44
|
+
delete rawVars[oldKey];
|
|
45
|
+
if (!(newKey in rawVars)) rawVars[newKey] = value;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function migrateLegacyKeys(rawVars: Record<string, string>): void {
|
|
52
|
+
for (const [oldKey, newKey] of Object.entries(LEGACY_KEY_RENAMES)) {
|
|
53
|
+
if (!(oldKey in rawVars)) continue;
|
|
54
|
+
const value = rawVars[oldKey];
|
|
55
|
+
delete rawVars[oldKey];
|
|
56
|
+
if (newKey && !(newKey in rawVars)) rawVars[newKey] = value;
|
|
57
|
+
}
|
|
58
|
+
migrateBgToCanvas(rawVars);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const themeMigration_2026_04_24_legacyKeysAndBgToCanvas: Migration = {
|
|
62
|
+
id: '2026-04-24-legacy-keys-and-bg-to-canvas',
|
|
63
|
+
fromVersion: 0,
|
|
64
|
+
toVersion: 1,
|
|
65
|
+
appliesTo: 'theme',
|
|
66
|
+
apply(rawVars) {
|
|
67
|
+
const out = { ...rawVars };
|
|
68
|
+
migrateLegacyKeys(out);
|
|
69
|
+
return out;
|
|
70
|
+
},
|
|
71
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Migration } from './index';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Component-config migration (2026-04-27, segmentedcontrol only): the
|
|
5
|
+
* disabled component state used to be modeled as an interaction state on
|
|
6
|
+
* the default option (`--segmentedcontrol-option-disabled-*`); it's now
|
|
7
|
+
* its own top-level component state (`--segmentedcontrol-disabled-*`).
|
|
8
|
+
*
|
|
9
|
+
* Selected-disabled was briefly introduced as a state then removed — a
|
|
10
|
+
* disabled control can't have a selected option. Selected-hover was also
|
|
11
|
+
* briefly introduced then removed when the editor flattened to a single
|
|
12
|
+
* 4-state list (default/selected/hover/disabled); the selected pill now
|
|
13
|
+
* looks the same regardless of pointer state. Drop the legacy keys on load.
|
|
14
|
+
*/
|
|
15
|
+
const OPTION_DISABLED_PREFIX = '--segmentedcontrol-option-disabled-';
|
|
16
|
+
const DISABLED_PREFIX = '--segmentedcontrol-disabled-';
|
|
17
|
+
const SELECTED_DISABLED_PREFIX = '--segmentedcontrol-selected-disabled-';
|
|
18
|
+
const SELECTED_HOVER_PREFIX = '--segmentedcontrol-selected-hover-';
|
|
19
|
+
|
|
20
|
+
export const componentMigration_2026_04_27_segmentedcontrolDisabledFlatten: Migration = {
|
|
21
|
+
id: '2026-04-27-segmentedcontrol-disabled-flatten',
|
|
22
|
+
fromVersion: 1,
|
|
23
|
+
toVersion: 2,
|
|
24
|
+
appliesTo: 'component-config',
|
|
25
|
+
apply(rawVars, meta) {
|
|
26
|
+
if (meta.component !== 'segmentedcontrol') return { ...rawVars };
|
|
27
|
+
const out: Record<string, string> = {};
|
|
28
|
+
for (const [oldKey, value] of Object.entries(rawVars)) {
|
|
29
|
+
let key = oldKey;
|
|
30
|
+
// Drop short-lived selected-disabled tokens (impossible state).
|
|
31
|
+
if (key.startsWith(SELECTED_DISABLED_PREFIX)) continue;
|
|
32
|
+
// Drop short-lived selected-hover tokens (selected pill no longer has
|
|
33
|
+
// a hover variation).
|
|
34
|
+
if (key.startsWith(SELECTED_HOVER_PREFIX)) continue;
|
|
35
|
+
// Move option-disabled-* tokens to disabled-* (component-state level).
|
|
36
|
+
if (key.startsWith(OPTION_DISABLED_PREFIX)) {
|
|
37
|
+
key = DISABLED_PREFIX + key.slice(OPTION_DISABLED_PREFIX.length);
|
|
38
|
+
}
|
|
39
|
+
if (!(key in out)) out[key] = value;
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
},
|
|
43
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Migration } from './index';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Component-config migration (2026-05-08, collapsiblesection only):
|
|
5
|
+
* variant chrome was reorganised so each variant only owns the tokens it can
|
|
6
|
+
* actually paint. Three changes:
|
|
7
|
+
*
|
|
8
|
+
* 1. Container's outer chrome moved into a single `frame` group. The old
|
|
9
|
+
* default-state border / border-width / radius drove header chrome at v3;
|
|
10
|
+
* they now drive the always-on frame instead. We copy those values across
|
|
11
|
+
* so users keep their tuned border / radius. Surface is also copied so the
|
|
12
|
+
* box's background reads identically — the header strip can still be tinted
|
|
13
|
+
* on hover via the surviving default-surface.
|
|
14
|
+
*
|
|
15
|
+
* 2. Per-state border tokens that no longer paint anything are dropped:
|
|
16
|
+
* - chromeless border / border-width / radius for every state
|
|
17
|
+
* - container hover/active border / border-width / radius
|
|
18
|
+
* - divider radius for every state (divider keeps border / border-width
|
|
19
|
+
* since they paint the bottom rule per state)
|
|
20
|
+
*
|
|
21
|
+
* 3. The expanded panel only carries padding (chromeless/divider) or
|
|
22
|
+
* surface + padding (container). Drop the rest.
|
|
23
|
+
*/
|
|
24
|
+
const PFX = '--collapsiblesection-';
|
|
25
|
+
|
|
26
|
+
export const componentMigration_2026_05_08_collapsiblesectionFrameAndCleanup: Migration = {
|
|
27
|
+
id: '2026-05-08-collapsiblesection-frame-and-cleanup',
|
|
28
|
+
fromVersion: 3,
|
|
29
|
+
toVersion: 4,
|
|
30
|
+
appliesTo: 'component-config',
|
|
31
|
+
apply(rawVars, meta) {
|
|
32
|
+
if (meta.component !== 'collapsiblesection') return { ...rawVars };
|
|
33
|
+
const out: Record<string, string> = {};
|
|
34
|
+
|
|
35
|
+
// First pass: seed container-frame-* from container-default-* so user
|
|
36
|
+
// values for the (former-header, now-frame) chrome are preserved.
|
|
37
|
+
for (const prop of ['surface', 'border', 'border-width', 'radius'] as const) {
|
|
38
|
+
const src = `${PFX}container-default-${prop}`;
|
|
39
|
+
if (src in rawVars) {
|
|
40
|
+
out[`${PFX}container-frame-${prop}`] = rawVars[src];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
45
|
+
// Drop chromeless per-state border / border-width / radius (no chrome).
|
|
46
|
+
if (/^--collapsiblesection-chromeless-(default|hover|active)-(border|border-width|radius)$/.test(key)) continue;
|
|
47
|
+
|
|
48
|
+
// Drop container hover/active border / border-width / radius (frame owns these now).
|
|
49
|
+
if (/^--collapsiblesection-container-(hover|active)-(border|border-width|radius)$/.test(key)) continue;
|
|
50
|
+
|
|
51
|
+
// Drop container default-state border / border-width / radius (already
|
|
52
|
+
// copied above into frame-*; the header strip no longer paints them).
|
|
53
|
+
if (/^--collapsiblesection-container-default-(border|border-width|radius)$/.test(key)) continue;
|
|
54
|
+
|
|
55
|
+
// Drop divider per-state radius (divider has no rounded corners).
|
|
56
|
+
if (/^--collapsiblesection-divider-(default|hover|active)-radius$/.test(key)) continue;
|
|
57
|
+
|
|
58
|
+
// Drop expanded border / border-width / radius for every variant.
|
|
59
|
+
if (/^--collapsiblesection-(chromeless|divider|container)-expanded-(border|border-width|radius)$/.test(key)) continue;
|
|
60
|
+
|
|
61
|
+
// Drop expanded surface for chromeless / divider (only container keeps it).
|
|
62
|
+
if (/^--collapsiblesection-(chromeless|divider)-expanded-surface$/.test(key)) continue;
|
|
63
|
+
|
|
64
|
+
if (!(key in out)) out[key] = value;
|
|
65
|
+
}
|
|
66
|
+
return out;
|
|
67
|
+
},
|
|
68
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Migration } from './index';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Component-config migration (2026-05-08, collapsiblesection only): the
|
|
5
|
+
* component grew Cloudscape-style variants (chromeless / divider / container).
|
|
6
|
+
* Existing tokens were unscoped — `--collapsiblesection-{state}-*` and
|
|
7
|
+
* `--collapsiblesection-expanded-*`. They map onto the new `container` variant
|
|
8
|
+
* since that preserves the previous chromed appearance; chromeless and divider
|
|
9
|
+
* fall through to the component's CSS defaults.
|
|
10
|
+
*/
|
|
11
|
+
const PREFIX = '--collapsiblesection-';
|
|
12
|
+
const STATE_NAMES = new Set(['default', 'hover', 'active', 'expanded']);
|
|
13
|
+
|
|
14
|
+
export const componentMigration_2026_05_08_collapsiblesectionVariantNamespace: Migration = {
|
|
15
|
+
id: '2026-05-08-collapsiblesection-variant-namespace',
|
|
16
|
+
fromVersion: 2,
|
|
17
|
+
toVersion: 3,
|
|
18
|
+
appliesTo: 'component-config',
|
|
19
|
+
apply(rawVars, meta) {
|
|
20
|
+
if (meta.component !== 'collapsiblesection') return { ...rawVars };
|
|
21
|
+
const out: Record<string, string> = {};
|
|
22
|
+
for (const [oldKey, value] of Object.entries(rawVars)) {
|
|
23
|
+
let key = oldKey;
|
|
24
|
+
if (key.startsWith(PREFIX)) {
|
|
25
|
+
const tail = key.slice(PREFIX.length);
|
|
26
|
+
const firstSegment = tail.split('-', 1)[0];
|
|
27
|
+
if (STATE_NAMES.has(firstSegment)) {
|
|
28
|
+
key = `${PREFIX}container-${tail}`;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (!(key in out)) out[key] = value;
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
},
|
|
35
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Migration } from './index';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Component-config migration (2026-05-10, sectiondivider only):
|
|
5
|
+
* the per-variant gradient was 4 fixed-position color stops with a hard-coded
|
|
6
|
+
* 135deg angle. It now exposes angle + 3× (color + position). User-tuned colors
|
|
7
|
+
* from the old stops are preserved (1 → 1-color, 2 → 2-color, 4 → 3-color);
|
|
8
|
+
* stop 3's color is dropped because the new shape only has three slots.
|
|
9
|
+
* Angle defaults to 135deg and positions to 0%/50%/100% — the same effect the
|
|
10
|
+
* old hard-coded `linear-gradient(135deg, ... 0%, ... 30%, ... 60%, ... 100%)`
|
|
11
|
+
* approximated.
|
|
12
|
+
*/
|
|
13
|
+
const PFX = '--sectiondivider-';
|
|
14
|
+
const VARIANTS = ['canvas', 'neutral', 'alternate', 'primary', 'accent', 'special'] as const;
|
|
15
|
+
const OLD_STOP_RE = /^--sectiondivider-(canvas|neutral|alternate|primary|accent|special)-gradient-stop-\d+$/;
|
|
16
|
+
|
|
17
|
+
export const componentMigration_2026_05_10_sectiondividerGradientStops: Migration = {
|
|
18
|
+
id: '2026-05-10-sectiondivider-gradient-stops',
|
|
19
|
+
fromVersion: 4,
|
|
20
|
+
toVersion: 5,
|
|
21
|
+
appliesTo: 'component-config',
|
|
22
|
+
apply(rawVars, meta) {
|
|
23
|
+
if (meta.component !== 'sectiondivider') return { ...rawVars };
|
|
24
|
+
const out: Record<string, string> = {};
|
|
25
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
26
|
+
if (OLD_STOP_RE.test(key)) continue;
|
|
27
|
+
out[key] = value;
|
|
28
|
+
}
|
|
29
|
+
// Idempotent: only fill in keys that the file doesn't already carry.
|
|
30
|
+
// `default.json` is unstamped (v0) and re-runs every load, so seeding
|
|
31
|
+
// unconditionally would clobber user-tuned values on configs already on
|
|
32
|
+
// the new shape.
|
|
33
|
+
const setIfMissing = (key: string, fallback: string) => {
|
|
34
|
+
if (!(key in out)) out[key] = fallback;
|
|
35
|
+
};
|
|
36
|
+
for (const v of VARIANTS) {
|
|
37
|
+
const old1 = rawVars[`${PFX}${v}-gradient-stop-1`];
|
|
38
|
+
const old2 = rawVars[`${PFX}${v}-gradient-stop-2`];
|
|
39
|
+
const old4 = rawVars[`${PFX}${v}-gradient-stop-4`];
|
|
40
|
+
setIfMissing(`${PFX}${v}-gradient-angle`, '--gradient-angle-diagonal');
|
|
41
|
+
setIfMissing(`${PFX}${v}-gradient-stop-1-color`, old1 ?? `--surface-${v}-highest`);
|
|
42
|
+
setIfMissing(`${PFX}${v}-gradient-stop-1-position`, '--gradient-stop-start');
|
|
43
|
+
setIfMissing(`${PFX}${v}-gradient-stop-2-color`, old2 ?? `--surface-${v}-higher`);
|
|
44
|
+
setIfMissing(`${PFX}${v}-gradient-stop-2-position`, '--gradient-stop-mid');
|
|
45
|
+
setIfMissing(`${PFX}${v}-gradient-stop-3-color`, old4 ?? `--surface-${v}`);
|
|
46
|
+
setIfMissing(`${PFX}${v}-gradient-stop-3-position`, '--gradient-stop-end');
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
},
|
|
50
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { Migration } from './index';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 2026-05-13: rename the `primary` color family to `brand`.
|
|
5
|
+
*
|
|
6
|
+
* The word "primary" was overloaded — both a color-family slot (alongside
|
|
7
|
+
* info/success/danger/etc.) AND the top of the neutral text-emphasis ramp
|
|
8
|
+
* (`--text-primary` / `--text-secondary` / `--text-tertiary`). Tokens like
|
|
9
|
+
* `--text-primary-color` only existed because `--text-primary` was already
|
|
10
|
+
* taken by neutral. Renaming the family to `brand` dissolves the collision:
|
|
11
|
+
*
|
|
12
|
+
* --color-primary-{step} → --color-brand-{step}
|
|
13
|
+
* --surface-primary[-step] → --surface-brand[-step]
|
|
14
|
+
* --border-primary[-step] → --border-brand[-step]
|
|
15
|
+
* --text-primary-color → --text-brand
|
|
16
|
+
* --text-primary-{step} → --text-brand-{step} (step in secondary|tertiary|muted|disabled)
|
|
17
|
+
*
|
|
18
|
+
* The neutral text ramp (`--text-primary`, `--text-secondary`, …) is **left
|
|
19
|
+
* untouched** — it's a different namespace that just happens to share the
|
|
20
|
+
* word. The match list below enumerates the brand-family names explicitly so
|
|
21
|
+
* a substring-on-`primary` mistake can't clobber neutral text or unrelated
|
|
22
|
+
* tokens like `--button-primary-*` (component variant, not family).
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const PALETTE_STEPS = ['100','200','300','400','500','600','700','800','850','900','950'] as const;
|
|
26
|
+
const SURFACE_SUFFIXES = ['lowest','lower','low','high','higher','highest'] as const;
|
|
27
|
+
const BORDER_SUFFIXES = ['faint','subtle','medium','strong'] as const;
|
|
28
|
+
const TEXT_SUFFIXES = ['secondary','tertiary','muted','disabled'] as const;
|
|
29
|
+
|
|
30
|
+
const RENAME_MAP: Record<string, string> = (() => {
|
|
31
|
+
const m: Record<string, string> = {};
|
|
32
|
+
for (const step of PALETTE_STEPS) m[`--color-primary-${step}`] = `--color-brand-${step}`;
|
|
33
|
+
m['--surface-primary'] = '--surface-brand';
|
|
34
|
+
for (const suf of SURFACE_SUFFIXES) m[`--surface-primary-${suf}`] = `--surface-brand-${suf}`;
|
|
35
|
+
m['--border-primary'] = '--border-brand';
|
|
36
|
+
for (const suf of BORDER_SUFFIXES) m[`--border-primary-${suf}`] = `--border-brand-${suf}`;
|
|
37
|
+
m['--text-primary-color'] = '--text-brand';
|
|
38
|
+
for (const suf of TEXT_SUFFIXES) m[`--text-primary-${suf}`] = `--text-brand-${suf}`;
|
|
39
|
+
return m;
|
|
40
|
+
})();
|
|
41
|
+
|
|
42
|
+
function renameToken(name: string): string {
|
|
43
|
+
return RENAME_MAP[name] ?? name;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Rewrite keys only — used for theme cssVariables (values are hex). */
|
|
47
|
+
function renameKeys(rawVars: Record<string, string>): Record<string, string> {
|
|
48
|
+
const out: Record<string, string> = {};
|
|
49
|
+
for (const [k, v] of Object.entries(rawVars)) {
|
|
50
|
+
out[renameToken(k)] = v;
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Rewrite both keys and values — used for component-config aliases. */
|
|
56
|
+
function renameKeysAndValues(rawVars: Record<string, string>): Record<string, string> {
|
|
57
|
+
const out: Record<string, string> = {};
|
|
58
|
+
for (const [k, v] of Object.entries(rawVars)) {
|
|
59
|
+
out[renameToken(k)] = renameToken(v);
|
|
60
|
+
}
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const themeMigration_2026_05_13_primaryToBrand: Migration = {
|
|
65
|
+
id: '2026-05-13-primary-to-brand-theme',
|
|
66
|
+
fromVersion: 1,
|
|
67
|
+
toVersion: 2,
|
|
68
|
+
appliesTo: 'theme',
|
|
69
|
+
apply: renameKeys,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const componentMigration_2026_05_13_primaryToBrand: Migration = {
|
|
73
|
+
id: '2026-05-13-primary-to-brand-component',
|
|
74
|
+
fromVersion: 5,
|
|
75
|
+
toVersion: 6,
|
|
76
|
+
appliesTo: 'component-config',
|
|
77
|
+
apply: renameKeysAndValues,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Helper for loadFromFile: rename `theme.editorConfigs.Primary` → `Brand`.
|
|
82
|
+
* Lives here (with the rest of the rename) instead of in the migration
|
|
83
|
+
* framework because the framework's contract is `Record<string, string>` —
|
|
84
|
+
* editorConfigs is a structured palette-config map and can't pass through it.
|
|
85
|
+
*/
|
|
86
|
+
export function renamePrimaryPaletteKey<T>(editorConfigs: Record<string, T>): Record<string, T> {
|
|
87
|
+
if (!('Primary' in editorConfigs) || 'Brand' in editorConfigs) return editorConfigs;
|
|
88
|
+
const { Primary, ...rest } = editorConfigs;
|
|
89
|
+
return { ...rest, Brand: Primary };
|
|
90
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema-versioned migration runner.
|
|
3
|
+
*
|
|
4
|
+
* Each migration lives in its own dated file (`YYYY-MM-DD-<short-name>.ts`)
|
|
5
|
+
* and exports a `Migration` object. Saved theme / component-config files
|
|
6
|
+
* carry a `schemaVersion` stamp; on load, only migrations with
|
|
7
|
+
* `fromVersion >= file.schemaVersion` are applied — once every on-disk file
|
|
8
|
+
* is past a given version, that migration's bookkeeping is dead code and
|
|
9
|
+
* the file can be deleted.
|
|
10
|
+
*
|
|
11
|
+
* Theme and component-config have INDEPENDENT version sequences. Every
|
|
12
|
+
* theme migration steps the theme version; every component-config migration
|
|
13
|
+
* steps the component-config version. There is no shared 'both' kind.
|
|
14
|
+
*/
|
|
15
|
+
export interface MigrationMeta {
|
|
16
|
+
/** Component id when the migration runs in component-config context. */
|
|
17
|
+
component?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface Migration {
|
|
21
|
+
/** Unique identifier; convention: `YYYY-MM-DD-<short-name>`. */
|
|
22
|
+
id: string;
|
|
23
|
+
/** Pre-condition version — files at or below this are unmigrated for this step. */
|
|
24
|
+
fromVersion: number;
|
|
25
|
+
/** Post-condition version — files past this no longer need this migration. */
|
|
26
|
+
toVersion: number;
|
|
27
|
+
/** Which storage flavor this applies to. */
|
|
28
|
+
appliesTo: 'theme' | 'component-config';
|
|
29
|
+
/** Pure transform on the raw vars map. May add, remove, or rename keys. */
|
|
30
|
+
apply(rawVars: Record<string, string>, meta: MigrationMeta): Record<string, string>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
import { themeMigration_2026_04_24_legacyKeysAndBgToCanvas } from './2026-04-24-legacy-keys-and-bg-to-canvas';
|
|
34
|
+
import { componentMigration_2026_04_24_prefixAndSuffixRenames } from './2026-04-24-component-prefix-and-suffix-renames';
|
|
35
|
+
import { componentMigration_2026_04_27_segmentedcontrolDisabledFlatten } from './2026-04-27-segmentedcontrol-disabled-flatten';
|
|
36
|
+
import { componentMigration_2026_05_08_collapsiblesectionVariantNamespace } from './2026-05-08-collapsiblesection-variant-namespace';
|
|
37
|
+
import { componentMigration_2026_05_08_collapsiblesectionFrameAndCleanup } from './2026-05-08-collapsiblesection-frame-and-cleanup';
|
|
38
|
+
import { componentMigration_2026_05_10_sectiondividerGradientStops } from './2026-05-10-sectiondivider-gradient-stops';
|
|
39
|
+
import {
|
|
40
|
+
themeMigration_2026_05_13_primaryToBrand,
|
|
41
|
+
componentMigration_2026_05_13_primaryToBrand,
|
|
42
|
+
} from './2026-05-13-primary-to-brand';
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Registered migrations. Order in this array does not matter — the runner
|
|
46
|
+
* filters by `appliesTo` and sorts by `toVersion` before applying.
|
|
47
|
+
*/
|
|
48
|
+
export const MIGRATIONS: Migration[] = [
|
|
49
|
+
themeMigration_2026_04_24_legacyKeysAndBgToCanvas,
|
|
50
|
+
themeMigration_2026_05_13_primaryToBrand,
|
|
51
|
+
componentMigration_2026_04_24_prefixAndSuffixRenames,
|
|
52
|
+
componentMigration_2026_04_27_segmentedcontrolDisabledFlatten,
|
|
53
|
+
componentMigration_2026_05_08_collapsiblesectionVariantNamespace,
|
|
54
|
+
componentMigration_2026_05_08_collapsiblesectionFrameAndCleanup,
|
|
55
|
+
componentMigration_2026_05_10_sectiondividerGradientStops,
|
|
56
|
+
componentMigration_2026_05_13_primaryToBrand,
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
function countFor(kind: 'theme' | 'component-config'): number {
|
|
60
|
+
return MIGRATIONS.filter((m) => m.appliesTo === kind).length;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Current schema versions. Computed from the registered migrations so that
|
|
65
|
+
* adding a new dated migration file (and importing it above) auto-bumps the
|
|
66
|
+
* relevant constant.
|
|
67
|
+
*/
|
|
68
|
+
export const CURRENT_THEME_SCHEMA_VERSION = countFor('theme');
|
|
69
|
+
export const CURRENT_COMPONENT_SCHEMA_VERSION = countFor('component-config');
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Apply all migrations for a given kind whose fromVersion is at or above the
|
|
73
|
+
* file's stamped version. Pure: returns a new map; never mutates the input.
|
|
74
|
+
*
|
|
75
|
+
* The "fromVersion >= fileVersion" filter is what gives this its TTL: once
|
|
76
|
+
* every saved file has been resaved past version N, the migration with
|
|
77
|
+
* fromVersion=N can be deleted without affecting any load path.
|
|
78
|
+
*/
|
|
79
|
+
export function runMigrations(
|
|
80
|
+
kind: 'theme' | 'component-config',
|
|
81
|
+
fileVersion: number,
|
|
82
|
+
rawVars: Record<string, string>,
|
|
83
|
+
meta: MigrationMeta = {},
|
|
84
|
+
): Record<string, string> {
|
|
85
|
+
const applicable = MIGRATIONS
|
|
86
|
+
.filter((m) => m.appliesTo === kind && m.fromVersion >= fileVersion)
|
|
87
|
+
.sort((a, b) => a.toVersion - b.toVersion);
|
|
88
|
+
let out = { ...rawVars };
|
|
89
|
+
for (const m of applicable) {
|
|
90
|
+
out = m.apply(out, meta);
|
|
91
|
+
}
|
|
92
|
+
return out;
|
|
93
|
+
}
|