@motion-proto/live-tokens 0.3.7 → 0.5.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 (104) hide show
  1. package/README.md +1 -1
  2. package/package.json +11 -9
  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 +260 -37
  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 +73 -36
  61. package/src/pages/ComponentEditorPage.svelte +17 -13
  62. package/src/pages/EditorShell.svelte +24 -20
  63. package/src/styles/form-controls.css +2 -2
  64. package/src/styles/tokens.css +59 -81
  65. package/src/ui/BezierCurveEditor.svelte +59 -43
  66. package/src/ui/ColorEditPanel.svelte +71 -44
  67. package/src/ui/EditorViewSwitcher.svelte +9 -5
  68. package/src/ui/FontStackEditor.svelte +16 -15
  69. package/src/ui/GradientEditor.svelte +42 -33
  70. package/src/ui/GradientStopPicker.svelte +18 -29
  71. package/src/ui/PaletteEditor.svelte +238 -212
  72. package/src/ui/PresetFileManager.svelte +20 -18
  73. package/src/ui/ProjectFontsSection.svelte +30 -30
  74. package/src/ui/SurfacesTab.svelte +3 -3
  75. package/src/ui/TextTab.svelte +2 -2
  76. package/src/ui/ThemeFileManager.svelte +38 -35
  77. package/src/ui/Toggle.svelte +11 -9
  78. package/src/ui/UICopyPopover.svelte +19 -15
  79. package/src/ui/UIDialog.svelte +48 -30
  80. package/src/ui/UIFontFamilySelector.svelte +104 -78
  81. package/src/ui/UIFontSizeSelector.svelte +38 -20
  82. package/src/ui/UIFontWeightSelector.svelte +33 -13
  83. package/src/ui/UILineHeightSelector.svelte +33 -13
  84. package/src/ui/UILinkToggle.svelte +7 -6
  85. package/src/ui/UIOptionItem.svelte +21 -7
  86. package/src/ui/UIOptionList.svelte +9 -3
  87. package/src/ui/UIPaddingSelector.svelte +108 -82
  88. package/src/ui/UIPaletteSelector.svelte +186 -161
  89. package/src/ui/UIRadio.svelte +23 -8
  90. package/src/ui/UIRadioGroup.svelte +9 -8
  91. package/src/ui/UIRelinkConfirmPopover.svelte +26 -16
  92. package/src/ui/UITokenSelector.svelte +112 -68
  93. package/src/ui/UIVariantSelector.svelte +79 -57
  94. package/src/ui/VariablesTab.svelte +15 -15
  95. package/src/ui/palette/GradientStopEditor.svelte +45 -26
  96. package/src/ui/palette/OverridesPanel.svelte +85 -49
  97. package/src/ui/palette/PaletteBase.svelte +60 -32
  98. package/src/ui/palette/ScaleCurveEditor.svelte +25 -10
  99. package/src/ui/sections/ColumnsSection.svelte +13 -13
  100. package/src/ui/sections/GradientsSection.svelte +12 -9
  101. package/src/ui/sections/OverlaysSection.svelte +50 -47
  102. package/src/ui/sections/ShadowsSection.svelte +110 -104
  103. package/src/ui/sections/TokenScaleTable.svelte +38 -22
  104. package/src/ui/sections/tokenScales.ts +2 -2
@@ -1,11 +1,21 @@
1
1
  <script lang="ts">
2
- export let text: string = '';
3
- export let position: 'top' | 'bottom' = 'top';
4
- export let open: boolean = false;
2
+ interface Props {
3
+ text?: string;
4
+ position?: 'top' | 'bottom';
5
+ open?: boolean;
6
+ children?: import('svelte').Snippet;
7
+ }
8
+
9
+ let {
10
+ text = '',
11
+ position = 'top',
12
+ open = false,
13
+ children
14
+ }: Props = $props();
5
15
  </script>
6
16
 
7
17
  <div class="tooltip-wrapper" class:open>
8
- <slot />
18
+ {@render children?.()}
9
19
  {#if text}
10
20
  <div class="tooltip" class:bottom={position === 'bottom'}>
11
21
  {text}
@@ -20,7 +30,7 @@
20
30
  --tooltip-text-font-family: var(--font-sans);
21
31
  --tooltip-text-font-size: var(--font-size-sm);
22
32
  --tooltip-text-font-weight: var(--font-weight-normal);
23
- --tooltip-text-line-height: var(--line-height-normal);
33
+ --tooltip-text-line-height: var(--line-height-md);
24
34
  --tooltip-border: var(--border-neutral);
25
35
  --tooltip-border-width: var(--border-width-0);
26
36
  --tooltip-radius: var(--radius-md);
@@ -6,9 +6,9 @@
6
6
  const isInIframe = typeof window !== 'undefined' && window.parent !== window;
7
7
  const enabled = isDev && !isInIframe;
8
8
 
9
- let count = 12;
10
- let gutter = '';
11
- let margin = '';
9
+ let count = $state(12);
10
+ let gutter = $state('');
11
+ let margin = $state('');
12
12
 
13
13
  function readTokens() {
14
14
  const cs = getComputedStyle(document.documentElement);
@@ -1,14 +1,19 @@
1
- <script context="module" lang="ts">
1
+ <script module lang="ts">
2
2
  // __PROJECT_ROOT__ is injected by the themeFileApi Vite plugin as a `define`.
3
3
  // Consumers don't need to configure it themselves. We declare it locally so
4
4
  // this component's type-check passes in consumer projects that haven't added
5
5
  // the ambient global to their tsconfig.
6
6
  declare const __PROJECT_ROOT__: string | undefined;
7
+ declare const __APP_VERSION__: string | undefined;
7
8
  const INJECTED_PROJECT_ROOT: string =
8
9
  typeof __PROJECT_ROOT__ !== 'undefined' ? (__PROJECT_ROOT__ ?? '') : '';
10
+ const APP_VERSION: string =
11
+ typeof __APP_VERSION__ !== 'undefined' ? (__APP_VERSION__ ?? '') : '';
9
12
  </script>
10
13
 
11
14
  <script lang="ts">
15
+ import { run } from 'svelte/legacy';
16
+
12
17
  import { onMount, onDestroy } from 'svelte';
13
18
  import { fade } from 'svelte/transition';
14
19
  import { cubicInOut } from 'svelte/easing';
@@ -20,12 +25,23 @@
20
25
  import { postParentRoute } from './parentRouteStore';
21
26
  import type { NavLink } from './navLinkTypes';
22
27
 
23
- export let open: boolean | undefined = undefined;
24
- export let editorPath: string = '/editor';
25
- export let navLinks: NavLink[] = [];
26
- export let pageSources: Record<string, string> = {};
27
- export let hidePageSourceOn: string[] = [];
28
- export let projectRoot: string = INJECTED_PROJECT_ROOT;
28
+ interface Props {
29
+ open?: boolean | undefined;
30
+ editorPath?: string;
31
+ navLinks?: NavLink[];
32
+ pageSources?: Record<string, string>;
33
+ hidePageSourceOn?: string[];
34
+ projectRoot?: string;
35
+ }
36
+
37
+ let {
38
+ open = $bindable(undefined),
39
+ editorPath = '/editor',
40
+ navLinks = [],
41
+ pageSources = {},
42
+ hidePageSourceOn = [],
43
+ projectRoot = INJECTED_PROJECT_ROOT
44
+ }: Props = $props();
29
45
 
30
46
  // Self-gate: only render in dev, and never inside an iframe (the /editor
31
47
  // page embeds this same app in an iframe and would otherwise recursively
@@ -41,25 +57,33 @@
41
57
  if (!consumerControlsOpen) {
42
58
  open = enabled && quietGet(OPEN_KEY) === '1';
43
59
  }
44
- $: if (!consumerControlsOpen && typeof window !== 'undefined') {
45
- quietSet(OPEN_KEY, open ? '1' : '0');
46
- }
47
- $: overlayOpen.set(!!open);
60
+ run(() => {
61
+ if (!consumerControlsOpen && typeof window !== 'undefined') {
62
+ quietSet(OPEN_KEY, open ? '1' : '0');
63
+ }
64
+ });
65
+ run(() => {
66
+ overlayOpen.set(!!open);
67
+ });
48
68
 
49
69
  // Hide the overlay entirely when the user is already on the editor route
50
70
  // (the editor page has its own chrome).
51
- $: onEditorPath = $route === editorPath;
52
- $: sourceFile = pageSources[$route];
53
- $: showSource = !!sourceFile && !!projectRoot && !hidePageSourceOn.includes($route);
71
+ let onEditorPath = $derived($route === editorPath);
72
+ let sourceFile = $derived(pageSources[$route]);
73
+ let showSource = $derived(!!sourceFile && !!projectRoot && !hidePageSourceOn.includes($route));
54
74
 
55
75
  // Mount the iframe the first time the editor is shown, then keep it mounted
56
76
  // across hide/show cycles so editor state (unsaved slider values, scroll
57
77
  // position, expanded sections) survives.
58
- let hasBeenOpen: boolean = !!open;
59
- $: if (open) hasBeenOpen = true;
78
+ let hasBeenOpen: boolean = $state(!!open);
79
+ run(() => {
80
+ if (open) hasBeenOpen = true;
81
+ });
60
82
 
61
- let editorFrame: HTMLIFrameElement | undefined;
62
- $: postParentRoute(editorFrame?.contentWindow, $route);
83
+ let editorFrame: HTMLIFrameElement | undefined = $state();
84
+ run(() => {
85
+ postParentRoute(editorFrame?.contentWindow, $route);
86
+ });
63
87
 
64
88
  type Mode = 'docked' | 'floating';
65
89
 
@@ -106,9 +130,9 @@
106
130
  }
107
131
 
108
132
  const initial = loadState();
109
- let mode: Mode = initial.mode;
110
- let dockedWidth: number = Math.max(MIN_WIDTH, initial.dockedWidth);
111
- let floating = { ...initial.floating };
133
+ let mode: Mode = $state(initial.mode);
134
+ let dockedWidth: number = $state(Math.max(MIN_WIDTH, initial.dockedWidth));
135
+ let floating = $state({ ...initial.floating });
112
136
 
113
137
  // Approximate natural size of the collapsed pill (Editor title + columns toggle).
114
138
  // A few pixels of overshoot is fine — the panel has overflow:hidden.
@@ -122,11 +146,11 @@
122
146
 
123
147
  // Suppress CSS transitions during gestures and mode swaps so dragging doesn't
124
148
  // re-animate every frame, and floating↔docked swaps snap cleanly.
125
- let suppressTransition = false;
149
+ let suppressTransition = $state(false);
126
150
 
127
151
  // Gesture state — a transparent scrim covers the iframe while any gesture is active
128
152
  // so pointer events land on the panel, not on content inside the iframe.
129
- let gesturing: 'drag' | 'resize-left' | 'resize-se' | null = null;
153
+ let gesturing: 'drag' | 'resize-left' | 'resize-se' | null = $state(null);
130
154
 
131
155
  function startDrag(e: PointerEvent) {
132
156
  if (!open || mode !== 'floating') return;
@@ -241,15 +265,15 @@
241
265
  window.removeEventListener('lt-overlay-toggle', handleToggleRequest);
242
266
  });
243
267
 
244
- $: panelStyle = !open
268
+ let panelStyle = $derived(!open
245
269
  ? `position: fixed; top: 12px; right: 12px; width: ${COLLAPSED_WIDTH}px; height: ${COLLAPSED_HEIGHT}px;`
246
270
  : mode === 'docked'
247
271
  ? `position: fixed; top: 0; right: 0; width: ${dockedWidth}px; height: 100vh;`
248
- : `position: fixed; top: ${floating.y}px; left: ${floating.x}px; width: ${floating.width}px; height: ${floating.height}px;`;
272
+ : `position: fixed; top: ${floating.y}px; left: ${floating.x}px; width: ${floating.width}px; height: ${floating.height}px;`);
249
273
  </script>
250
274
 
251
275
  {#if enabled && !onEditorPath}
252
- <!-- svelte-ignore a11y-no-static-element-interactions -->
276
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
253
277
  <div
254
278
  class="lt-overlay"
255
279
  style={panelStyle}
@@ -261,13 +285,13 @@
261
285
  >
262
286
  <div
263
287
  class="header"
264
- on:pointerdown={startDrag}
265
- on:dblclick={handleHeaderDblClick}
288
+ onpointerdown={startDrag}
289
+ ondblclick={handleHeaderDblClick}
266
290
  title={open ? 'Double-click to hide' : 'Double-click to show'}
267
291
  >
268
292
  <button
269
293
  class="hdr-btn text title"
270
- on:click={toggleOpen}
294
+ onclick={toggleOpen}
271
295
  title={open ? 'Hide Editor' : 'Show Editor'}
272
296
  >
273
297
  <i class="fas {open ? 'fa-chevron-right' : 'fa-chevron-left'}"></i>
@@ -277,7 +301,7 @@
277
301
  <button
278
302
  class="hdr-btn icon"
279
303
  class:active={$columnsVisible}
280
- on:click={toggleColumns}
304
+ onclick={toggleColumns}
281
305
  title="{$columnsVisible ? 'Hide' : 'Show'} columns"
282
306
  >
283
307
  <i class="fas fa-grip-lines-vertical"></i>
@@ -287,13 +311,17 @@
287
311
  <button
288
312
  class="hdr-btn icon"
289
313
  title={mode === 'docked' ? 'Float' : 'Dock to right'}
290
- on:click={toggleMode}
314
+ onclick={toggleMode}
291
315
  transition:fade={BTN_FADE}
292
316
  >
293
317
  <i class={mode === 'docked' ? 'fas fa-up-right-from-square' : 'fas fa-thumbtack'}></i>
294
318
  </button>
295
319
  {/if}
296
320
 
321
+ {#if APP_VERSION}
322
+ <span class="version" title="live-tokens version">v{APP_VERSION}</span>
323
+ {/if}
324
+
297
325
  {#if open}
298
326
  <div class="spacer" transition:fade={BTN_FADE}></div>
299
327
  {/if}
@@ -306,7 +334,7 @@
306
334
  transition:fade={BTN_FADE}
307
335
  >
308
336
  <i class="fas fa-code"></i>
309
- Show Source
337
+ Show page source
310
338
  </a>
311
339
  {/if}
312
340
 
@@ -322,7 +350,7 @@
322
350
  class:active={$route === link.path}
323
351
  aria-selected={$route === link.path}
324
352
  disabled={link.disabled}
325
- on:click={() => navigate(link.path)}
353
+ onclick={() => navigate(link.path)}
326
354
  >
327
355
  {#if link.icon}<i class="fas {link.icon}"></i>{/if}
328
356
  <span>{link.label}</span>
@@ -340,7 +368,7 @@
340
368
  title="Token editor"
341
369
  class="editor-frame"
342
370
  bind:this={editorFrame}
343
- on:load={() => postParentRoute(editorFrame?.contentWindow, $route)}
371
+ onload={() => postParentRoute(editorFrame?.contentWindow, $route)}
344
372
  ></iframe>
345
373
  {#if gesturing}
346
374
  <div class="gesture-scrim"></div>
@@ -348,9 +376,9 @@
348
376
  </div>
349
377
 
350
378
  {#if mode === 'docked'}
351
- <div class="resize-left" on:pointerdown={startDockedResize}></div>
379
+ <div class="resize-left" onpointerdown={startDockedResize}></div>
352
380
  {:else}
353
- <div class="resize-se" on:pointerdown={startFloatingResize}></div>
381
+ <div class="resize-se" onpointerdown={startFloatingResize}></div>
354
382
  {/if}
355
383
  {/if}
356
384
  </div>
@@ -454,6 +482,15 @@
454
482
 
455
483
  .spacer { flex: 1; }
456
484
 
485
+ .version {
486
+ font-size: 10px;
487
+ font-weight: 500;
488
+ color: rgba(255, 255, 255, 0.4);
489
+ letter-spacing: 0.02em;
490
+ margin-left: 2px;
491
+ user-select: none;
492
+ }
493
+
457
494
  .hdr-btn {
458
495
  display: inline-flex;
459
496
  align-items: center;
@@ -1,4 +1,6 @@
1
1
  <script lang="ts">
2
+ import { run } from 'svelte/legacy';
3
+
2
4
  import { onMount, onDestroy } from 'svelte';
3
5
  import ComponentsTab from '../component-editor/scaffolding/ComponentsTab.svelte';
4
6
  import PresetFileManager from '../ui/PresetFileManager.svelte';
@@ -7,19 +9,19 @@
7
9
  import { listComponents } from '../lib/componentConfigService';
8
10
  import { selectedComponent } from '../lib/editorViewStore';
9
11
 
10
- let drawerOpen = true;
12
+ let drawerOpen = $state(true);
11
13
 
12
14
  // Demo page is statically imported from `./Demo.svelte` in App.svelte; the
13
15
  // glob resolves to an empty object if the file has been deleted, in which
14
16
  // case we hide the demo option from the page-switcher.
15
17
  const demoExists = Object.keys(import.meta.glob('./Demo.svelte')).length > 0;
16
18
 
17
- let pageMenuOpen = false;
18
- let pageMenuRoot: HTMLElement;
19
+ let pageMenuOpen = $state(false);
20
+ let pageMenuRoot: HTMLElement | undefined = $state();
19
21
 
20
22
  const HINT_DELAY_MS = 80;
21
- let hintLabel: string | null = null;
22
- let hintTop = 0;
23
+ let hintLabel: string | null = $state(null);
24
+ let hintTop = $state(0);
23
25
  let hintTimer: ReturnType<typeof setTimeout> | null = null;
24
26
 
25
27
  function showHint(label: string, target: HTMLElement) {
@@ -40,7 +42,9 @@
40
42
  hintLabel = null;
41
43
  }
42
44
 
43
- $: if (drawerOpen) hideHint();
45
+ run(() => {
46
+ if (drawerOpen) hideHint();
47
+ });
44
48
 
45
49
  function selectComponent(id: string) {
46
50
  selectedComponent.set(id);
@@ -101,7 +105,7 @@
101
105
  class="rail-toggle"
102
106
  aria-label={drawerOpen ? 'Collapse components menu' : 'Expand components menu'}
103
107
  aria-expanded={drawerOpen}
104
- on:click={() => (drawerOpen = !drawerOpen)}
108
+ onclick={() => (drawerOpen = !drawerOpen)}
105
109
  >
106
110
  <i class="fas {drawerOpen ? 'fa-arrow-left' : 'fa-arrow-right'}"></i>
107
111
  </button>
@@ -112,19 +116,19 @@
112
116
  aria-haspopup="menu"
113
117
  aria-expanded={pageMenuOpen}
114
118
  tabindex={drawerOpen ? 0 : -1}
115
- on:click={() => drawerOpen && (pageMenuOpen = !pageMenuOpen)}
119
+ onclick={() => drawerOpen && (pageMenuOpen = !pageMenuOpen)}
116
120
  >
117
121
  <span class="rail-label">Components</span>
118
122
  <i class="fas fa-chevron-down rail-chevron" class:open={pageMenuOpen}></i>
119
123
  </button>
120
124
  {#if pageMenuOpen && drawerOpen}
121
125
  <div class="page-menu" role="menu">
122
- <button class="page-menu-item" role="menuitem" on:click={() => selectPage('/')}>
126
+ <button class="page-menu-item" role="menuitem" onclick={() => selectPage('/')}>
123
127
  <i class="fas fa-home"></i>
124
128
  <span>Main site</span>
125
129
  </button>
126
130
  {#if demoExists}
127
- <button class="page-menu-item" role="menuitem" on:click={() => selectPage('/demo')}>
131
+ <button class="page-menu-item" role="menuitem" onclick={() => selectPage('/demo')}>
128
132
  <i class="fas fa-box-open"></i>
129
133
  <span>Demo page</span>
130
134
  </button>
@@ -137,9 +141,9 @@
137
141
  <button
138
142
  class="nav-item"
139
143
  class:active={$selectedComponent === item.id}
140
- on:mouseenter={(e) => showHint(item.label, e.currentTarget)}
141
- on:mouseleave={hideHint}
142
- on:click={() => selectComponent(item.id)}
144
+ onmouseenter={(e) => showHint(item.label, e.currentTarget)}
145
+ onmouseleave={hideHint}
146
+ onclick={() => selectComponent(item.id)}
143
147
  >
144
148
  <i class={item.icon}></i>
145
149
  <span class="rail-label">{item.label}</span>
@@ -1,4 +1,6 @@
1
1
  <script lang="ts">
2
+ import { run } from 'svelte/legacy';
3
+
2
4
  import { onMount, onDestroy } from 'svelte';
3
5
  import { get } from 'svelte/store';
4
6
  import VariablesTab from '../ui/VariablesTab.svelte';
@@ -28,18 +30,18 @@
28
30
 
29
31
  const componentNavItems = componentRegistryEntries.map(({ id, label, icon }) => ({ id, label, icon }));
30
32
 
31
- let selectedTokenSection: string | null = null;
32
- let saveStatus: 'idle' | 'saving' | 'saved' | 'error' = 'idle';
33
+ let selectedTokenSection: string | null = $state(null);
34
+ let saveStatus: 'idle' | 'saving' | 'saved' | 'error' = $state('idle');
33
35
 
34
- let shellEl: HTMLElement | null = null;
35
- let shellWidth = 1024;
36
+ let shellEl: HTMLElement | null = $state(null);
37
+ let shellWidth = $state(1024);
36
38
  const CONDENSE_BELOW = 520;
37
39
 
38
- $: condensed = $sidebarCondensed === 'auto' ? shellWidth < CONDENSE_BELOW : $sidebarCondensed;
40
+ let condensed = $derived($sidebarCondensed === 'auto' ? shellWidth < CONDENSE_BELOW : $sidebarCondensed);
39
41
 
40
42
  const HINT_DELAY_MS = 80;
41
- let hintLabel: string | null = null;
42
- let hintTop = 0;
43
+ let hintLabel: string | null = $state(null);
44
+ let hintTop = $state(0);
43
45
  let hintTimer: ReturnType<typeof setTimeout> | null = null;
44
46
 
45
47
  function showHint(label: string, target: HTMLElement) {
@@ -60,7 +62,9 @@
60
62
  hintLabel = null;
61
63
  }
62
64
 
63
- $: if (!condensed) hideHint();
65
+ run(() => {
66
+ if (!condensed) hideHint();
67
+ });
64
68
 
65
69
  function scrollToSection(sectionId: string) {
66
70
  selectedTokenSection = sectionId;
@@ -80,8 +84,8 @@
80
84
  });
81
85
  }
82
86
 
83
- async function handleSave(e: CustomEvent<{ fileName: string; displayName: string }>) {
84
- const { fileName, displayName } = e.detail;
87
+ async function handleSave(detail: { fileName: string; displayName: string }) {
88
+ const { fileName, displayName } = detail;
85
89
  saveStatus = 'saving';
86
90
  try {
87
91
  await persistTheme(get(editorState), fileName, displayName);
@@ -93,9 +97,9 @@
93
97
  }
94
98
  }
95
99
 
96
- async function handleLoad(e: CustomEvent<{ fileName: string }>) {
100
+ async function handleLoad(detail: { fileName: string }) {
97
101
  try {
98
- await hydrateTheme(e.detail.fileName);
102
+ await hydrateTheme(detail.fileName);
99
103
  } catch {
100
104
  // silent
101
105
  }
@@ -132,7 +136,7 @@
132
136
  class="rail-toggle"
133
137
  aria-label={condensed ? 'Expand sidebar' : 'Collapse sidebar'}
134
138
  aria-expanded={!condensed}
135
- on:click={toggleCondensed}
139
+ onclick={toggleCondensed}
136
140
  >
137
141
  <i class="fas {condensed ? 'fa-arrow-right' : 'fa-arrow-left'}"></i>
138
142
  </button>
@@ -146,9 +150,9 @@
146
150
  <button
147
151
  class="nav-item"
148
152
  class:active={selectedTokenSection === item.id}
149
- on:mouseenter={(e) => showHint(item.label, e.currentTarget)}
150
- on:mouseleave={hideHint}
151
- on:click={() => scrollToSection(item.id)}
153
+ onmouseenter={(e) => showHint(item.label, e.currentTarget)}
154
+ onmouseleave={hideHint}
155
+ onclick={() => scrollToSection(item.id)}
152
156
  >
153
157
  <i class={item.icon}></i>
154
158
  <span class="nav-label">{item.label}</span>
@@ -157,7 +161,7 @@
157
161
  </div>
158
162
  {#if !condensed}
159
163
  <div class="sidebar-footer">
160
- <ThemeFileManager {saveStatus} on:save={handleSave} on:load={handleLoad} />
164
+ <ThemeFileManager {saveStatus} onsave={handleSave} onload={handleLoad} />
161
165
  </div>
162
166
  {/if}
163
167
  {:else}
@@ -166,9 +170,9 @@
166
170
  <button
167
171
  class="nav-item"
168
172
  class:active={$selectedComponent === item.id}
169
- on:mouseenter={(e) => showHint(item.label, e.currentTarget)}
170
- on:mouseleave={hideHint}
171
- on:click={() => selectComponent(item.id)}
173
+ onmouseenter={(e) => showHint(item.label, e.currentTarget)}
174
+ onmouseleave={hideHint}
175
+ onclick={() => selectComponent(item.id)}
172
176
  >
173
177
  <i class={item.icon}></i>
174
178
  <span class="nav-label">{item.label}</span>
@@ -69,7 +69,7 @@
69
69
  font-family: var(--font-sans);
70
70
  font-size: var(--font-size-md);
71
71
  font-weight: var(--font-weight-light);
72
- line-height: var(--line-height-relaxed);
72
+ line-height: var(--line-height-md);
73
73
  vertical-align: middle;
74
74
  cursor: pointer;
75
75
  transition: all var(--duration-150);
@@ -124,7 +124,7 @@
124
124
  min-height: 2rem;
125
125
  font-size: var(--font-size-md);
126
126
  font-family: var(--font-sans);
127
- line-height: var(--line-height-relaxed);
127
+ line-height: var(--line-height-md);
128
128
  }
129
129
 
130
130
  /* Disabled options */