@motion-proto/live-tokens 0.3.9 → 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 (103) hide show
  1. package/package.json +9 -8
  2. package/src/component-editor/BadgeEditor.svelte +24 -22
  3. package/src/component-editor/CalloutEditor.svelte +3 -3
  4. package/src/component-editor/CardEditor.svelte +25 -21
  5. package/src/component-editor/CollapsibleSectionEditor.svelte +27 -25
  6. package/src/component-editor/CornerBadgeEditor.svelte +37 -35
  7. package/src/component-editor/DialogEditor.svelte +26 -24
  8. package/src/component-editor/ImageEditor.svelte +11 -9
  9. package/src/component-editor/InlineEditActionsEditor.svelte +17 -15
  10. package/src/component-editor/NotificationEditor.svelte +32 -30
  11. package/src/component-editor/ProgressBarEditor.svelte +3 -3
  12. package/src/component-editor/RadioButtonEditor.svelte +31 -29
  13. package/src/component-editor/SectionDividerEditor.svelte +30 -28
  14. package/src/component-editor/SegmentedControlEditor.svelte +29 -25
  15. package/src/component-editor/StandardButtonsEditor.svelte +42 -38
  16. package/src/component-editor/TabBarEditor.svelte +20 -18
  17. package/src/component-editor/TableEditor.svelte +4 -4
  18. package/src/component-editor/TooltipEditor.svelte +11 -9
  19. package/src/component-editor/registry.ts +2 -2
  20. package/src/component-editor/scaffolding/AngleDial.svelte +20 -19
  21. package/src/component-editor/scaffolding/ComponentEditorBase.svelte +44 -20
  22. package/src/component-editor/scaffolding/ComponentFileManager.svelte +260 -37
  23. package/src/component-editor/scaffolding/ComponentFileMenu.svelte +41 -29
  24. package/src/component-editor/scaffolding/ComponentsTab.svelte +7 -3
  25. package/src/component-editor/scaffolding/CopyFromMenu.svelte +21 -12
  26. package/src/component-editor/scaffolding/DemoHeader.svelte +13 -4
  27. package/src/component-editor/scaffolding/DividerEditor.svelte +27 -14
  28. package/src/component-editor/scaffolding/FieldsetWrapper.svelte +10 -4
  29. package/src/component-editor/scaffolding/GradientCard.svelte +25 -20
  30. package/src/component-editor/scaffolding/LinkageChart.svelte +43 -34
  31. package/src/component-editor/scaffolding/LinkedBlock.svelte +24 -21
  32. package/src/component-editor/scaffolding/NonStylableConfig.svelte +6 -1
  33. package/src/component-editor/scaffolding/SaveAsDialog.svelte +39 -35
  34. package/src/component-editor/scaffolding/ShadowBackdrop.svelte +21 -9
  35. package/src/component-editor/scaffolding/ShadowBackdropControls.svelte +8 -3
  36. package/src/component-editor/scaffolding/StateBlock.svelte +30 -13
  37. package/src/component-editor/scaffolding/TokenLayout.svelte +46 -30
  38. package/src/component-editor/scaffolding/TypeEditor.svelte +52 -26
  39. package/src/component-editor/scaffolding/VariantGroup.svelte +81 -48
  40. package/src/component-editor/scaffolding/componentSectionType.ts +2 -2
  41. package/src/components/Badge.svelte +45 -26
  42. package/src/components/Button.svelte +44 -21
  43. package/src/components/Callout.svelte +17 -12
  44. package/src/components/Card.svelte +23 -11
  45. package/src/components/CollapsibleSection.svelte +56 -27
  46. package/src/components/CornerBadge.svelte +32 -18
  47. package/src/components/Dialog.svelte +55 -31
  48. package/src/components/Image.svelte +14 -5
  49. package/src/components/InlineEditActions.svelte +22 -10
  50. package/src/components/Notification.svelte +39 -19
  51. package/src/components/ProgressBar.svelte +27 -17
  52. package/src/components/RadioButton.svelte +27 -10
  53. package/src/components/SectionDivider.svelte +34 -26
  54. package/src/components/SegmentedControl.svelte +23 -9
  55. package/src/components/TabBar.svelte +23 -10
  56. package/src/components/Table.svelte +8 -3
  57. package/src/components/Tooltip.svelte +15 -5
  58. package/src/lib/ColumnsOverlay.svelte +3 -3
  59. package/src/lib/LiveEditorOverlay.svelte +57 -36
  60. package/src/pages/ComponentEditorPage.svelte +17 -13
  61. package/src/pages/EditorShell.svelte +24 -20
  62. package/src/styles/form-controls.css +2 -2
  63. package/src/styles/tokens.css +59 -81
  64. package/src/ui/BezierCurveEditor.svelte +59 -43
  65. package/src/ui/ColorEditPanel.svelte +71 -44
  66. package/src/ui/EditorViewSwitcher.svelte +9 -5
  67. package/src/ui/FontStackEditor.svelte +16 -15
  68. package/src/ui/GradientEditor.svelte +42 -33
  69. package/src/ui/GradientStopPicker.svelte +18 -29
  70. package/src/ui/PaletteEditor.svelte +238 -212
  71. package/src/ui/PresetFileManager.svelte +20 -18
  72. package/src/ui/ProjectFontsSection.svelte +30 -30
  73. package/src/ui/SurfacesTab.svelte +3 -3
  74. package/src/ui/TextTab.svelte +2 -2
  75. package/src/ui/ThemeFileManager.svelte +38 -35
  76. package/src/ui/Toggle.svelte +11 -9
  77. package/src/ui/UICopyPopover.svelte +19 -15
  78. package/src/ui/UIDialog.svelte +48 -30
  79. package/src/ui/UIFontFamilySelector.svelte +104 -78
  80. package/src/ui/UIFontSizeSelector.svelte +38 -20
  81. package/src/ui/UIFontWeightSelector.svelte +33 -13
  82. package/src/ui/UILineHeightSelector.svelte +33 -13
  83. package/src/ui/UILinkToggle.svelte +7 -6
  84. package/src/ui/UIOptionItem.svelte +21 -7
  85. package/src/ui/UIOptionList.svelte +9 -3
  86. package/src/ui/UIPaddingSelector.svelte +108 -82
  87. package/src/ui/UIPaletteSelector.svelte +186 -161
  88. package/src/ui/UIRadio.svelte +23 -8
  89. package/src/ui/UIRadioGroup.svelte +9 -8
  90. package/src/ui/UIRelinkConfirmPopover.svelte +26 -16
  91. package/src/ui/UITokenSelector.svelte +112 -68
  92. package/src/ui/UIVariantSelector.svelte +79 -57
  93. package/src/ui/VariablesTab.svelte +15 -15
  94. package/src/ui/palette/GradientStopEditor.svelte +45 -26
  95. package/src/ui/palette/OverridesPanel.svelte +85 -49
  96. package/src/ui/palette/PaletteBase.svelte +60 -32
  97. package/src/ui/palette/ScaleCurveEditor.svelte +25 -10
  98. package/src/ui/sections/ColumnsSection.svelte +13 -13
  99. package/src/ui/sections/GradientsSection.svelte +12 -9
  100. package/src/ui/sections/OverlaysSection.svelte +50 -47
  101. package/src/ui/sections/ShadowsSection.svelte +110 -104
  102. package/src/ui/sections/TokenScaleTable.svelte +38 -22
  103. package/src/ui/sections/tokenScales.ts +2 -2
@@ -1,17 +1,26 @@
1
1
  <script lang="ts">
2
- import { createEventDispatcher, onMount, onDestroy } from 'svelte';
2
+ import { onMount, onDestroy } from 'svelte';
3
3
 
4
4
  type Source = { name: string; label: string; states: string[] };
5
5
 
6
- export let toState: string;
7
- export let variantName: string;
8
- export let copySources: Source[] = [];
9
- export let placement: 'start' | 'end' = 'start';
6
+ interface Props {
7
+ toState: string;
8
+ variantName: string;
9
+ copySources?: Source[];
10
+ placement?: 'start' | 'end';
11
+ onselect?: (payload: { fromVariant: string; fromState: string }) => void;
12
+ }
10
13
 
11
- const dispatch = createEventDispatcher<{ select: { fromVariant: string; fromState: string } }>();
14
+ let {
15
+ toState,
16
+ variantName,
17
+ copySources = [],
18
+ placement = 'start',
19
+ onselect
20
+ }: Props = $props();
12
21
 
13
- let open = false;
14
- let root: HTMLElement;
22
+ let open = $state(false);
23
+ let root: HTMLElement | undefined = $state();
15
24
 
16
25
  function toggle() {
17
26
  open = !open;
@@ -19,7 +28,7 @@
19
28
 
20
29
  function pick(fromVariant: string, fromState: string) {
21
30
  open = false;
22
- dispatch('select', { fromVariant, fromState });
31
+ onselect?.({ fromVariant, fromState });
23
32
  }
24
33
 
25
34
  function handleDocClick(e: MouseEvent) {
@@ -47,7 +56,7 @@
47
56
  type="button"
48
57
  class="copy-from-btn"
49
58
  class:active={open}
50
- on:click={toggle}
59
+ onclick={toggle}
51
60
  title="Copy values from another variant/state"
52
61
  >
53
62
  <i class="fas fa-clone"></i>
@@ -63,7 +72,7 @@
63
72
  type="button"
64
73
  class="copy-menu-item"
65
74
  disabled={isSelf}
66
- on:click={() => pick(src.name, onlyState)}
75
+ onclick={() => pick(src.name, onlyState)}
67
76
  role="menuitem"
68
77
  >
69
78
  <span>{src.label}</span>
@@ -87,7 +96,7 @@
87
96
  type="button"
88
97
  class="copy-menu-item"
89
98
  disabled={isSelf}
90
- on:click={() => pick(src.name, fromState)}
99
+ onclick={() => pick(src.name, fromState)}
91
100
  role="menuitem"
92
101
  >
93
102
  <span>{fromState}</span>
@@ -1,10 +1,19 @@
1
1
  <script lang="ts">
2
2
  import ComponentFileManager from './ComponentFileManager.svelte';
3
3
 
4
- export let component: string;
5
- export let title: string;
6
- export let description: string = '';
7
- export let resetVariables: string[] | null = null;
4
+ interface Props {
5
+ component: string;
6
+ title: string;
7
+ description?: string;
8
+ resetVariables?: string[] | null;
9
+ }
10
+
11
+ let {
12
+ component,
13
+ title,
14
+ description = '',
15
+ resetVariables = null
16
+ }: Props = $props();
8
17
  </script>
9
18
 
10
19
  <ComponentFileManager {component} {title} {resetVariables} />
@@ -6,16 +6,29 @@
6
6
  import { BORDER_WIDTH, DIVIDER_HEIGHT } from '../../ui/variantScales';
7
7
  import FieldsetWrapper from './FieldsetWrapper.svelte';
8
8
 
9
- export let colorVariable: string | undefined = undefined;
10
- export let colorLabel: string | undefined = undefined;
11
- export let widthVariable: string | undefined = undefined;
12
- export let widthLabel: string | undefined = undefined;
13
- export let heightVariable: string | undefined = undefined;
14
- export let heightLabel: string | undefined = undefined;
15
- /** When set, writes persist through the editor store under this component. */
16
- export let component: string | undefined = undefined;
9
+
10
+ interface Props {
11
+ colorVariable?: string | undefined;
12
+ colorLabel?: string | undefined;
13
+ widthVariable?: string | undefined;
14
+ widthLabel?: string | undefined;
15
+ heightVariable?: string | undefined;
16
+ heightLabel?: string | undefined;
17
+ /** When set, writes persist through the editor store under this component. */
18
+ component?: string | undefined;
19
+ }
20
+
21
+ let {
22
+ colorVariable = undefined,
23
+ colorLabel = undefined,
24
+ widthVariable = undefined,
25
+ widthLabel = undefined,
26
+ heightVariable = undefined,
27
+ heightLabel = undefined,
28
+ component = undefined
29
+ }: Props = $props();
17
30
 
18
- let heightResolved = '';
31
+ let heightResolved = $state('');
19
32
 
20
33
  function readHeight() {
21
34
  if (!heightVariable) {
@@ -41,26 +54,26 @@
41
54
  document.removeEventListener(CSS_VAR_CHANGE_EVENT, handleVarChange);
42
55
  });
43
56
 
44
- $: heightIsZero = /^0+(?:\.0+)?(px|rem|em|%)?$/.test(heightResolved);
45
- $: siblingDisabled = heightIsZero;
57
+ let heightIsZero = $derived(/^0+(?:\.0+)?(px|rem|em|%)?$/.test(heightResolved));
58
+ let siblingDisabled = $derived(heightIsZero);
46
59
  </script>
47
60
 
48
61
  <FieldsetWrapper legend="divider">
49
62
  {#if colorVariable}
50
63
  <div class="entry">
51
- <UIPaletteSelector variable={colorVariable} {component} disabled={siblingDisabled} on:change={readHeight} />
64
+ <UIPaletteSelector variable={colorVariable} {component} disabled={siblingDisabled} onchange={readHeight} />
52
65
  <span class="label">{colorLabel ?? ''}</span>
53
66
  </div>
54
67
  {/if}
55
68
  {#if widthVariable}
56
69
  <div class="entry">
57
- <UIVariantSelector variable={widthVariable} {component} disabled={siblingDisabled} {...BORDER_WIDTH} on:change={readHeight} />
70
+ <UIVariantSelector variable={widthVariable} {component} disabled={siblingDisabled} {...BORDER_WIDTH} onchange={readHeight} />
58
71
  <span class="label">{widthLabel ?? ''}</span>
59
72
  </div>
60
73
  {/if}
61
74
  {#if heightVariable}
62
75
  <div class="entry">
63
- <UIVariantSelector variable={heightVariable} {component} {...DIVIDER_HEIGHT} on:change={readHeight} />
76
+ <UIVariantSelector variable={heightVariable} {component} {...DIVIDER_HEIGHT} onchange={readHeight} />
64
77
  <span class="label">{heightLabel ?? ''}</span>
65
78
  </div>
66
79
  {/if}
@@ -1,7 +1,13 @@
1
1
  <script lang="ts">
2
- export let legend: string = '';
3
- /** When true, the fieldset is rendered with a strong outline to mark it as the one currently driving the rendered preview. */
4
- export let active: boolean = false;
2
+
3
+ interface Props {
4
+ legend?: string;
5
+ /** When true, the fieldset is rendered with a strong outline to mark it as the one currently driving the rendered preview. */
6
+ active?: boolean;
7
+ children?: import('svelte').Snippet;
8
+ }
9
+
10
+ let { legend = '', active = false, children }: Props = $props();
5
11
  </script>
6
12
 
7
13
  <fieldset class="fieldset-wrapper" class:active>
@@ -9,7 +15,7 @@
9
15
  <legend class="fieldset-legend">{legend}</legend>
10
16
  {/if}
11
17
  <div class="fieldset-controls">
12
- <slot />
18
+ {@render children?.()}
13
19
  </div>
14
20
  </fieldset>
15
21
 
@@ -16,14 +16,19 @@
16
16
  import UIPaletteSelector from '../../ui/UIPaletteSelector.svelte';
17
17
  import AngleDial from './AngleDial.svelte';
18
18
 
19
- export let component: string;
20
- /** Prefix shared by all 7 token names — e.g. `--sectiondivider-canvas`. */
21
- export let prefix: string;
19
+
20
+ interface Props {
21
+ component: string;
22
+ /** Prefix shared by all 7 token names — e.g. `--sectiondivider-canvas`. */
23
+ prefix: string;
24
+ }
25
+
26
+ let { component, prefix }: Props = $props();
22
27
 
23
28
  type StopIndex = 1 | 2 | 3;
24
29
  const STOPS: readonly StopIndex[] = [1, 2, 3] as const;
25
30
 
26
- $: angleVar = `${prefix}-gradient-angle`;
31
+ let angleVar = $derived(`${prefix}-gradient-angle`);
27
32
  function stopColorVar(i: StopIndex): string {
28
33
  return `${prefix}-gradient-stop-${i}-color`;
29
34
  }
@@ -52,27 +57,27 @@
52
57
  return m ? parseFloat(m[1]) : null;
53
58
  }
54
59
 
55
- $: angleDeg = parseNumberFromCss(resolveLiteralWith($tokenRegistry$, angleVar), 'deg') ?? 135;
56
- $: positions = [
60
+ let angleDeg = $derived(parseNumberFromCss(resolveLiteralWith($tokenRegistry$, angleVar), 'deg') ?? 135);
61
+ let positions = $derived([
57
62
  parseNumberFromCss(resolveLiteralWith($tokenRegistry$, stopPositionVar(1)), '%') ?? 0,
58
63
  parseNumberFromCss(resolveLiteralWith($tokenRegistry$, stopPositionVar(2)), '%') ?? 50,
59
64
  parseNumberFromCss(resolveLiteralWith($tokenRegistry$, stopPositionVar(3)), '%') ?? 100,
60
- ] as [number, number, number];
65
+ ] as [number, number, number]);
61
66
 
62
67
  // Reference the per-stop CSS var directly so the cascade fills in the
63
68
  // component's CSS defaults when the user hasn't overridden a stop. Reading
64
69
  // `aliases[...]` alone would miss defaults (no override → `#888`) even
65
70
  // though the component is rendering the color via its own `:root` block.
66
- $: stopColors = ([1, 2, 3] as StopIndex[]).map((i) => `var(${stopColorVar(i)})`) as [string, string, string];
71
+ let stopColors = $derived(([1, 2, 3] as StopIndex[]).map((i) => `var(${stopColorVar(i)})`) as [string, string, string]);
67
72
 
68
73
  // Build the live gradient string from current positions + colors so the
69
74
  // ribbon reflects edits even mid-drag (before the component re-renders via
70
75
  // its own CSS var consumption).
71
- $: ribbonBg = `linear-gradient(90deg, ${stopColors
76
+ let ribbonBg = $derived(`linear-gradient(90deg, ${stopColors
72
77
  .map((c, i) => `${c} ${positions[i]}%`)
73
- .join(', ')})`;
78
+ .join(', ')})`);
74
79
 
75
- let selected: StopIndex = 1;
80
+ let selected: StopIndex = $state(1);
76
81
 
77
82
  function setAngle(deg: number) {
78
83
  setComponentAlias(component, angleVar, { kind: 'literal', value: `${Math.round(deg)}deg` });
@@ -84,11 +89,11 @@
84
89
  }
85
90
 
86
91
  // ── Position handle drag ────────────────────────────────────────────────
87
- let barEl: HTMLDivElement;
88
- let dragIndex: StopIndex | null = null;
92
+ let barEl: HTMLDivElement | undefined = $state();
93
+ let dragIndex: StopIndex | null = $state(null);
89
94
 
90
95
  function pctFromEvent(e: PointerEvent): number {
91
- const rect = barEl.getBoundingClientRect();
96
+ const rect = barEl!.getBoundingClientRect();
92
97
  const x = e.clientX - rect.left;
93
98
  return (x / rect.width) * 100;
94
99
  }
@@ -126,10 +131,10 @@
126
131
  class:selected={selected === i}
127
132
  class:dragging={dragIndex === i}
128
133
  style="left: {positions[i - 1]}%; --stop-color: {stopColors[i - 1]};"
129
- on:pointerdown={(e) => onHandleDown(e, i)}
130
- on:pointermove={onHandleMove}
131
- on:pointerup={onHandleUp}
132
- on:pointercancel={onHandleUp}
134
+ onpointerdown={(e) => onHandleDown(e, i)}
135
+ onpointermove={onHandleMove}
136
+ onpointerup={onHandleUp}
137
+ onpointercancel={onHandleUp}
133
138
  title="Stop {i} ({positions[i - 1]}%)"
134
139
  aria-label="Gradient stop {i}"
135
140
  >
@@ -148,7 +153,7 @@
148
153
  max="100"
149
154
  step="0.1"
150
155
  value={positions[selected - 1]}
151
- on:change={(e) => onPositionInput(selected, e)}
156
+ onchange={(e) => onPositionInput(selected, e)}
152
157
  />
153
158
  <span class="suffix">%</span>
154
159
  </label>
@@ -156,7 +161,7 @@
156
161
  <UIPaletteSelector variable={stopColorVar(selected)} {component} />
157
162
  </div>
158
163
  <div class="angle-slot">
159
- <AngleDial value={angleDeg} on:change={(e) => setAngle(e.detail.value)} />
164
+ <AngleDial value={angleDeg} onchange={(d) => setAngle(d.value)} />
160
165
  </div>
161
166
  </div>
162
167
  </div>
@@ -1,4 +1,4 @@
1
- <script context="module" lang="ts">
1
+ <script module lang="ts">
2
2
  type CellStatus = 'linked' | 'broken' | 'absent';
3
3
  type RowEntry = { label: string; key: string };
4
4
  type Axes =
@@ -34,37 +34,46 @@
34
34
  </script>
35
35
 
36
36
  <script lang="ts">
37
- import { createEventDispatcher } from 'svelte';
38
-
39
- export let contexts: string[] = [];
40
- export let broken: string[] = [];
41
- export let singleAxisLabel: string = '';
42
- /** Caption rendered above the grid. Use to describe the linkage scope
37
+ interface Props {
38
+ contexts?: string[];
39
+ broken?: string[];
40
+ singleAxisLabel?: string;
41
+ /** Caption rendered above the grid. Use to describe the linkage scope
43
42
  (e.g. "Links across variants and states"). Defaults to the legacy
44
43
  "Linked Properties" label so consumers that don't pass a caption
45
44
  keep their existing rendering. */
46
- export let caption: string = 'Linked Properties';
47
- /** Currently focused variant (matches a row in 2d / a row label in 1d). When set,
45
+ caption?: string;
46
+ /** Currently focused variant (matches a row in 2d / a row label in 1d). When set,
48
47
  the matching row is highlighted with the same active style as the variant tab strip. */
49
- export let selectedRow: string | null = null;
50
- /** Currently focused state (matches a column in 2d). The cell at (selectedRow, selectedCol)
48
+ selectedRow?: string | null;
49
+ /** Currently focused state (matches a column in 2d). The cell at (selectedRow, selectedCol)
51
50
  gets an additional accent. Ignored in 1d charts. */
52
- export let selectedCol: string | null = null;
51
+ selectedCol?: string | null;
52
+ onselect?: (label: string) => void;
53
+ }
53
54
 
54
- const dispatch = createEventDispatcher<{ select: string }>();
55
+ let {
56
+ contexts = [],
57
+ broken = [],
58
+ singleAxisLabel = '',
59
+ caption = 'Linked Properties',
60
+ selectedRow = null,
61
+ selectedCol = null,
62
+ onselect
63
+ }: Props = $props();
55
64
 
56
- $: axes = deriveAxes(contexts);
57
- $: status = (() => {
65
+ let axes = $derived(deriveAxes(contexts));
66
+ let status = $derived((() => {
58
67
  const brokenSet = new Set(broken);
59
68
  const m = new Map<string, CellStatus>();
60
69
  for (const c of contexts) m.set(c, brokenSet.has(c) ? 'broken' : 'linked');
61
70
  return m;
62
- })();
71
+ })());
63
72
 
64
- let hoveredRow: number = -1;
73
+ let hoveredRow: number = $state(-1);
65
74
 
66
75
  function key2d(r: string, c: string): string { return `${r} ${c}`; }
67
- function selectRow(label: string) { dispatch('select', label); }
76
+ function selectRow(label: string) { onselect?.(label); }
68
77
  /** True when this 1d row's key matches focus — either as a bare label
69
78
  (`"primary"` matches focusedVariant `"primary"`) or as a compound
70
79
  `"variant state"` matching the focused pair. */
@@ -92,11 +101,11 @@
92
101
  class="row-h row-target"
93
102
  class:hovered={hoveredRow === i}
94
103
  class:selected={selectedRow === r}
95
- on:click={() => selectRow(r)}
96
- on:mouseenter={() => (hoveredRow = i)}
97
- on:mouseleave={() => (hoveredRow = -1)}
98
- on:focus={() => (hoveredRow = i)}
99
- on:blur={() => (hoveredRow = -1)}
104
+ onclick={() => selectRow(r)}
105
+ onmouseenter={() => (hoveredRow = i)}
106
+ onmouseleave={() => (hoveredRow = -1)}
107
+ onfocus={() => (hoveredRow = i)}
108
+ onblur={() => (hoveredRow = -1)}
100
109
  >{r}</button>
101
110
  {#each axes.cols as c (c)}
102
111
  {@const st = status.get(key2d(r, c)) ?? 'absent'}
@@ -108,9 +117,9 @@
108
117
  class:selected={selectedRow === r && selectedCol === c}
109
118
  class:in-selected-row={selectedRow === r && selectedCol !== c}
110
119
  aria-label="{r} {c}: {st}"
111
- on:click={() => selectRow(r)}
112
- on:mouseenter={() => (hoveredRow = i)}
113
- on:mouseleave={() => (hoveredRow = -1)}
120
+ onclick={() => selectRow(r)}
121
+ onmouseenter={() => (hoveredRow = i)}
122
+ onmouseleave={() => (hoveredRow = -1)}
114
123
  >
115
124
  {#if st === 'linked'}
116
125
  <span class="dot" aria-hidden="true"></span>
@@ -138,11 +147,11 @@
138
147
  class="row-h row-target"
139
148
  class:hovered={hoveredRow === i}
140
149
  class:selected={isSel}
141
- on:click={() => selectRow(r.label)}
142
- on:mouseenter={() => (hoveredRow = i)}
143
- on:mouseleave={() => (hoveredRow = -1)}
144
- on:focus={() => (hoveredRow = i)}
145
- on:blur={() => (hoveredRow = -1)}
150
+ onclick={() => selectRow(r.label)}
151
+ onmouseenter={() => (hoveredRow = i)}
152
+ onmouseleave={() => (hoveredRow = -1)}
153
+ onfocus={() => (hoveredRow = i)}
154
+ onblur={() => (hoveredRow = -1)}
146
155
  >{r.label}</button>
147
156
  <button
148
157
  type="button"
@@ -151,9 +160,9 @@
151
160
  class:hovered={hoveredRow === i}
152
161
  class:selected={isSel}
153
162
  aria-label="{r.label}: {st}"
154
- on:click={() => selectRow(r.label)}
155
- on:mouseenter={() => (hoveredRow = i)}
156
- on:mouseleave={() => (hoveredRow = -1)}
163
+ onclick={() => selectRow(r.label)}
164
+ onmouseenter={() => (hoveredRow = i)}
165
+ onmouseleave={() => (hoveredRow = -1)}
157
166
  >
158
167
  {#if st === 'linked'}
159
168
  <span class="dot" aria-hidden="true"></span>
@@ -13,8 +13,12 @@
13
13
  const fadeDur = reduceMotion ? 0 : 140;
14
14
  const slideDur = reduceMotion ? 0 : 200;
15
15
 
16
- export let component: string;
17
- export let linked: LinkedBlockResult;
16
+ interface Props {
17
+ component: string;
18
+ linked: LinkedBlockResult;
19
+ }
20
+
21
+ let { component, linked }: Props = $props();
18
22
 
19
23
  const editorCtx = getEditorContext();
20
24
  const focusedVariant = editorCtx?.focusedVariant;
@@ -25,9 +29,9 @@
25
29
  doesn't know if its rows are variants (top-level tab strip) or states (per-VariantGroup
26
30
  state tabs), so we set both stores; each consumer adopts the value only if it names
27
31
  one of its own tabs. */
28
- function handleChartSelect(e: CustomEvent<string>) {
29
- editorCtx?.focusedVariant.set(e.detail);
30
- editorCtx?.focusedState.set(e.detail);
32
+ function handleChartSelect(label: string) {
33
+ editorCtx?.focusedVariant.set(label);
34
+ editorCtx?.focusedState.set(label);
31
35
  }
32
36
 
33
37
  /** Pick the sibling that backs the cell the user is currently focused on, so the row
@@ -71,35 +75,35 @@
71
75
  return `${brokenContexts.length} unlinked`;
72
76
  }
73
77
 
74
- $: focusedV = (focusedVariant ? $focusedVariant : null) ?? null;
75
- $: focusedS = (focusedState ? $focusedState : null) ?? null;
76
- $: hoveredVar = (hoveredLinkedVariable ? $hoveredLinkedVariable : null) ?? null;
78
+ let focusedV = $derived((focusedVariant ? $focusedVariant : null) ?? null);
79
+ let focusedS = $derived((focusedState ? $focusedState : null) ?? null);
80
+ let hoveredVar = $derived((hoveredLinkedVariable ? $hoveredLinkedVariable : null) ?? null);
77
81
 
78
82
  function setHover(variable: string | null) {
79
83
  hoveredLinkedVariable?.set(variable);
80
84
  }
81
85
 
82
86
  /** One card per LinkedGroup. Stable order = editor-declared order. */
83
- $: cards = linked.groups.map((g) => ({
87
+ let cards = $derived(linked.groups.map((g) => ({
84
88
  contexts: g.contexts,
85
89
  brokenContexts: g.brokenContexts,
86
90
  row: { ...g.token, variable: pickFocusedVariable(g, focusedV, focusedS) },
87
91
  caption: captionFor(g.contexts),
88
92
  unlinkedText: formatUnlinked(g.brokenContexts),
89
93
  isBroken: g.brokenContexts.length > 0,
90
- }));
94
+ })));
91
95
 
92
96
  /** Section-level summary: count of properties with any broken peers. The
93
97
  header tells the user *whether to look*; the per-card text tells them
94
98
  *what's broken*. Two layers, two granularities. */
95
- $: brokenPropertyCount = cards.filter((c) => c.isBroken).length;
96
- $: hasAnyBroken = brokenPropertyCount > 0;
99
+ let brokenPropertyCount = $derived(cards.filter((c) => c.isBroken).length);
100
+ let hasAnyBroken = $derived(brokenPropertyCount > 0);
97
101
 
98
102
  /** Default closed; the section header's summary count + "in sync / N unlinked"
99
103
  text is the at-a-glance signal, so users opt into the matrix only when
100
104
  they need it. */
101
- let sectionToggleOverride: boolean | null = null;
102
- $: sectionExpanded = sectionToggleOverride ?? false;
105
+ let sectionToggleOverride: boolean | null = $state(null);
106
+ let sectionExpanded = $derived(sectionToggleOverride ?? false);
103
107
  function toggleSection() {
104
108
  sectionToggleOverride = !sectionExpanded;
105
109
  }
@@ -107,7 +111,7 @@
107
111
  /** Per-card chart expand state, keyed by the card's row variable (which is
108
112
  stable per LinkedGroup since pickFocusedVariable runs against the same
109
113
  group on every render). */
110
- let expandedCards: Record<string, boolean> = {};
114
+ let expandedCards: Record<string, boolean> = $state({});
111
115
  function toggleCard(variable: string) {
112
116
  expandedCards = { ...expandedCards, [variable]: !expandedCards[variable] };
113
117
  }
@@ -120,7 +124,7 @@
120
124
  class="section-header"
121
125
  class:expanded={sectionExpanded}
122
126
  aria-expanded={sectionExpanded}
123
- on:click={toggleSection}
127
+ onclick={toggleSection}
124
128
  >
125
129
  <i class="fas fa-chevron-right chevron"></i>
126
130
  <span class="section-title">Linked properties</span>
@@ -144,8 +148,8 @@
144
148
  class="linked-card"
145
149
  class:broken={card.isBroken}
146
150
  class:hovered={cardHovered}
147
- on:mouseenter={() => setHover(card.row.variable)}
148
- on:mouseleave={() => setHover(null)}
151
+ onmouseenter={() => setHover(card.row.variable)}
152
+ onmouseleave={() => setHover(null)}
149
153
  >
150
154
  <h4 class="property-name">{card.row.label}</h4>
151
155
  <div class="control-row">
@@ -154,7 +158,6 @@
154
158
  {component}
155
159
  linkedOrder={linked.linkedOrder}
156
160
  isLinkedBlock
157
- on:change
158
161
  />
159
162
  </div>
160
163
  <button
@@ -162,7 +165,7 @@
162
165
  class="drill-down"
163
166
  class:expanded={cardExpanded}
164
167
  aria-expanded={cardExpanded}
165
- on:click={() => toggleCard(card.row.variable)}
168
+ onclick={() => toggleCard(card.row.variable)}
166
169
  >
167
170
  <i class="fas fa-chevron-right chevron"></i>
168
171
  <span class="drill-label">Links</span>
@@ -181,7 +184,7 @@
181
184
  caption={card.caption}
182
185
  selectedRow={focusedV}
183
186
  selectedCol={focusedS}
184
- on:select={handleChartSelect}
187
+ onselect={handleChartSelect}
185
188
  />
186
189
  </div>
187
190
  {/if}
@@ -1,4 +1,9 @@
1
1
  <script lang="ts">
2
+ interface Props {
3
+ children?: import('svelte').Snippet;
4
+ }
5
+
6
+ let { children }: Props = $props();
2
7
  /** Section that gathers render-time toggles a component accepts as props
3
8
  (e.g. dismissible, action buttons, hover shimmer, show icons). */
4
9
  </script>
@@ -9,7 +14,7 @@
9
14
  <p class="config-description">Component accepts multiple properties that can change its layout. Use these to preview.</p>
10
15
  </header>
11
16
  <div class="config-controls">
12
- <slot />
17
+ {@render children?.()}
13
18
  </div>
14
19
  </section>
15
20