@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
@@ -20,7 +20,7 @@
20
20
 
21
21
  // Bumped on breakpoint flips; passed to TokenScaleTable so it re-resolves.
22
22
  // tokens.css declares responsive overrides at 768px and 480px.
23
- let liveVersion = 0;
23
+ let liveVersion = $state(0);
24
24
  const BREAKPOINTS = ['(max-width: 768px)', '(max-width: 480px)'] as const;
25
25
 
26
26
  onMount(() => {
@@ -34,7 +34,7 @@
34
34
  };
35
35
  });
36
36
 
37
- let copiedVar: string | null = null;
37
+ let copiedVar: string | null = $state(null);
38
38
  function copyVariable(v: string) {
39
39
  navigator.clipboard.writeText(v);
40
40
  copiedVar = v;
@@ -65,9 +65,9 @@
65
65
  <section class="section" id="spacing">
66
66
  <h2 class="section-title">Spacing &amp; Borders</h2>
67
67
  <h3 class="subsection-title">Spacing</h3>
68
- <TokenScaleTable kind="spacing" vars={SPACING_VARS} {liveVersion} {copiedVar} on:copy={(e) => copyVariable(e.detail)} />
68
+ <TokenScaleTable kind="spacing" vars={SPACING_VARS} {liveVersion} {copiedVar} oncopy={copyVariable} />
69
69
  <h3 class="subsection-title">Borders</h3>
70
- <TokenScaleTable kind="border" vars={BORDER_WIDTH_VARS} {liveVersion} {copiedVar} on:copy={(e) => copyVariable(e.detail)} />
70
+ <TokenScaleTable kind="border" vars={BORDER_WIDTH_VARS} {liveVersion} {copiedVar} oncopy={copyVariable} />
71
71
  </section>
72
72
 
73
73
  <!-- Columns -->
@@ -76,7 +76,7 @@
76
76
  <!-- Border Radius -->
77
77
  <section class="section" id="border-radius">
78
78
  <h2 class="section-title">Border Radius</h2>
79
- <TokenScaleTable kind="radius" vars={RADIUS_VARS} {liveVersion} {copiedVar} on:copy={(e) => copyVariable(e.detail)} />
79
+ <TokenScaleTable kind="radius" vars={RADIUS_VARS} {liveVersion} {copiedVar} oncopy={copyVariable} />
80
80
  </section>
81
81
 
82
82
  <!-- Typography -->
@@ -92,17 +92,17 @@
92
92
 
93
93
  <div class="typography-group">
94
94
  <h3 class="group-title">Font Sizes</h3>
95
- <TokenScaleTable kind="font-size" vars={FONT_SIZE_VARS} {liveVersion} {copiedVar} on:copy={(e) => copyVariable(e.detail)} />
95
+ <TokenScaleTable kind="font-size" vars={FONT_SIZE_VARS} {liveVersion} {copiedVar} oncopy={copyVariable} />
96
96
  </div>
97
97
 
98
98
  <div class="typography-group">
99
99
  <h3 class="group-title">Font Weights</h3>
100
- <TokenScaleTable kind="font-weight" vars={FONT_WEIGHT_VARS} {liveVersion} {copiedVar} on:copy={(e) => copyVariable(e.detail)} />
100
+ <TokenScaleTable kind="font-weight" vars={FONT_WEIGHT_VARS} {liveVersion} {copiedVar} oncopy={copyVariable} />
101
101
  </div>
102
102
 
103
103
  <div class="typography-group">
104
104
  <h3 class="group-title">Line Heights</h3>
105
- <TokenScaleTable kind="line-height" vars={LINE_HEIGHT_VARS} {liveVersion} {copiedVar} on:copy={(e) => copyVariable(e.detail)} />
105
+ <TokenScaleTable kind="line-height" vars={LINE_HEIGHT_VARS} {liveVersion} {copiedVar} oncopy={copyVariable} />
106
106
  </div>
107
107
  </div>
108
108
  </section>
@@ -110,19 +110,19 @@
110
110
  <!-- Icon Sizes -->
111
111
  <section class="section" id="icon-sizes">
112
112
  <h2 class="section-title">Icon Sizes</h2>
113
- <TokenScaleTable kind="icon-size" vars={ICON_SIZE_VARS} {liveVersion} {copiedVar} on:copy={(e) => copyVariable(e.detail)} />
113
+ <TokenScaleTable kind="icon-size" vars={ICON_SIZE_VARS} {liveVersion} {copiedVar} oncopy={copyVariable} />
114
114
  </section>
115
115
 
116
116
 
117
117
  <!-- Shadows -->
118
- <ShadowsSection {copiedVar} on:copy={(e) => copyVariable(e.detail)} />
118
+ <ShadowsSection {copiedVar} oncopy={copyVariable} />
119
119
 
120
120
 
121
121
  <!-- Overlays -->
122
- <OverlaysSection {copiedVar} on:copy={(e) => copyVariable(e.detail)} />
122
+ <OverlaysSection {copiedVar} oncopy={copyVariable} />
123
123
 
124
124
  <!-- Gradients -->
125
- <GradientsSection {copiedVar} on:copy={(e) => copyVariable(e.detail)} />
125
+ <GradientsSection {copiedVar} oncopy={copyVariable} />
126
126
 
127
127
  <!-- Utility Tokens -->
128
128
  <section class="section" id="utility-tokens">
@@ -130,17 +130,17 @@
130
130
  <div class="utility-columns">
131
131
  <div class="utility-group">
132
132
  <h3 class="group-title">Durations</h3>
133
- <TokenScaleTable kind="line-height" tokens={DURATION_TOKENS} {copiedVar} on:copy={(e) => copyVariable(e.detail)} />
133
+ <TokenScaleTable kind="line-height" tokens={DURATION_TOKENS} {copiedVar} oncopy={copyVariable} />
134
134
  </div>
135
135
 
136
136
  <div class="utility-group">
137
137
  <h3 class="group-title">Z-Index Layers</h3>
138
- <TokenScaleTable kind="line-height" tokens={Z_INDEX_TOKENS} {copiedVar} on:copy={(e) => copyVariable(e.detail)} />
138
+ <TokenScaleTable kind="line-height" tokens={Z_INDEX_TOKENS} {copiedVar} oncopy={copyVariable} />
139
139
  </div>
140
140
 
141
141
  <div class="utility-group">
142
142
  <h3 class="group-title">Opacity</h3>
143
- <TokenScaleTable kind="line-height" tokens={OPACITY_TOKENS} {copiedVar} on:copy={(e) => copyVariable(e.detail)} />
143
+ <TokenScaleTable kind="line-height" tokens={OPACITY_TOKENS} {copiedVar} oncopy={copyVariable} />
144
144
  </div>
145
145
  </div>
146
146
  </section>
@@ -1,4 +1,6 @@
1
1
  <script lang="ts">
2
+ import { stopPropagation } from 'svelte/legacy';
3
+
2
4
  import type { GradientStyle, GradientStop } from '../../lib/themeTypes';
3
5
  import { beginSliderGesture } from '../../lib/editorStore';
4
6
 
@@ -16,19 +18,36 @@
16
18
 
17
19
  interface PaletteStep { label: string; hex: string }
18
20
 
19
- export let gradientStyle: GradientStyle;
20
- export let gradientAngle: number;
21
- export let gradientSize: 'page' | 'window';
22
- export let gradientReverse: boolean;
23
- export let gradientStops: GradientStop[];
24
- export let gradientBarPreview: string;
25
- export let paletteComputed: PaletteStep[];
26
21
 
27
- export let onSetGradientStyle: (style: GradientStyle) => void;
28
- export let onSetGradientSize: (size: 'page' | 'window') => void;
29
- export let onSetGradientAngle: (angle: number) => void;
30
- export let onSetGradientReverse: (reverse: boolean) => void;
31
- export let onSetGradientStops: (stops: GradientStop[]) => void;
22
+ interface Props {
23
+ gradientStyle: GradientStyle;
24
+ gradientAngle: number;
25
+ gradientSize: 'page' | 'window';
26
+ gradientReverse: boolean;
27
+ gradientStops: GradientStop[];
28
+ gradientBarPreview: string;
29
+ paletteComputed: PaletteStep[];
30
+ onSetGradientStyle: (style: GradientStyle) => void;
31
+ onSetGradientSize: (size: 'page' | 'window') => void;
32
+ onSetGradientAngle: (angle: number) => void;
33
+ onSetGradientReverse: (reverse: boolean) => void;
34
+ onSetGradientStops: (stops: GradientStop[]) => void;
35
+ }
36
+
37
+ let {
38
+ gradientStyle,
39
+ gradientAngle,
40
+ gradientSize,
41
+ gradientReverse,
42
+ gradientStops,
43
+ gradientBarPreview,
44
+ paletteComputed,
45
+ onSetGradientStyle,
46
+ onSetGradientSize,
47
+ onSetGradientAngle,
48
+ onSetGradientReverse,
49
+ onSetGradientStops
50
+ }: Props = $props();
32
51
 
33
52
  const gradientStyleOptions: { value: GradientStyle; icon: string; title: string }[] = [
34
53
  { value: 'linear', icon: '/', title: 'Linear' },
@@ -41,7 +60,7 @@
41
60
  { value: 'window', label: 'Window', title: 'Gradient stays fixed to the viewport' },
42
61
  ];
43
62
 
44
- let selectedStopIndex = 0;
63
+ let selectedStopIndex = $state(0);
45
64
  let draggingStopIndex: number | null = null;
46
65
 
47
66
  function stopColor(stop: GradientStop): string {
@@ -152,7 +171,7 @@
152
171
  class:active={gradientStyle === opt.value}
153
172
  type="button"
154
173
  title={opt.title}
155
- on:click={() => onSetGradientStyle(opt.value)}
174
+ onclick={() => onSetGradientStyle(opt.value)}
156
175
  >{opt.icon}</button>
157
176
  {/each}
158
177
  </div>
@@ -166,7 +185,7 @@
166
185
  min="0"
167
186
  max="360"
168
187
  value={gradientAngle}
169
- on:input={onAngleInput}
188
+ oninput={onAngleInput}
170
189
  />
171
190
  <span class="gradient-unit">deg</span>
172
191
  <input
@@ -175,7 +194,7 @@
175
194
  min="0"
176
195
  max="360"
177
196
  value={gradientAngle}
178
- on:input={onAngleInput}
197
+ oninput={onAngleInput}
179
198
  />
180
199
  </div>
181
200
 
@@ -188,7 +207,7 @@
188
207
  class:active={gradientSize === opt.value}
189
208
  type="button"
190
209
  title={opt.title}
191
- on:click={() => onSetGradientSize(opt.value)}
210
+ onclick={() => onSetGradientSize(opt.value)}
192
211
  >{opt.label}</button>
193
212
  {/each}
194
213
  </div>
@@ -196,7 +215,7 @@
196
215
 
197
216
  <div class="gradient-row">
198
217
  <label class="gradient-checkbox-label">
199
- <input type="checkbox" checked={gradientReverse} on:change={onReverseChange} />
218
+ <input type="checkbox" checked={gradientReverse} onchange={onReverseChange} />
200
219
  Reverse
201
220
  </label>
202
221
  </div>
@@ -205,15 +224,15 @@
205
224
  <div class="gradient-stop-bar-wrapper">
206
225
  <div class="gradient-stop-handles">
207
226
  {#each gradientStops as stop, i}
208
- <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
227
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
209
228
  <div
210
229
  class="gradient-stop-handle"
211
230
  class:selected={selectedStopIndex === i}
212
231
  style="left: {stop.position}%; --stop-color: {stopColor(stop)}"
213
- on:mousedown|stopPropagation={(e) => handleStopHandleMouseDown(e, i)}
232
+ onmousedown={stopPropagation((e) => handleStopHandleMouseDown(e as MouseEvent, i))}
214
233
  role="button"
215
234
  tabindex="0"
216
- on:keydown={(e) => {
235
+ onkeydown={(e) => {
217
236
  if (e.key === 'Delete' || e.key === 'Backspace') removeGradientStop(i);
218
237
  }}
219
238
  >
@@ -222,11 +241,11 @@
222
241
  </div>
223
242
  {/each}
224
243
  </div>
225
- <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
244
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
226
245
  <div
227
246
  class="gradient-stop-bar"
228
247
  style="background: {gradientBarPreview}"
229
- on:mousedown={handleStopBarMouseDown}
248
+ onmousedown={handleStopBarMouseDown}
230
249
  role="slider"
231
250
  tabindex="0"
232
251
  aria-label="Gradient stops"
@@ -243,7 +262,7 @@
243
262
  <select
244
263
  class="gradient-select"
245
264
  value={gradientStops[selectedStopIndex].paletteLabel}
246
- on:change={onStopColorChange}
265
+ onchange={onStopColorChange}
247
266
  >
248
267
  {#each paletteComputed as ps}
249
268
  <option value={ps.label}>{ps.label}</option>
@@ -257,7 +276,7 @@
257
276
  min="0"
258
277
  max="100"
259
278
  value={gradientStops[selectedStopIndex].position}
260
- on:change={onStopPositionChange}
279
+ onchange={onStopPositionChange}
261
280
  />
262
281
  <span class="gradient-unit">%</span>
263
282
  {#if gradientStops.length > 2}
@@ -265,7 +284,7 @@
265
284
  class="stop-remove-btn"
266
285
  type="button"
267
286
  title="Remove stop"
268
- on:click={() => removeGradientStop(selectedStopIndex)}
287
+ onclick={() => removeGradientStop(selectedStopIndex)}
269
288
  >&times;</button>
270
289
  {/if}
271
290
  </div>
@@ -36,37 +36,71 @@
36
36
 
37
37
  interface PaletteStep { label: string; hex: string }
38
38
 
39
- export let scale: Scale;
40
- export let editorOpen: boolean;
41
- export let snapped: boolean;
42
- export let supportsSnap: boolean;
43
- export let cssNamespace: string | null;
44
- export let scaleCurves: Record<string, { lightness: CurveAnchor[]; saturation: CurveAnchor[] }>;
45
- export let curveOffset: Record<string, number>;
46
- export let defaultScaleCurves: Record<string, ScaleCurveDef>;
47
- export let overrides: Record<string, string>;
48
- export let editingKey: string | null;
49
- export let snapPickerKey: string | null;
50
- export let copiedKey: string | null;
51
- export let copiedLabelKey: string | null;
52
- export let paletteComputed: PaletteStep[];
53
-
54
- export let derivedHexFor: (step: Step, scaleTitle: string) => string;
55
- export let effectiveHexFor: (key: string, step: Step, scaleTitle: string) => string;
56
- export let stepKeyFor: (scaleTitle: string, stepName: string) => string;
57
- export let scaleCurveKeyFor: (scaleTitle: string, channel: Channel) => string;
58
-
59
- export let onToggleSnap: (scale: Scale) => void;
60
- export let onClearScaleOverrides: (scale: Scale) => void;
61
- export let onToggleEditor: (scaleTitle: string) => void;
62
- export let onResetOverride: (key: string) => void;
63
- export let onOverrideClick: (key: string, step: Step, scaleTitle: string) => void;
64
- export let onSnappedClick: (key: string) => void;
65
- export let onSelectSnapValue: (key: string, paletteHex: string, scaleTitle: string) => void;
66
- export let onCopyHex: (key: string, hex: string, event?: MouseEvent) => void;
67
- export let onCopyVarName: (key: string, varName: string, event?: MouseEvent) => void;
68
- export let onSetScaleCurve: (scaleTitle: string, channel: Channel, anchors: CurveAnchor[]) => void;
69
- export let onOffsetChange: (key: string, value: number) => void;
39
+
40
+
41
+ interface Props {
42
+ scale: Scale;
43
+ editorOpen: boolean;
44
+ snapped: boolean;
45
+ supportsSnap: boolean;
46
+ cssNamespace: string | null;
47
+ scaleCurves: Record<string, { lightness: CurveAnchor[]; saturation: CurveAnchor[] }>;
48
+ curveOffset: Record<string, number>;
49
+ defaultScaleCurves: Record<string, ScaleCurveDef>;
50
+ overrides: Record<string, string>;
51
+ editingKey: string | null;
52
+ snapPickerKey: string | null;
53
+ copiedKey: string | null;
54
+ copiedLabelKey: string | null;
55
+ paletteComputed: PaletteStep[];
56
+ derivedHexFor: (step: Step, scaleTitle: string) => string;
57
+ effectiveHexFor: (key: string, step: Step, scaleTitle: string) => string;
58
+ stepKeyFor: (scaleTitle: string, stepName: string) => string;
59
+ scaleCurveKeyFor: (scaleTitle: string, channel: Channel) => string;
60
+ onToggleSnap: (scale: Scale) => void;
61
+ onClearScaleOverrides: (scale: Scale) => void;
62
+ onToggleEditor: (scaleTitle: string) => void;
63
+ onResetOverride: (key: string) => void;
64
+ onOverrideClick: (key: string, step: Step, scaleTitle: string) => void;
65
+ onSnappedClick: (key: string) => void;
66
+ onSelectSnapValue: (key: string, paletteHex: string, scaleTitle: string) => void;
67
+ onCopyHex: (key: string, hex: string, event?: MouseEvent) => void;
68
+ onCopyVarName: (key: string, varName: string, event?: MouseEvent) => void;
69
+ onSetScaleCurve: (scaleTitle: string, channel: Channel, anchors: CurveAnchor[]) => void;
70
+ onOffsetChange: (key: string, value: number) => void;
71
+ }
72
+
73
+ let {
74
+ scale,
75
+ editorOpen,
76
+ snapped,
77
+ supportsSnap,
78
+ cssNamespace,
79
+ scaleCurves,
80
+ curveOffset,
81
+ defaultScaleCurves,
82
+ overrides,
83
+ editingKey,
84
+ snapPickerKey,
85
+ copiedKey,
86
+ copiedLabelKey,
87
+ paletteComputed,
88
+ derivedHexFor,
89
+ effectiveHexFor,
90
+ stepKeyFor,
91
+ scaleCurveKeyFor,
92
+ onToggleSnap,
93
+ onClearScaleOverrides,
94
+ onToggleEditor,
95
+ onResetOverride,
96
+ onOverrideClick,
97
+ onSnappedClick,
98
+ onSelectSnapValue,
99
+ onCopyHex,
100
+ onCopyVarName,
101
+ onSetScaleCurve,
102
+ onOffsetChange
103
+ }: Props = $props();
70
104
 
71
105
  interface CurveDescriptor {
72
106
  key: string;
@@ -76,7 +110,7 @@
76
110
  channel: Channel;
77
111
  }
78
112
 
79
- $: curveDescriptors = ((): CurveDescriptor[] => {
113
+ let curveDescriptors = $derived(((): CurveDescriptor[] => {
80
114
  const lightnessCfg = scale.isText ? textLightnessCurveConfig : lightnessCurveConfig;
81
115
  const sc = scaleCurves[scale.title];
82
116
  const defs = defaultScaleCurves[scale.title];
@@ -85,7 +119,7 @@
85
119
  { key: scaleCurveKeyFor(scale.title, 'lightness'), anchors: sc.lightness, cfg: lightnessCfg, defaults: defs.lightness(), channel: 'lightness' },
86
120
  { key: scaleCurveKeyFor(scale.title, 'saturation'), anchors: sc.saturation, cfg: saturationCurveConfig, defaults: defs.saturation(), channel: 'saturation' },
87
121
  ];
88
- })();
122
+ })());
89
123
  </script>
90
124
 
91
125
  <div class="scale-section">
@@ -96,14 +130,14 @@
96
130
  class="edit-toggle"
97
131
  class:active={snapped}
98
132
  type="button"
99
- on:click={() => onToggleSnap(scale)}
133
+ onclick={() => onToggleSnap(scale)}
100
134
  >{snapped ? 'Unsnap' : 'Snap All'}</button>
101
135
  {/if}
102
- <button class="edit-toggle" type="button" on:click={() => onClearScaleOverrides(scale)}>Clear Overrides</button>
136
+ <button class="edit-toggle" type="button" onclick={() => onClearScaleOverrides(scale)}>Clear Overrides</button>
103
137
  <button
104
138
  class="edit-toggle"
105
139
  type="button"
106
- on:click={() => onToggleEditor(scale.title)}
140
+ onclick={() => onToggleEditor(scale.title)}
107
141
  >{editorOpen ? 'Close' : 'Edit'}</button>
108
142
  </div>
109
143
  <div class="swatch-grid" style="--swatch-cols: {scale.steps.length}; --swatch-gap: var(--ui-space-8)">
@@ -112,37 +146,39 @@
112
146
  {@const hex = effectiveHexFor(k, step, scale.title)}
113
147
  {@const dHex = derivedHexFor(step, scale.title)}
114
148
  <div class="step-column">
115
- <button class="step-label copyable-label" class:copied={copiedLabelKey === k} type="button" on:click={(e) => { const v = scaleToCssVar(scale.title, step.name, cssNamespace); if (v) onCopyVarName(k, v, e); }}>
149
+ <button class="step-label copyable-label" class:copied={copiedLabelKey === k} type="button" onclick={(e) => { const v = scaleToCssVar(scale.title, step.name, cssNamespace); if (v) onCopyVarName(k, v, e); }}>
116
150
  {copiedLabelKey === k ? 'copied!' : step.name}
117
151
  </button>
118
152
  {#if scale.isText}
153
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
119
154
  <div
120
155
  class="swatch derived text-swatch"
121
156
  class:dimmed={k in overrides}
122
157
  class:clickable={k in overrides}
123
- on:click={() => onResetOverride(k)}
158
+ onclick={() => onResetOverride(k)}
124
159
  role={k in overrides ? 'button' : undefined}
125
160
  tabindex={k in overrides ? 0 : undefined}
126
- on:keydown={(e) => k in overrides && e.key === 'Enter' && onResetOverride(k)}
161
+ onkeydown={(e) => k in overrides && e.key === 'Enter' && onResetOverride(k)}
127
162
  >
128
163
  <span style="color: {dHex}">Ag</span>
129
164
  </div>
130
- <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
165
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
131
166
  <div
132
167
  class="swatch override-slot text-swatch"
133
168
  class:active={editingKey === k}
134
169
  class:populated={k in overrides}
135
170
  class:matching={k in overrides && overrides[k] === dHex}
136
- on:click={() => onOverrideClick(k, step, scale.title)}
171
+ onclick={() => onOverrideClick(k, step, scale.title)}
137
172
  role="button"
138
173
  tabindex="0"
139
- on:keydown={(e) => e.key === 'Enter' && onOverrideClick(k, step, scale.title)}
174
+ onkeydown={(e) => e.key === 'Enter' && onOverrideClick(k, step, scale.title)}
140
175
  >
141
176
  {#if k in overrides}
142
177
  <span style="color: {overrides[k]}">Ag</span>
143
178
  {/if}
144
179
  </div>
145
180
  {:else}
181
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
146
182
  <div
147
183
  class="swatch derived"
148
184
  class:border-preview={scale.title === 'Borders'}
@@ -151,23 +187,23 @@
151
187
  style={scale.title === 'Borders'
152
188
  ? `border: 3px solid ${dHex}`
153
189
  : `background: ${dHex}`}
154
- on:click={() => onResetOverride(k)}
190
+ onclick={() => onResetOverride(k)}
155
191
  role={k in overrides ? 'button' : undefined}
156
192
  tabindex={k in overrides ? 0 : undefined}
157
- on:keydown={(e) => k in overrides && e.key === 'Enter' && onResetOverride(k)}
193
+ onkeydown={(e) => k in overrides && e.key === 'Enter' && onResetOverride(k)}
158
194
  ></div>
159
195
  <div class="override-slot-wrapper">
160
- <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
196
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
161
197
  <div
162
198
  class="swatch override-slot"
163
199
  class:border-preview={scale.title === 'Borders'}
164
200
  class:active={editingKey === k || snapPickerKey === k}
165
201
  class:populated={k in overrides}
166
202
  class:matching={k in overrides && overrides[k] === dHex}
167
- on:click={() => snapped ? onSnappedClick(k) : onOverrideClick(k, step, scale.title)}
203
+ onclick={() => snapped ? onSnappedClick(k) : onOverrideClick(k, step, scale.title)}
168
204
  role="button"
169
205
  tabindex="0"
170
- on:keydown={(e) => e.key === 'Enter' && (snapped ? onSnappedClick(k) : onOverrideClick(k, step, scale.title))}
206
+ onkeydown={(e) => e.key === 'Enter' && (snapped ? onSnappedClick(k) : onOverrideClick(k, step, scale.title))}
171
207
  >
172
208
  {#if k in overrides}
173
209
  {#if scale.title === 'Borders'}
@@ -190,7 +226,7 @@
190
226
  class="snap-picker-item"
191
227
  class:selected={overrides[k] === ps.hex}
192
228
  type="button"
193
- on:click={() => onSelectSnapValue(k, ps.hex, scale.title)}
229
+ onclick={() => onSelectSnapValue(k, ps.hex, scale.title)}
194
230
  >
195
231
  <span class="snap-picker-swatch" style="background: {ps.hex}"></span>
196
232
  <span class="snap-picker-label">{ps.label}</span>
@@ -204,7 +240,7 @@
204
240
  class="step-hex"
205
241
  class:copied={copiedKey === k}
206
242
  type="button"
207
- on:click={(e) => onCopyHex(k, hex, e)}
243
+ onclick={(e) => onCopyHex(k, hex, e)}
208
244
  >{copiedKey === k ? 'copied!' : hex}</button>
209
245
  </div>
210
246
  {/each}
@@ -3,7 +3,11 @@
3
3
  import Toggle from '../Toggle.svelte';
4
4
  import { beginSliderGesture } from '../../lib/editorStore';
5
5
 
6
- /**
6
+
7
+
8
+
9
+ interface Props {
10
+ /**
7
11
  * The header swatch + label + base-hex + (when active) the ColorEditPanel
8
12
  * for editing the palette's base colour. In chromatic mode the user picks
9
13
  * an arbitrary hex; in gray mode the user picks tint hue + chroma and the
@@ -13,51 +17,73 @@
13
17
  * fires callbacks (`onStartEdit`, `onConfirm`, `onCancel`, etc.). The
14
18
  * parent decides whether to apply the chromatic-vs-gray snapshot dance.
15
19
  */
20
+ label: string;
21
+ displayLabel?: string | null;
22
+ mode: 'chromatic' | 'gray';
23
+ baseColor: string;
24
+ gray500Hex: string;
25
+ tintHue: number;
26
+ tintChroma: number;
27
+ anchorToBase: boolean;
28
+ isEditingBase: boolean;
29
+ panelOpen: boolean;
30
+ editingColor: string | null;
31
+ editPanelTitle: string | null;
32
+ copiedKey: string | null;
33
+ onStartEdit: () => void;
34
+ onConfirm: () => void;
35
+ onCancel: () => void;
36
+ onColorChange: (hex: string) => void;
37
+ onTintChange: (hue: number, chroma: number) => void;
38
+ onAnchorToBaseChange: (next: boolean) => void;
39
+ onCopyBaseHex: (key: string, hex: string, event?: MouseEvent) => void;
40
+ }
16
41
 
17
- export let label: string;
18
- export let displayLabel: string | null = null;
19
- export let mode: 'chromatic' | 'gray';
20
- export let baseColor: string;
21
- export let gray500Hex: string;
22
- export let tintHue: number;
23
- export let tintChroma: number;
24
- export let anchorToBase: boolean;
25
- export let isEditingBase: boolean;
26
- export let panelOpen: boolean;
27
- export let editingColor: string | null;
28
- export let editPanelTitle: string | null;
29
- export let copiedKey: string | null;
30
-
31
- export let onStartEdit: () => void;
32
- export let onConfirm: () => void;
33
- export let onCancel: () => void;
34
- export let onColorChange: (hex: string) => void;
35
- export let onTintChange: (hue: number, chroma: number) => void;
36
- export let onAnchorToBaseChange: (next: boolean) => void;
37
- export let onCopyBaseHex: (key: string, hex: string, event?: MouseEvent) => void;
38
-
39
- $: displayHex = mode === 'gray' ? gray500Hex : baseColor;
40
- $: copyKey = mode === 'gray' ? 'gray-500' : '__base__';
42
+ let {
43
+ label,
44
+ displayLabel = null,
45
+ mode,
46
+ baseColor,
47
+ gray500Hex,
48
+ tintHue,
49
+ tintChroma,
50
+ anchorToBase,
51
+ isEditingBase,
52
+ panelOpen,
53
+ editingColor,
54
+ editPanelTitle,
55
+ copiedKey,
56
+ onStartEdit,
57
+ onConfirm,
58
+ onCancel,
59
+ onColorChange,
60
+ onTintChange,
61
+ onAnchorToBaseChange,
62
+ onCopyBaseHex
63
+ }: Props = $props();
64
+
65
+ let displayHex = $derived(mode === 'gray' ? gray500Hex : baseColor);
66
+ let copyKey = $derived(mode === 'gray' ? 'gray-500' : '__base__');
41
67
  </script>
42
68
 
43
69
  <div class="editor-top">
44
70
  <div class="editor-primary">
45
- <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
71
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
46
72
  <div
47
73
  class="header-swatch"
48
74
  class:active={isEditingBase}
49
75
  style="background: {displayHex}"
50
- on:click={onStartEdit}
76
+ onclick={onStartEdit}
51
77
  role="button"
52
78
  tabindex="0"
53
- on:keydown={(e) => e.key === 'Enter' && onStartEdit()}
79
+ onkeydown={(e) => e.key === 'Enter' && onStartEdit()}
54
80
  ></div>
55
81
  <div class="primary-info">
56
82
  <span class="editor-label">{displayLabel ?? label}</span>
57
83
  <button
58
84
  class="base-hex clickable-hex"
59
85
  type="button"
60
- on:click={(e) => onCopyBaseHex(copyKey, displayHex, e)}
86
+ onclick={(e) => onCopyBaseHex(copyKey, displayHex, e)}
61
87
  >{copiedKey === copyKey ? 'copied!' : displayHex}</button>
62
88
  </div>
63
89
  </div>
@@ -78,9 +104,11 @@
78
104
  onRemoveOverride={() => {}}
79
105
  onSliderStart={() => beginSliderGesture(`edit ${label} base`)}
80
106
  >
81
- <span slot="actions" class:hidden={mode !== 'chromatic'}>
82
- <Toggle checked={anchorToBase} on:change={(e) => onAnchorToBaseChange(e.detail ?? !anchorToBase)} label="Lock base color to position 500" />
83
- </span>
107
+ {#snippet actions()}
108
+ <span class:hidden={mode !== 'chromatic'}>
109
+ <Toggle checked={anchorToBase} onchange={(v) => onAnchorToBaseChange(v ?? !anchorToBase)} label="Lock base color to position 500" />
110
+ </span>
111
+ {/snippet}
84
112
  </ColorEditPanel>
85
113
  {/if}
86
114