@motion-proto/live-tokens 0.3.9 → 0.6.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 (107) hide show
  1. package/README.md +47 -4
  2. package/package.json +18 -12
  3. package/src/component-editor/BadgeEditor.svelte +24 -22
  4. package/src/component-editor/CalloutEditor.svelte +3 -3
  5. package/src/component-editor/CardEditor.svelte +25 -21
  6. package/src/component-editor/CollapsibleSectionEditor.svelte +27 -25
  7. package/src/component-editor/CornerBadgeEditor.svelte +37 -35
  8. package/src/component-editor/DialogEditor.svelte +26 -24
  9. package/src/component-editor/ImageEditor.svelte +11 -9
  10. package/src/component-editor/InlineEditActionsEditor.svelte +17 -15
  11. package/src/component-editor/NotificationEditor.svelte +32 -30
  12. package/src/component-editor/ProgressBarEditor.svelte +3 -3
  13. package/src/component-editor/RadioButtonEditor.svelte +31 -29
  14. package/src/component-editor/SectionDividerEditor.svelte +30 -28
  15. package/src/component-editor/SegmentedControlEditor.svelte +29 -25
  16. package/src/component-editor/StandardButtonsEditor.svelte +42 -38
  17. package/src/component-editor/TabBarEditor.svelte +20 -18
  18. package/src/component-editor/TableEditor.svelte +4 -4
  19. package/src/component-editor/TooltipEditor.svelte +11 -9
  20. package/src/component-editor/registry.ts +2 -2
  21. package/src/component-editor/scaffolding/AngleDial.svelte +20 -19
  22. package/src/component-editor/scaffolding/ComponentEditorBase.svelte +44 -20
  23. package/src/component-editor/scaffolding/ComponentFileManager.svelte +262 -38
  24. package/src/component-editor/scaffolding/ComponentFileMenu.svelte +41 -29
  25. package/src/component-editor/scaffolding/ComponentsTab.svelte +7 -3
  26. package/src/component-editor/scaffolding/CopyFromMenu.svelte +21 -12
  27. package/src/component-editor/scaffolding/DemoHeader.svelte +13 -4
  28. package/src/component-editor/scaffolding/DividerEditor.svelte +27 -14
  29. package/src/component-editor/scaffolding/FieldsetWrapper.svelte +10 -4
  30. package/src/component-editor/scaffolding/GradientCard.svelte +25 -20
  31. package/src/component-editor/scaffolding/LinkageChart.svelte +43 -34
  32. package/src/component-editor/scaffolding/LinkedBlock.svelte +24 -21
  33. package/src/component-editor/scaffolding/NonStylableConfig.svelte +6 -1
  34. package/src/component-editor/scaffolding/SaveAsDialog.svelte +39 -35
  35. package/src/component-editor/scaffolding/ShadowBackdrop.svelte +21 -9
  36. package/src/component-editor/scaffolding/ShadowBackdropControls.svelte +8 -3
  37. package/src/component-editor/scaffolding/StateBlock.svelte +30 -13
  38. package/src/component-editor/scaffolding/TokenLayout.svelte +46 -30
  39. package/src/component-editor/scaffolding/TypeEditor.svelte +52 -26
  40. package/src/component-editor/scaffolding/VariantGroup.svelte +81 -48
  41. package/src/component-editor/scaffolding/componentSectionType.ts +2 -2
  42. package/src/components/Badge.svelte +45 -26
  43. package/src/components/Button.svelte +44 -21
  44. package/src/components/Callout.svelte +17 -12
  45. package/src/components/Card.svelte +23 -11
  46. package/src/components/CollapsibleSection.svelte +56 -27
  47. package/src/components/CornerBadge.svelte +32 -18
  48. package/src/components/Dialog.svelte +55 -31
  49. package/src/components/Image.svelte +14 -5
  50. package/src/components/InlineEditActions.svelte +22 -10
  51. package/src/components/Notification.svelte +39 -19
  52. package/src/components/ProgressBar.svelte +27 -17
  53. package/src/components/RadioButton.svelte +27 -10
  54. package/src/components/SectionDivider.svelte +34 -26
  55. package/src/components/SegmentedControl.svelte +23 -9
  56. package/src/components/TabBar.svelte +23 -10
  57. package/src/components/Table.svelte +8 -3
  58. package/src/components/Tooltip.svelte +15 -5
  59. package/src/lib/ColumnsOverlay.svelte +3 -3
  60. package/src/lib/LiveEditorOverlay.svelte +57 -36
  61. package/src/pages/ComponentEditorPage.svelte +25 -14
  62. package/src/pages/Editor.svelte +8 -2
  63. package/src/pages/EditorShell.svelte +24 -20
  64. package/src/styles/site.css +138 -0
  65. package/src/styles/tokens.css +78 -76
  66. package/src/styles/ui-form-controls.css +186 -0
  67. package/src/ui/BezierCurveEditor.svelte +59 -43
  68. package/src/ui/ColorEditPanel.svelte +71 -44
  69. package/src/ui/EditorViewSwitcher.svelte +9 -5
  70. package/src/ui/FontStackEditor.svelte +17 -16
  71. package/src/ui/GradientEditor.svelte +42 -33
  72. package/src/ui/GradientStopPicker.svelte +18 -29
  73. package/src/ui/PaletteEditor.svelte +238 -212
  74. package/src/ui/PresetFileManager.svelte +20 -18
  75. package/src/ui/ProjectFontsSection.svelte +34 -34
  76. package/src/ui/SurfacesTab.svelte +3 -3
  77. package/src/ui/TextTab.svelte +2 -2
  78. package/src/ui/ThemeFileManager.svelte +38 -35
  79. package/src/ui/Toggle.svelte +11 -9
  80. package/src/ui/UICopyPopover.svelte +19 -15
  81. package/src/ui/UIDialog.svelte +48 -30
  82. package/src/ui/UIFontFamilySelector.svelte +104 -78
  83. package/src/ui/UIFontSizeSelector.svelte +38 -20
  84. package/src/ui/UIFontWeightSelector.svelte +33 -13
  85. package/src/ui/UILineHeightSelector.svelte +33 -13
  86. package/src/ui/UILinkToggle.svelte +7 -6
  87. package/src/ui/UIOptionItem.svelte +21 -7
  88. package/src/ui/UIOptionList.svelte +9 -3
  89. package/src/ui/UIPaddingSelector.svelte +108 -82
  90. package/src/ui/UIPaletteSelector.svelte +186 -161
  91. package/src/ui/UIRadio.svelte +23 -8
  92. package/src/ui/UIRadioGroup.svelte +9 -8
  93. package/src/ui/UIRelinkConfirmPopover.svelte +26 -16
  94. package/src/ui/UITokenSelector.svelte +112 -68
  95. package/src/ui/UIVariantSelector.svelte +79 -57
  96. package/src/ui/VariablesTab.svelte +15 -15
  97. package/src/ui/palette/GradientStopEditor.svelte +45 -26
  98. package/src/ui/palette/OverridesPanel.svelte +85 -49
  99. package/src/ui/palette/PaletteBase.svelte +60 -32
  100. package/src/ui/palette/ScaleCurveEditor.svelte +25 -10
  101. package/src/ui/sections/ColumnsSection.svelte +13 -13
  102. package/src/ui/sections/GradientsSection.svelte +12 -9
  103. package/src/ui/sections/OverlaysSection.svelte +50 -47
  104. package/src/ui/sections/ShadowsSection.svelte +110 -104
  105. package/src/ui/sections/TokenScaleTable.svelte +38 -22
  106. package/src/ui/sections/tokenScales.ts +2 -2
  107. package/src/styles/form-controls.css +0 -188
package/README.md CHANGED
@@ -127,13 +127,56 @@ The components carry their own design-token aliases (declared inside each `.svel
127
127
 
128
128
  ### Styles
129
129
 
130
+ Editor chrome (`ui-editor.css`, `ui-form-controls.css`) and the icon font are
131
+ **auto-loaded by the editor pages themselves**; you don't import them. The
132
+ only stylesheet a consumer needs is a `tokens.css` declaring the design-token
133
+ CSS variables on `:root`.
134
+
135
+ You can use the package's default as a starting point:
136
+
137
+ ```ts
138
+ import '@motion-proto/live-tokens/starter/tokens.css';
139
+ import '@motion-proto/live-tokens/starter/site.css'; // optional: themed h1/p/a styles
140
+ import '@motion-proto/live-tokens/starter/fonts.css'; // optional: Fraunces + Manrope @font-face
141
+ ```
142
+
143
+ …or copy `node_modules/@motion-proto/live-tokens/src/styles/tokens.css` into
144
+ your project and edit. The editor will seed `themes/default.json` on first
145
+ run and you can promote your edits back into the file.
146
+
147
+ ## Consuming live-tokens from scratch
148
+
149
+ The minimum a consumer needs after `npm install @motion-proto/live-tokens`:
150
+
151
+ ```ts
152
+ // src/main.ts
153
+ import '@motion-proto/live-tokens/starter/tokens.css';
154
+ import { mount } from 'svelte';
155
+ import App from './App.svelte';
156
+
157
+ mount(App, { target: document.getElementById('app')! });
158
+ ```
159
+
160
+ ```svelte
161
+ <!-- src/App.svelte -->
162
+ <script lang="ts">
163
+ import Editor from '@motion-proto/live-tokens/editor';
164
+ </script>
165
+
166
+ <Editor />
167
+ ```
168
+
130
169
  ```ts
131
- import '@motion-proto/live-tokens/styles/ui-editor.css';
132
- import '@motion-proto/live-tokens/styles/form-controls.css';
133
- import '@motion-proto/live-tokens/styles/fonts.css';
170
+ // vite.config.ts
171
+ import { defineConfig } from 'vite';
172
+ import { svelte } from '@sveltejs/vite-plugin-svelte';
173
+
174
+ export default defineConfig({
175
+ plugins: [svelte()],
176
+ });
134
177
  ```
135
178
 
136
- You'll also need your own `src/styles/tokens.css` declaring your design tokens as CSS variables on `:root`. Start from the package's default (`node_modules/@motion-proto/live-tokens/src/styles/tokens.css`) and overlay your overrides or let the editor seed `themes/default.json` on first run and promote it.
179
+ No `css: 'injected'` workaround, no `optimizeDeps` excludes `vite build` works as-is. (You'll want the full `themeFileApi` plugin from the Quick install section above when you're ready to persist edits to disk.)
137
180
 
138
181
  ## Greenfield? Use the starter
139
182
 
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@motion-proto/live-tokens",
3
- "version": "0.3.9",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
- "description": "Design token editor with live CSS variable editing. Svelte 4/5 + Vite 5/6/7.",
5
+ "description": "Design token editor with live CSS variable editing. Svelte 5 + Vite 6/7.",
6
6
  "keywords": [
7
7
  "svelte",
8
8
  "vite",
@@ -11,6 +11,7 @@
11
11
  "editor"
12
12
  ],
13
13
  "license": "MIT",
14
+ "author": "Mark Pearce <mark@motionproto.com>",
14
15
  "repository": {
15
16
  "type": "git",
16
17
  "url": "git+https://github.com/motionproto/live-tokens.git"
@@ -28,11 +29,12 @@
28
29
  "src/pages/ComponentEditorPage.svelte",
29
30
  "src/pages/ComponentEditorPage.svelte.d.ts",
30
31
  "src/styles/ui-editor.css",
31
- "src/styles/form-controls.css",
32
+ "src/styles/ui-form-controls.css",
32
33
  "src/styles/fonts.css",
33
34
  "src/styles/fonts",
34
35
  "src/styles/_padding.scss",
35
36
  "src/styles/tokens.css",
37
+ "src/styles/site.css",
36
38
  "src/data",
37
39
  "src/assets",
38
40
  "dist-plugin",
@@ -76,8 +78,9 @@
76
78
  "require": "./dist-plugin/index.cjs"
77
79
  },
78
80
  "./styles/ui-editor.css": "./src/styles/ui-editor.css",
79
- "./styles/form-controls.css": "./src/styles/form-controls.css",
80
- "./styles/fonts.css": "./src/styles/fonts.css"
81
+ "./starter/tokens.css": "./src/styles/tokens.css",
82
+ "./starter/site.css": "./src/styles/site.css",
83
+ "./starter/fonts.css": "./src/styles/fonts.css"
81
84
  },
82
85
  "scripts": {
83
86
  "dev": "vite",
@@ -89,26 +92,29 @@
89
92
  "build:plugin": "tsup src/vite-plugin/index.ts --out-dir dist-plugin --format esm,cjs --dts --external vite --platform node --clean",
90
93
  "build:lib": "npm run build:plugin",
91
94
  "deploy:local": "bash scripts/deploy-local.sh",
92
- "prepublishOnly": "npm run build:lib"
95
+ "check:no-style-imports": "node scripts/check-no-style-imports.mjs",
96
+ "check:editor-font-isolation": "node scripts/check-editor-font-isolation.mjs",
97
+ "check:smoke-install": "bash scripts/smoke-install.sh",
98
+ "prepublishOnly": "npm run check:no-style-imports && npm run check:editor-font-isolation && npm run build:lib && npm run check:smoke-install"
93
99
  },
94
100
  "peerDependencies": {
95
101
  "sass": "^1.0",
96
- "svelte": "^4.2 || ^5",
102
+ "svelte": "^5",
97
103
  "svelte-preprocess": "^6.0",
98
- "vite": "^5 || ^6 || ^7"
104
+ "vite": "^6 || ^7"
99
105
  },
100
106
  "devDependencies": {
101
- "@sveltejs/vite-plugin-svelte": "^3.1.2",
107
+ "@sveltejs/vite-plugin-svelte": "^6.2.4",
102
108
  "@tsconfig/svelte": "^5.0.8",
103
109
  "@types/node": "^24.12.0",
104
110
  "happy-dom": "^20.9.0",
105
111
  "sass": "^1.98.0",
106
- "svelte": "^4.2.20",
107
- "svelte-check": "^3.8.6",
112
+ "svelte": "^5.55.5",
113
+ "svelte-check": "^4.4.8",
108
114
  "svelte-preprocess": "^6.0.3",
109
115
  "tsup": "^8.5.1",
110
116
  "typescript": "~5.9.3",
111
- "vite": "^5.4.21",
117
+ "vite": "^7.3.3",
112
118
  "vitest": "^4.1.4"
113
119
  },
114
120
  "dependencies": {
@@ -1,4 +1,4 @@
1
- <script context="module" lang="ts">
1
+ <script module lang="ts">
2
2
  import { buildTypeGroupColorTokens } from './scaffolding/buildTypeGroupTokens';
3
3
  import type { Token, TypeGroupConfig } from './scaffolding/types';
4
4
  import { badgeVariants } from '../components/Badge.svelte';
@@ -69,18 +69,18 @@
69
69
  import ShadowBackdropControls from './scaffolding/ShadowBackdropControls.svelte';
70
70
  import UIRadioGroup from '../ui/UIRadioGroup.svelte';
71
71
 
72
- $: linked = computeLinkedBlock(component, linkableContexts, allTokens, $editorState);
73
- $: visibleVariantTokens = (v: Variant) => withLinkedDisabled(variantTokens(v), linked.varSet);
72
+ let linked = $derived(computeLinkedBlock(component, linkableContexts, allTokens, $editorState));
73
+ let visibleVariantTokens = $derived((v: Variant) => withLinkedDisabled(variantTokens(v), linked.varSet));
74
74
 
75
- let bgMode: 'image' | 'color' = 'image';
75
+ let bgMode: 'image' | 'color' = $state('image');
76
76
  const bgVar = '--backdrop-badge-surface';
77
77
 
78
78
  // Preview-only props for Badge's floating/anchor/flush features (not persisted).
79
79
  // For corner-anchored use, prefer the dedicated CornerBadge component; Badge.floating
80
80
  // is the low-level escape hatch for off-corner floating placements.
81
- let floating: boolean = false;
82
- let flush: boolean = false;
83
- let anchor: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' = 'bottom-right';
81
+ let floating: boolean = $state(false);
82
+ let flush: boolean = $state(false);
83
+ let anchor: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' = $state('bottom-right');
84
84
  const anchorOptions = [
85
85
  { value: 'top-left' as const, label: 'TL' },
86
86
  { value: 'top-right' as const, label: 'TR' },
@@ -90,23 +90,25 @@
90
90
  </script>
91
91
 
92
92
  <ComponentEditorBase {component} title="Badge" description="Pill-shaped badges with color variants. Import from <code>components/Badge.svelte</code>" tokens={allTokens} {linked} variants={variantOptions}>
93
- <svelte:fragment slot="config">
94
- <ShadowBackdropControls bind:mode={bgMode} colorVariable={bgVar} />
95
- <label class="float-toggle">
96
- <input type="checkbox" bind:checked={floating} />
97
- <span>Floating preview</span>
98
- </label>
99
- {#if floating}
93
+ {#snippet config()}
94
+
95
+ <ShadowBackdropControls bind:mode={bgMode} colorVariable={bgVar} />
100
96
  <label class="float-toggle">
101
- <input type="checkbox" bind:checked={flush} />
102
- <span>Flush corner</span>
97
+ <input type="checkbox" bind:checked={floating} />
98
+ <span>Floating preview</span>
103
99
  </label>
104
- <div class="anchor-control">
105
- <span>Anchor</span>
106
- <UIRadioGroup bind:value={anchor} name="badge-anchor" options={anchorOptions} />
107
- </div>
108
- {/if}
109
- </svelte:fragment>
100
+ {#if floating}
101
+ <label class="float-toggle">
102
+ <input type="checkbox" bind:checked={flush} />
103
+ <span>Flush corner</span>
104
+ </label>
105
+ <div class="anchor-control">
106
+ <span>Anchor</span>
107
+ <UIRadioGroup bind:value={anchor} name="badge-anchor" options={anchorOptions} />
108
+ </div>
109
+ {/if}
110
+
111
+ {/snippet}
110
112
  {#each variants as v}
111
113
  <VariantGroup
112
114
  name={v}
@@ -1,4 +1,4 @@
1
- <script context="module" lang="ts">
1
+ <script module lang="ts">
2
2
  import { buildTypeGroupColorTokens } from './scaffolding/buildTypeGroupTokens';
3
3
  import type { Token, TypeGroupConfig } from './scaffolding/types';
4
4
  import { calloutVariants } from '../components/Callout.svelte';
@@ -76,8 +76,8 @@
76
76
  import { computeLinkedBlock, withLinkedDisabled } from './scaffolding/linkedBlock';
77
77
  import { buildSiblings } from './scaffolding/siblings';
78
78
 
79
- $: linked = computeLinkedBlock(component, linkableContexts, allTokens, $editorState);
80
- $: visibleVariantTokens = (v: Variant) => withLinkedDisabled(variantTokens(v), linked.varSet);
79
+ let linked = $derived(computeLinkedBlock(component, linkableContexts, allTokens, $editorState));
80
+ let visibleVariantTokens = $derived((v: Variant) => withLinkedDisabled(variantTokens(v), linked.varSet));
81
81
 
82
82
  const sample: Record<Variant, { label: string; message: string }> = {
83
83
  info: { label: 'Note.', message: 'This is contextual information you should know about.' },
@@ -1,4 +1,4 @@
1
- <script context="module" lang="ts">
1
+ <script module lang="ts">
2
2
  import { buildTypeGroupColorTokens } from './scaffolding/buildTypeGroupTokens';
3
3
  import type { Token, TypeGroupConfig } from './scaffolding/types';
4
4
 
@@ -127,46 +127,50 @@
127
127
  import ShadowBackdrop from './scaffolding/ShadowBackdrop.svelte';
128
128
  import ShadowBackdropControls from './scaffolding/ShadowBackdropControls.svelte';
129
129
 
130
- $: linked = computeLinkedBlock(component, linkableContexts, allTokens, $editorState);
130
+ let linked = $derived(computeLinkedBlock(component, linkableContexts, allTokens, $editorState));
131
131
 
132
- $: visibleStates = Object.fromEntries(
132
+ let visibleStates = $derived(Object.fromEntries(
133
133
  Object.entries(states).map(([name, list]) => [name, withLinkedDisabled(list, linked.varSet)]),
134
- ) as Record<string, Token[]>;
134
+ ) as Record<string, Token[]>);
135
135
 
136
- let hoverEnabled = true;
137
- let bgMode: 'image' | 'color' = 'image';
136
+ let hoverEnabled = $state(true);
137
+ let bgMode: 'image' | 'color' = $state('image');
138
138
  const bgVar = '--backdrop-card-surface';
139
139
  </script>
140
140
 
141
141
  <ComponentEditorBase {component} title="Card" description="Generic card with icon, title, and slotted body. Import from <code>components/Card.svelte</code>" tokens={allTokens} {linked}>
142
- <svelte:fragment slot="config">
143
- <ShadowBackdropControls bind:mode={bgMode} colorVariable={bgVar} />
144
- </svelte:fragment>
142
+ {#snippet config()}
143
+
144
+ <ShadowBackdropControls bind:mode={bgMode} colorVariable={bgVar} />
145
+
146
+ {/snippet}
145
147
  <VariantGroup
146
148
  name="card"
147
149
  title="Card"
148
150
  states={visibleStates}
149
151
  {typeGroups}
150
152
  {component}
151
- let:activeState
153
+
152
154
  >
153
- <svelte:fragment slot="state-actions" let:stateName>
155
+ {#snippet stateActions(stateName)}
154
156
  {#if stateName === 'hover'}
155
157
  <label class="hover-enable">
156
158
  <input type="checkbox" bind:checked={hoverEnabled} />
157
159
  <span>Use hover</span>
158
160
  </label>
159
161
  {/if}
160
- </svelte:fragment>
161
- {@const previewClass = activeState === 'hover' ? 'force-hover' : (hoverEnabled ? '' : 'no-hover')}
162
- <ShadowBackdrop mode={bgMode} colorVariable={bgVar}>
163
- <div class="card-demo">
164
- <Card title="Card title" class={previewClass}>
165
- <p style="margin: 0;">Slotted body content. Hover the card (or switch the editor to the Hover state) to preview hover styling.</p>
166
- </Card>
167
- </div>
168
- </ShadowBackdrop>
169
- </VariantGroup>
162
+ {/snippet}
163
+ {#snippet children({ activeState })}
164
+ {@const previewClass = activeState === 'hover' ? 'force-hover' : (hoverEnabled ? '' : 'no-hover')}
165
+ <ShadowBackdrop mode={bgMode} colorVariable={bgVar}>
166
+ <div class="card-demo">
167
+ <Card title="Card title" class={previewClass}>
168
+ <p style="margin: 0;">Slotted body content. Hover the card (or switch the editor to the Hover state) to preview hover styling.</p>
169
+ </Card>
170
+ </div>
171
+ </ShadowBackdrop>
172
+ {/snippet}
173
+ </VariantGroup>
170
174
  </ComponentEditorBase>
171
175
 
172
176
  <style>
@@ -1,4 +1,4 @@
1
- <script context="module" lang="ts">
1
+ <script module lang="ts">
2
2
  import { buildTypeGroupColorTokens } from './scaffolding/buildTypeGroupTokens';
3
3
  import type { Token, TypeGroupConfig } from './scaffolding/types';
4
4
 
@@ -125,11 +125,11 @@
125
125
  import { editorState } from '../lib/editorStore';
126
126
  import { computeLinkedBlock, withLinkedDisabled } from './scaffolding/linkedBlock';
127
127
 
128
- $: linked = computeLinkedBlock(component, linkableContexts, allTokens, $editorState);
128
+ let linked = $derived(computeLinkedBlock(component, linkableContexts, allTokens, $editorState));
129
129
 
130
- $: visibleVariantStates = (v: Variant) => Object.fromEntries(
130
+ let visibleVariantStates = $derived((v: Variant) => Object.fromEntries(
131
131
  Object.entries(variantStates(v)).map(([name, list]) => [name, withLinkedDisabled(list, linked.varSet)]),
132
- ) as Record<string, Token[]>;
132
+ ) as Record<string, Token[]>);
133
133
  </script>
134
134
 
135
135
  <ComponentEditorBase {component} title="Collapsible Section" description="Expandable section with chevron toggle. Variants: chromeless, divider, container. Import from <code>components/CollapsibleSection.svelte</code>" tokens={allTokens} {linked} variants={variantOptions}>
@@ -141,27 +141,29 @@
141
141
  typeGroups={variantTypeGroups(v)}
142
142
  {component}
143
143
  siblings={buildSiblings(VARIANTS, v, variantStates, variantTypeGroups)}
144
- let:activeState
144
+
145
145
  >
146
- {@const isExpanded = activeState === 'expanded'}
147
- {@const isFrame = activeState === 'frame'}
148
- {@const forceClass = activeState === 'hover' ? 'force-hover' : ''}
149
- {@const forceActive = activeState === 'active'}
150
- <CollapsibleSection
151
- variant={v}
152
- label="Click to expand"
153
- expanded={isExpanded}
154
- active={forceActive}
155
- class={forceClass}
156
- >
157
- <p style="margin: 0; color: var(--text-secondary);">
158
- {#if isFrame}
159
- (Frame) — outer chrome only; expand the section to see content area styling.
160
- {:else}
161
- This content is revealed when the section is expanded. Any content can go here.
162
- {/if}
163
- </p>
164
- </CollapsibleSection>
165
- </VariantGroup>
146
+ {#snippet children({ activeState })}
147
+ {@const isExpanded = activeState === 'expanded'}
148
+ {@const isFrame = activeState === 'frame'}
149
+ {@const forceClass = activeState === 'hover' ? 'force-hover' : ''}
150
+ {@const forceActive = activeState === 'active'}
151
+ <CollapsibleSection
152
+ variant={v}
153
+ label="Click to expand"
154
+ expanded={isExpanded}
155
+ active={forceActive}
156
+ class={forceClass}
157
+ >
158
+ <p style="margin: 0; color: var(--text-secondary);">
159
+ {#if isFrame}
160
+ (Frame) — outer chrome only; expand the section to see content area styling.
161
+ {:else}
162
+ This content is revealed when the section is expanded. Any content can go here.
163
+ {/if}
164
+ </p>
165
+ </CollapsibleSection>
166
+ {/snippet}
167
+ </VariantGroup>
166
168
  {/each}
167
169
  </ComponentEditorBase>
@@ -1,4 +1,4 @@
1
- <script context="module" lang="ts">
1
+ <script module lang="ts">
2
2
  import type { Token } from './scaffolding/types';
3
3
  import { badgeVariants } from '../components/Badge.svelte';
4
4
 
@@ -65,10 +65,10 @@
65
65
  import { computeLinkedBlock, withLinkedDisabled } from './scaffolding/linkedBlock';
66
66
  import demoImageUrl from '../assets/newspaper.webp';
67
67
 
68
- $: linked = computeLinkedBlock(component, linkableContexts, allTokens, $editorState);
69
- $: visibleStates = Object.fromEntries(
68
+ let linked = $derived(computeLinkedBlock(component, linkableContexts, allTokens, $editorState));
69
+ let visibleStates = $derived(Object.fromEntries(
70
70
  badgeVariants.map((v) => [v, withLinkedDisabled(variantTokens(v), linked.varSet)]),
71
- ) as Record<string, Token[]>;
71
+ ) as Record<string, Token[]>);
72
72
 
73
73
  const bgVar = '--backdrop-cornerbadge-surface';
74
74
 
@@ -78,7 +78,7 @@
78
78
  }
79
79
  });
80
80
 
81
- let anchor: CornerAnchor = 'bottom-right';
81
+ let anchor: CornerAnchor = $state('bottom-right');
82
82
  const anchorGrid: ReadonlyArray<{ value: CornerAnchor; icon: string; label: string }> = [
83
83
  { value: 'top-left', icon: 'fas fa-arrow-up-left', label: 'Top left' },
84
84
  { value: 'top-right', icon: 'fas fa-arrow-up-right', label: 'Top right' },
@@ -86,42 +86,44 @@
86
86
  { value: 'bottom-right', icon: 'fas fa-arrow-down-right', label: 'Bottom right' },
87
87
  ];
88
88
 
89
- let variant: BadgeVariant = 'accent';
89
+ let variant: BadgeVariant = $state('accent');
90
90
  const variantOptions = badgeVariants.map((v) => ({ value: v, label: v.charAt(0).toUpperCase() + v.slice(1) }));
91
91
  </script>
92
92
 
93
93
  <ComponentEditorBase {component} title="Corner Badge" description="Badge pinned flush to a corner of a positioned ancestor. Composes <code>Badge</code>; adds offset + inner-radius tokens. Import from <code>components/CornerBadge.svelte</code>" tokens={allTokens} {linked}>
94
- <svelte:fragment slot="config">
95
- <label class="backdrop-config">
96
- <span>Sample background</span>
97
- <div class="picker-slot">
98
- <UIPaletteSelector variable={bgVar} />
94
+ {#snippet config()}
95
+
96
+ <label class="backdrop-config">
97
+ <span>Sample background</span>
98
+ <div class="picker-slot">
99
+ <UIPaletteSelector variable={bgVar} />
100
+ </div>
101
+ </label>
102
+ <div class="control-row">
103
+ <span>Anchor</span>
104
+ <div class="anchor-grid" role="radiogroup" aria-label="Corner badge anchor">
105
+ {#each anchorGrid as opt (opt.value)}
106
+ <button
107
+ type="button"
108
+ class="anchor-btn"
109
+ class:checked={anchor === opt.value}
110
+ role="radio"
111
+ aria-checked={anchor === opt.value}
112
+ aria-label={opt.label}
113
+ title={opt.label}
114
+ onclick={() => (anchor = opt.value)}
115
+ >
116
+ <i class={opt.icon} aria-hidden="true"></i>
117
+ </button>
118
+ {/each}
119
+ </div>
99
120
  </div>
100
- </label>
101
- <div class="control-row">
102
- <span>Anchor</span>
103
- <div class="anchor-grid" role="radiogroup" aria-label="Corner badge anchor">
104
- {#each anchorGrid as opt (opt.value)}
105
- <button
106
- type="button"
107
- class="anchor-btn"
108
- class:checked={anchor === opt.value}
109
- role="radio"
110
- aria-checked={anchor === opt.value}
111
- aria-label={opt.label}
112
- title={opt.label}
113
- on:click={() => (anchor = opt.value)}
114
- >
115
- <i class={opt.icon} aria-hidden="true"></i>
116
- </button>
117
- {/each}
121
+ <div class="control-row">
122
+ <span>Variant</span>
123
+ <UIRadioGroup bind:value={variant} name="corner-badge-variant" options={variantOptions} />
118
124
  </div>
119
- </div>
120
- <div class="control-row">
121
- <span>Variant</span>
122
- <UIRadioGroup bind:value={variant} name="corner-badge-variant" options={variantOptions} />
123
- </div>
124
- </svelte:fragment>
125
+
126
+ {/snippet}
125
127
  <VariantGroup name="cornerbadge" title="Corner Badge" states={visibleStates} {component}>
126
128
  <ShadowBackdrop mode="color" colorVariable={bgVar}>
127
129
  <div class="corner-stage-wrap">
@@ -1,4 +1,4 @@
1
- <script context="module" lang="ts">
1
+ <script module lang="ts">
2
2
  import { buildTypeGroupColorTokens } from './scaffolding/buildTypeGroupTokens';
3
3
  import type { Token, TypeGroupConfig } from './scaffolding/types';
4
4
 
@@ -95,9 +95,9 @@
95
95
  import ShadowBackdrop from './scaffolding/ShadowBackdrop.svelte';
96
96
  import ShadowBackdropControls from './scaffolding/ShadowBackdropControls.svelte';
97
97
 
98
- $: config = $editorState.components.dialog?.config ?? {};
99
- $: confirmVariant = (BUTTON_VARIANTS.includes(config[CONFIRM_VAR] as ButtonVariant) ? config[CONFIRM_VAR] : DEFAULT_CONFIRM) as ButtonVariant;
100
- $: cancelVariant = (BUTTON_VARIANTS.includes(config[CANCEL_VAR] as ButtonVariant) ? config[CANCEL_VAR] : DEFAULT_CANCEL) as ButtonVariant;
98
+ let config = $derived($editorState.components.dialog?.config ?? {});
99
+ let confirmVariant = $derived((BUTTON_VARIANTS.includes(config[CONFIRM_VAR] as ButtonVariant) ? config[CONFIRM_VAR] : DEFAULT_CONFIRM) as ButtonVariant);
100
+ let cancelVariant = $derived((BUTTON_VARIANTS.includes(config[CANCEL_VAR] as ButtonVariant) ? config[CANCEL_VAR] : DEFAULT_CANCEL) as ButtonVariant);
101
101
 
102
102
  function setConfirmVariant(e: Event) {
103
103
  const v = (e.target as HTMLSelectElement).value;
@@ -108,30 +108,32 @@
108
108
  setComponentConfig(component, CANCEL_VAR, v);
109
109
  }
110
110
 
111
- let bgMode: 'image' | 'color' = 'image';
111
+ let bgMode: 'image' | 'color' = $state('image');
112
112
  const bgVar = '--backdrop-dialog-surface';
113
113
  </script>
114
114
 
115
115
  <ComponentEditorBase {component} title="Dialog" description="Modal dialog with focus management and slide-in animation. Import from <code>components/Dialog.svelte</code>" tokens={allTokens}>
116
- <svelte:fragment slot="config">
117
- <label>
118
- <span>Cancel button (left)</span>
119
- <select class="form-select" value={cancelVariant} on:change={setCancelVariant}>
120
- {#each BUTTON_VARIANTS as v}
121
- <option value={v}>{variantLabel(v)}</option>
122
- {/each}
123
- </select>
124
- </label>
125
- <label>
126
- <span>Confirm button (right)</span>
127
- <select class="form-select" value={confirmVariant} on:change={setConfirmVariant}>
128
- {#each BUTTON_VARIANTS as v}
129
- <option value={v}>{variantLabel(v)}</option>
130
- {/each}
131
- </select>
132
- </label>
133
- <ShadowBackdropControls bind:mode={bgMode} colorVariable={bgVar} />
134
- </svelte:fragment>
116
+ {#snippet config()}
117
+
118
+ <label>
119
+ <span>Cancel button (left)</span>
120
+ <select class="ui-form-select" value={cancelVariant} onchange={setCancelVariant}>
121
+ {#each BUTTON_VARIANTS as v}
122
+ <option value={v}>{variantLabel(v)}</option>
123
+ {/each}
124
+ </select>
125
+ </label>
126
+ <label>
127
+ <span>Confirm button (right)</span>
128
+ <select class="ui-form-select" value={confirmVariant} onchange={setConfirmVariant}>
129
+ {#each BUTTON_VARIANTS as v}
130
+ <option value={v}>{variantLabel(v)}</option>
131
+ {/each}
132
+ </select>
133
+ </label>
134
+ <ShadowBackdropControls bind:mode={bgMode} colorVariable={bgVar} />
135
+
136
+ {/snippet}
135
137
  <div class="dialog-preview">
136
138
  <ShadowBackdrop mode={bgMode} colorVariable={bgVar} padding="0">
137
139
  <Dialog
@@ -1,4 +1,4 @@
1
- <script context="module" lang="ts">
1
+ <script module lang="ts">
2
2
  import type { Token } from './scaffolding/types';
3
3
 
4
4
  export const component = 'image';
@@ -36,14 +36,16 @@
36
36
  </script>
37
37
 
38
38
  <ComponentEditorBase {component} title="Image" description="Framed image with rounded corners, border, and shadow. Import from <code>components/Image.svelte</code>" tokens={allTokens}>
39
- <svelte:fragment slot="config">
40
- <label class="backdrop-config">
41
- <span>Sample background</span>
42
- <div class="picker-slot">
43
- <UIPaletteSelector variable={bgVar} />
44
- </div>
45
- </label>
46
- </svelte:fragment>
39
+ {#snippet config()}
40
+
41
+ <label class="backdrop-config">
42
+ <span>Sample background</span>
43
+ <div class="picker-slot">
44
+ <UIPaletteSelector variable={bgVar} />
45
+ </div>
46
+ </label>
47
+
48
+ {/snippet}
47
49
  <VariantGroup name="image" title="Image" {states} {component}>
48
50
  <ShadowBackdrop mode="color" colorVariable={bgVar}>
49
51
  <div class="image-demo-grid">