@motion-proto/live-tokens 0.9.0 → 0.11.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 (65) hide show
  1. package/README.md +50 -29
  2. package/dist-plugin/index.cjs +177 -125
  3. package/dist-plugin/index.d.cts +3 -2
  4. package/dist-plugin/index.d.ts +3 -2
  5. package/dist-plugin/index.js +177 -125
  6. package/package.json +4 -1
  7. package/src/editor/component-editor/BadgeEditor.svelte +44 -42
  8. package/src/editor/component-editor/ButtonEditor.svelte +224 -0
  9. package/src/editor/component-editor/CardEditor.svelte +2 -0
  10. package/src/editor/component-editor/CollapsibleSectionEditor.svelte +1 -7
  11. package/src/editor/component-editor/CornerBadgeEditor.svelte +44 -34
  12. package/src/editor/component-editor/ImageLightboxEditor.svelte +58 -0
  13. package/src/editor/component-editor/InputEditor.svelte +272 -0
  14. package/src/editor/component-editor/NotificationEditor.svelte +44 -65
  15. package/src/editor/component-editor/ProgressBarEditor.svelte +71 -87
  16. package/src/editor/component-editor/SegmentedControlEditor.svelte +98 -37
  17. package/src/editor/component-editor/SideNavigationEditor.svelte +342 -0
  18. package/src/editor/component-editor/registry.ts +35 -2
  19. package/src/editor/component-editor/scaffolding/ComponentFileManager.svelte +3 -2
  20. package/src/editor/component-editor/scaffolding/ShadowBackdrop.svelte +10 -1
  21. package/src/editor/component-editor/scaffolding/StateBlock.svelte +9 -10
  22. package/src/editor/component-editor/scaffolding/TokenLayout.svelte +60 -36
  23. package/src/editor/component-editor/scaffolding/VariantGroup.svelte +38 -1
  24. package/src/editor/component-editor/scaffolding/buildTypeGroupTokens.ts +1 -1
  25. package/src/editor/component-editor/scaffolding/siblings.ts +2 -2
  26. package/src/editor/component-editor/scaffolding/types.ts +2 -1
  27. package/src/editor/core/components/componentConfigService.ts +7 -6
  28. package/src/editor/core/manifests/manifestService.ts +5 -4
  29. package/src/editor/core/storage/apiBase.ts +15 -0
  30. package/src/editor/core/storage/files/versionedFileResourceClient.ts +1 -1
  31. package/src/editor/core/store/editorRenderer.ts +1 -4
  32. package/src/editor/core/store/editorStore.ts +5 -9
  33. package/src/editor/core/store/editorTypes.ts +6 -13
  34. package/src/editor/core/themes/migrations/2026-05-13-primary-to-brand.ts +2 -29
  35. package/src/editor/core/themes/migrations/2026-05-24-collapsiblesection-drop-active-state.ts +28 -0
  36. package/src/editor/core/themes/migrations/2026-05-24-progressbar-collapse-variants.ts +41 -0
  37. package/src/editor/core/themes/migrations/2026-05-24-promote-state-shared-tokens.ts +59 -0
  38. package/src/editor/core/themes/migrations/2026-05-24-segmentedcontrol-divider-inset.ts +29 -0
  39. package/src/editor/core/themes/migrations/2026-05-25-cornerbadge-flatten-variants.ts +46 -0
  40. package/src/editor/core/themes/migrations/2026-05-26-drop-overlay-extra-stops.ts +46 -0
  41. package/src/editor/core/themes/migrations/index.ts +16 -0
  42. package/src/editor/core/themes/slices/overlays.ts +44 -75
  43. package/src/editor/core/themes/themeInit.ts +3 -2
  44. package/src/editor/core/themes/themeService.ts +3 -2
  45. package/src/editor/ui/SurfacesTab.svelte +3 -7
  46. package/src/editor/ui/UIEasingSelector.svelte +240 -0
  47. package/src/editor/ui/UIPaddingSelector.svelte +2 -2
  48. package/src/editor/ui/UIPaletteSelector.svelte +151 -36
  49. package/src/editor/ui/{UIRelinkConfirmPopover.svelte → UIRelinkConfirmDialog.svelte} +107 -75
  50. package/src/editor/ui/UITokenSelector.svelte +15 -2
  51. package/src/editor/ui/sections/OverlaysSection.svelte +107 -540
  52. package/src/editor/ui/variantScales.ts +34 -0
  53. package/src/system/components/Button.svelte +34 -85
  54. package/src/system/components/Card.svelte +2 -1
  55. package/src/system/components/CollapsibleSection.svelte +1 -48
  56. package/src/system/components/CornerBadge.svelte +72 -138
  57. package/src/system/components/ImageLightbox.svelte +578 -0
  58. package/src/system/components/Input.svelte +387 -0
  59. package/src/system/components/ProgressBar.svelte +62 -258
  60. package/src/system/components/SegmentedControl.svelte +81 -15
  61. package/src/system/components/SideNavigation.svelte +777 -0
  62. package/src/system/components/TabBar.svelte +1 -1
  63. package/src/system/styles/tokens.css +48 -5
  64. package/src/system/styles/tokens.generated.css +33 -185
  65. package/src/editor/component-editor/StandardButtonsEditor.svelte +0 -190
@@ -1,10 +1,7 @@
1
1
  <script lang="ts">
2
- import { run, createBubbler, stopPropagation } from 'svelte/legacy';
3
-
4
- const bubble = createBubbler();
5
2
  import { onMount, onDestroy } from 'svelte';
3
+ import { self } from 'svelte/legacy';
6
4
  import UIRadio from './UIRadio.svelte';
7
- import { keepInViewport } from './keepInViewport';
8
5
 
9
6
  type Candidate = { variable: string; alias: string };
10
7
 
@@ -40,7 +37,7 @@
40
37
 
41
38
  let options = $derived(distinctOptions(candidates, initialVariable));
42
39
  let selected = $state('');
43
- run(() => {
40
+ $effect(() => {
44
41
  if (selected === '' && options.length > 0) selected = options[0].alias;
45
42
  });
46
43
 
@@ -64,10 +61,10 @@
64
61
  }
65
62
  }
66
63
 
67
- let popoverEl: HTMLDivElement | undefined = $state();
64
+ let confirmBtn: HTMLButtonElement | undefined = $state();
68
65
 
69
66
  onMount(() => {
70
- popoverEl?.focus();
67
+ confirmBtn?.focus();
71
68
  document.addEventListener('keydown', handleKeydown, true);
72
69
  });
73
70
 
@@ -76,70 +73,93 @@
76
73
  });
77
74
  </script>
78
75
 
79
- <!-- svelte-ignore a11y_click_events_have_key_events -->
80
- <div
81
- class="ui-relink-popover"
82
- role="dialog"
83
- aria-label="Confirm link"
84
- tabindex="-1"
85
- bind:this={popoverEl}
86
- use:keepInViewport
87
- onclick={stopPropagation(bubble('click'))}
88
- >
89
- <div class="ui-relink-header">
90
- {#if options.length > 1}
91
- <span class="ui-relink-title">{candidates.length} variants disagree — pick one to broadcast</span>
92
- {:else}
93
- <span class="ui-relink-title">Link this property across {candidates.length} variants?</span>
94
- {/if}
95
- </div>
96
-
97
- <div class="ui-relink-body">
98
- {#each options as opt}
99
- <label class="ui-relink-row">
100
- <UIRadio bind:group={selected} value={opt.alias} />
101
- <div class="ui-relink-row-info">
102
- <code class="ui-relink-alias">{opt.alias}</code>
103
- <span class="ui-relink-sources">
104
- from {opt.sources.join(', ')}
105
- </span>
106
- </div>
107
- </label>
108
- {/each}
109
- </div>
110
-
111
- <div class="ui-relink-footer">
112
- <button type="button" class="ui-relink-btn ui-relink-btn-cancel" onclick={handleCancel}>Cancel</button>
113
- <button type="button" class="ui-relink-btn ui-relink-btn-confirm" onclick={handleConfirm}>Link</button>
76
+ <!-- svelte-ignore a11y_click_events_have_key_events a11y_no_noninteractive_element_interactions a11y_no_static_element_interactions -->
77
+ <div class="ui-relink-backdrop" onclick={self(handleCancel)}>
78
+ <div
79
+ class="ui-relink-dialog"
80
+ role="dialog"
81
+ aria-label="Confirm link"
82
+ aria-modal="true"
83
+ tabindex="-1"
84
+ >
85
+ <div class="ui-relink-header">
86
+ {#if options.length > 1}
87
+ <span class="ui-relink-title">{candidates.length} variants disagree — pick one to broadcast</span>
88
+ {:else}
89
+ <span class="ui-relink-title">Link this property across {candidates.length} variants?</span>
90
+ {/if}
91
+ <button
92
+ type="button"
93
+ class="ui-relink-close"
94
+ onclick={handleCancel}
95
+ aria-label="Close"
96
+ >
97
+ <i class="fas fa-times"></i>
98
+ </button>
99
+ </div>
100
+
101
+ <div class="ui-relink-body" role="radiogroup">
102
+ {#each options as opt}
103
+ <label class="ui-relink-row" class:selected={selected === opt.alias}>
104
+ <UIRadio bind:group={selected} value={opt.alias} />
105
+ <div class="ui-relink-row-info">
106
+ <code class="ui-relink-alias">{opt.alias}</code>
107
+ <span class="ui-relink-sources">
108
+ from {opt.sources.join(', ')}
109
+ </span>
110
+ </div>
111
+ </label>
112
+ {/each}
113
+ </div>
114
+
115
+ <div class="ui-relink-footer">
116
+ <button type="button" class="ui-relink-btn ui-relink-btn-cancel" onclick={handleCancel}>Cancel</button>
117
+ <button
118
+ type="button"
119
+ class="ui-relink-btn ui-relink-btn-confirm"
120
+ onclick={handleConfirm}
121
+ bind:this={confirmBtn}
122
+ >Link</button>
123
+ </div>
114
124
  </div>
115
125
  </div>
116
126
 
117
127
  <style>
118
- .ui-relink-popover {
119
- position: absolute;
120
- top: calc(100% + var(--ui-space-4));
121
- right: 0;
128
+ .ui-relink-backdrop {
129
+ position: fixed;
130
+ inset: 0;
131
+ background: rgba(0, 0, 0, 0.55);
132
+ display: flex;
133
+ justify-content: center;
134
+ align-items: center;
135
+ z-index: 10000;
136
+ }
137
+
138
+ .ui-relink-dialog {
122
139
  background: var(--ui-surface-higher);
123
140
  border: 1px solid var(--ui-border-high);
124
141
  border-radius: var(--ui-radius-md);
125
142
  box-shadow: var(--ui-shadow-lg);
126
- z-index: 20;
127
- min-width: 18rem;
128
- max-width: 24rem;
129
- padding: var(--ui-space-8);
143
+ min-width: 22rem;
144
+ max-width: 28rem;
130
145
  display: flex;
131
146
  flex-direction: column;
132
- gap: var(--ui-space-8);
133
- animation: uiRelinkPopoverIn 120ms ease-out;
147
+ animation: uiRelinkDialogIn 140ms ease-out;
134
148
  }
149
+ .ui-relink-dialog:focus { outline: none; }
135
150
 
136
- .ui-relink-popover:focus {
137
- outline: none;
151
+ @keyframes uiRelinkDialogIn {
152
+ from { opacity: 0; transform: translateY(-6px); }
153
+ to { opacity: 1; transform: translateY(0); }
138
154
  }
139
155
 
140
156
  .ui-relink-header {
157
+ display: flex;
158
+ align-items: center;
159
+ justify-content: space-between;
160
+ gap: var(--ui-space-8);
161
+ padding: var(--ui-space-8) var(--ui-space-12);
141
162
  border-bottom: 1px solid var(--ui-border-low);
142
- padding-bottom: var(--ui-space-6);
143
163
  }
144
164
 
145
165
  .ui-relink-title {
@@ -148,31 +168,52 @@
148
168
  font-weight: var(--ui-font-weight-medium);
149
169
  }
150
170
 
171
+ .ui-relink-close {
172
+ flex-shrink: 0;
173
+ width: 22px;
174
+ height: 22px;
175
+ display: grid;
176
+ place-items: center;
177
+ background: transparent;
178
+ border: none;
179
+ border-radius: var(--ui-radius-sm);
180
+ color: var(--ui-text-tertiary);
181
+ cursor: pointer;
182
+ font-size: var(--ui-font-size-xs);
183
+ transition: background var(--ui-transition-fast), color var(--ui-transition-fast);
184
+ }
185
+ .ui-relink-close:hover {
186
+ background: var(--ui-hover);
187
+ color: var(--ui-text-primary);
188
+ }
189
+
151
190
  .ui-relink-body {
152
191
  display: flex;
153
192
  flex-direction: column;
154
193
  gap: var(--ui-space-4);
194
+ padding: var(--ui-space-8) var(--ui-space-8);
155
195
  }
156
196
 
157
197
  .ui-relink-row {
158
198
  display: flex;
159
199
  align-items: flex-start;
160
200
  gap: var(--ui-space-8);
161
- padding: var(--ui-space-4);
201
+ padding: var(--ui-space-6) var(--ui-space-8);
202
+ border: 1px solid transparent;
162
203
  border-radius: var(--ui-radius-sm);
163
204
  cursor: pointer;
164
- transition: background var(--ui-transition-fast);
205
+ transition:
206
+ background var(--ui-transition-fast),
207
+ border-color var(--ui-transition-fast);
165
208
  }
166
-
167
- .ui-relink-row:hover {
209
+ .ui-relink-row:hover { background: var(--ui-hover); }
210
+ .ui-relink-row.selected {
168
211
  background: var(--ui-hover);
212
+ border-color: var(--ui-border-high);
169
213
  }
170
214
 
171
- /* Lift the radio slightly so it visually aligns with the first line of the
172
- two-line row label. Selection styling lives in UIRadio. */
173
- .ui-relink-row :global(.ui-radio) {
174
- margin-top: 0.2rem;
175
- }
215
+ /* Lift the radio so it visually aligns with the first line of the row label. */
216
+ .ui-relink-row :global(.ui-radio) { margin-top: 0.2rem; }
176
217
 
177
218
  .ui-relink-row-info {
178
219
  display: flex;
@@ -204,7 +245,7 @@
204
245
  display: flex;
205
246
  justify-content: flex-end;
206
247
  gap: var(--ui-space-6);
207
- padding-top: var(--ui-space-4);
248
+ padding: var(--ui-space-8) var(--ui-space-12);
208
249
  border-top: 1px solid var(--ui-border-low);
209
250
  }
210
251
 
@@ -222,7 +263,6 @@
222
263
  border: 1px solid var(--ui-border);
223
264
  color: var(--ui-text-secondary);
224
265
  }
225
-
226
266
  .ui-relink-btn-cancel:hover {
227
267
  background: var(--ui-hover);
228
268
  color: var(--ui-text-primary);
@@ -233,13 +273,5 @@
233
273
  border: 1px solid var(--ui-text-accent);
234
274
  color: var(--ui-surface-lowest);
235
275
  }
236
-
237
- .ui-relink-btn-confirm:hover {
238
- filter: brightness(1.1);
239
- }
240
-
241
- @keyframes uiRelinkPopoverIn {
242
- from { opacity: 0; transform: translateY(-2px); }
243
- to { opacity: 1; transform: translateY(0); }
244
- }
276
+ .ui-relink-btn-confirm:hover { filter: brightness(1.1); }
245
277
  </style>
@@ -15,7 +15,7 @@
15
15
  getComponentPropertySiblings,
16
16
  } from '../core/store/editorStore';
17
17
  import UILinkToggle from './UILinkToggle.svelte';
18
- import UIRelinkConfirmPopover from './UIRelinkConfirmPopover.svelte';
18
+ import UIRelinkConfirmDialog from './UIRelinkConfirmDialog.svelte';
19
19
  import { keepInViewport } from './keepInViewport';
20
20
 
21
21
  type DropdownContext = { close: () => void; handleReset: () => void };
@@ -58,6 +58,14 @@
58
58
  onopen?: () => void;
59
59
  onclose?: () => void;
60
60
  onvarChange?: () => void;
61
+ /** When provided, writes route through this callback instead of touching
62
+ * the DOM or component aliases. Caller owns persistence (typically into
63
+ * a typed slice). The callback receives the same payload `writeOverride`
64
+ * would have written: a bare `--token-name`, a CSS expression like
65
+ * `color-mix(...)` or `transparent`, or `null` to reset. Caller is
66
+ * responsible for re-emitting the var so the picker's DOM read-back
67
+ * reflects the new state. */
68
+ onwrite?: (value: string | null) => void;
61
69
  }
62
70
 
63
71
  let {
@@ -81,6 +89,7 @@
81
89
  onopen,
82
90
  onclose,
83
91
  onvarChange,
92
+ onwrite,
84
93
  }: Props = $props();
85
94
 
86
95
  let open = $state(false);
@@ -100,6 +109,10 @@
100
109
 
101
110
  /** Persist a semantic CSS-var reference (or clear it when null). */
102
111
  export function writeOverride(semanticName: string | null): void {
112
+ if (onwrite) {
113
+ onwrite(semanticName);
114
+ return;
115
+ }
103
116
  if (component) {
104
117
  const useLinked = isLinkedDisplay;
105
118
  if (semanticName) {
@@ -280,7 +293,7 @@
280
293
  </button>
281
294
 
282
295
  {#if relinkOpen && component}
283
- <UIRelinkConfirmPopover
296
+ <UIRelinkConfirmDialog
284
297
  candidates={relinkCandidates}
285
298
  initialVariable={variable}
286
299
  prefixToStrip={`--${component}-`}