@motion-proto/live-tokens 0.49.1 → 0.52.1

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 (111) hide show
  1. package/CHANGELOG.md +72 -0
  2. package/dist-plugin/adjust/index.d.cts +1 -1
  3. package/dist-plugin/adjust/index.d.ts +1 -1
  4. package/dist-plugin/{chunk-76TFDTJO.js → chunk-JIGIIE5P.js} +60 -132
  5. package/dist-plugin/{chunk-44RSTAII.js → chunk-TKZBVIW5.js} +33 -5
  6. package/dist-plugin/chunk-YR6GPXW2.js +129 -0
  7. package/dist-plugin/generateColorsAndType/index.cjs +100 -33
  8. package/dist-plugin/generateColorsAndType/index.d.cts +1 -1
  9. package/dist-plugin/generateColorsAndType/index.d.ts +1 -1
  10. package/dist-plugin/generateColorsAndType/index.js +35 -14
  11. package/dist-plugin/index.cjs +95 -55
  12. package/dist-plugin/index.js +5 -3
  13. package/dist-plugin/{themeTypes-DSwKq-bj.d.cts → themeTypes-Dky03HL9.d.cts} +18 -5
  14. package/dist-plugin/{themeTypes-DSwKq-bj.d.ts → themeTypes-Dky03HL9.d.ts} +18 -5
  15. package/dist-plugin/tokensCssMigrations/index.cjs +71 -5
  16. package/dist-plugin/tokensCssMigrations/index.d.cts +20 -9
  17. package/dist-plugin/tokensCssMigrations/index.d.ts +20 -9
  18. package/dist-plugin/tokensCssMigrations/index.js +4 -1
  19. package/package.json +8 -1
  20. package/src/editor/bootstrap.ts +2 -0
  21. package/src/editor/component-editor/ButtonEditor.svelte +1 -1
  22. package/src/editor/component-editor/CardEditor.svelte +5 -2
  23. package/src/editor/component-editor/IconButtonEditor.svelte +1 -1
  24. package/src/editor/component-editor/ImageEditor.svelte +1 -1
  25. package/src/editor/component-editor/NotificationEditor.svelte +6 -0
  26. package/src/editor/component-editor/SectionDividerEditor.svelte +4 -1
  27. package/src/editor/component-editor/SideNavigationEditor.svelte +6 -0
  28. package/src/editor/component-editor/TabBarEditor.svelte +1 -5
  29. package/src/editor/component-editor/scaffolding/ComponentEditorBase.svelte +8 -1
  30. package/src/editor/component-editor/scaffolding/ComponentFileManager.svelte +10 -32
  31. package/src/editor/component-editor/scaffolding/StateBlock.svelte +2 -0
  32. package/src/editor/component-editor/scaffolding/TypeEditor.svelte +3 -1
  33. package/src/editor/component-editor/scaffolding/types.ts +3 -0
  34. package/src/editor/core/components/componentConfigService.ts +25 -0
  35. package/src/editor/core/cssVarSync.ts +65 -7
  36. package/src/editor/core/fonts/fontLoader.ts +12 -3
  37. package/src/editor/core/fonts/fontWeightAvailability.ts +97 -0
  38. package/src/editor/core/palettes/oklch.ts +3 -137
  39. package/src/editor/core/palettes/paletteDerivation.ts +79 -37
  40. package/src/editor/core/preview/lookPreview.ts +23 -18
  41. package/src/editor/core/store/editorRenderer.ts +22 -7
  42. package/src/editor/core/store/editorStore.ts +31 -0
  43. package/src/editor/core/store/gradientSource.ts +5 -0
  44. package/src/editor/core/themes/colorsAndTypeService.ts +2 -12
  45. package/src/editor/core/themes/generateColorsAndType.ts +18 -8
  46. package/src/editor/core/themes/migrations/2026-05-20-sectiondivider-slim-variants.ts +4 -1
  47. package/src/editor/core/themes/migrations/2026-05-21-sectiondivider-spacing-to-padding.ts +4 -1
  48. package/src/editor/core/themes/migrations/2026-05-25-cornerbadge-flatten-variants.ts +8 -0
  49. package/src/editor/core/themes/slices/fonts.ts +4 -5
  50. package/src/editor/core/themes/themeDocumentSync.ts +66 -0
  51. package/src/editor/core/themes/themeInit.ts +7 -10
  52. package/src/editor/core/themes/themeService.ts +10 -3
  53. package/src/editor/core/themes/themeTypes.ts +18 -6
  54. package/src/editor/docs/content/editing-tokens.md +6 -2
  55. package/src/editor/docs/content/themes-workflow.md +14 -11
  56. package/src/editor/docs/content/where-themes-live.md +2 -2
  57. package/src/editor/docs/content.generated.ts +3 -3
  58. package/src/editor/ui/BezierCurveEditor.svelte +90 -67
  59. package/src/editor/ui/FileLoadList.svelte +1 -0
  60. package/src/editor/ui/FontStackEditor.svelte +1 -2
  61. package/src/editor/ui/GradientEditor.svelte +5 -1
  62. package/src/editor/ui/PaletteEditor.svelte +150 -44
  63. package/src/editor/ui/ProjectFontsSection.svelte +0 -5
  64. package/src/editor/ui/ThemePanel.svelte +206 -42
  65. package/src/editor/ui/Toggle.svelte +14 -2
  66. package/src/editor/ui/UIDialog.svelte +7 -1
  67. package/src/editor/ui/UIFontFamilySelector.svelte +13 -13
  68. package/src/editor/ui/UIFontSizeSelector.svelte +5 -5
  69. package/src/editor/ui/UIFontWeightSelector.svelte +52 -2
  70. package/src/editor/ui/UIOptionItem.svelte +14 -1
  71. package/src/editor/ui/UIPaddingSelector.svelte +4 -3
  72. package/src/editor/ui/UIPaletteSelector.svelte +20 -13
  73. package/src/editor/ui/UIRelinkConfirmDialog.svelte +18 -3
  74. package/src/editor/ui/UITextTransformSelector.svelte +5 -5
  75. package/src/editor/ui/UITokenSelector.svelte +29 -7
  76. package/src/editor/ui/colors/ColorStory.svelte +12 -8
  77. package/src/editor/ui/curveEngine.ts +101 -21
  78. package/src/editor/ui/palette/OverridesPanel.svelte +19 -5
  79. package/src/editor/ui/palette/PaletteBase.svelte +17 -78
  80. package/src/editor/ui/palette/ScaleCurveEditor.svelte +109 -20
  81. package/src/editor/ui/palette/curveSummary.ts +20 -0
  82. package/src/editor/ui/palette/dockMagnify.ts +5 -13
  83. package/src/editor/ui/palette/paletteMath.ts +7 -4
  84. package/src/live-tokens/data/colors-and-type/autumn.json +528 -528
  85. package/src/live-tokens/data/colors-and-type/default.json +247 -247
  86. package/src/live-tokens/data/colors-and-type/halloween.json +532 -532
  87. package/src/live-tokens/data/colors-and-type/midnight-study.json +538 -538
  88. package/src/live-tokens/data/colors-and-type/ocean.json +521 -521
  89. package/src/live-tokens/data/colors-and-type/royal-velvet.json +532 -532
  90. package/src/live-tokens/data/colors-and-type/spring-meadow.json +504 -504
  91. package/src/live-tokens/data/colors-and-type/sunset.json +531 -531
  92. package/src/live-tokens/data/themes/autumn.json +527 -527
  93. package/src/live-tokens/data/themes/halloween.json +531 -531
  94. package/src/live-tokens/data/themes/midnight-study.json +537 -537
  95. package/src/live-tokens/data/themes/ocean.json +520 -520
  96. package/src/live-tokens/data/themes/royal-velvet.json +531 -531
  97. package/src/live-tokens/data/themes/spring-meadow.json +516 -514
  98. package/src/live-tokens/data/themes/sunset.json +531 -531
  99. package/src/live-tokens/data/tokens.generated.css +282 -282
  100. package/src/system/components/Button.svelte +2 -1
  101. package/src/system/components/FloatingTokenTags.css +2 -2
  102. package/src/system/components/FloatingTokenTags.svelte +11 -0
  103. package/src/system/components/IconButton.svelte +2 -1
  104. package/src/system/components/Image.svelte +9 -3
  105. package/src/system/components/ImageLightbox.svelte +2 -0
  106. package/src/system/components/SectionDivider.svelte +20 -2
  107. package/src/system/components/SideNavigation.svelte +15 -1
  108. package/src/system/internal/backgroundContrast.ts +7 -0
  109. package/src/system/internal/oklch.ts +189 -0
  110. package/src/system/styles/fonts.css +6 -6
  111. package/src/system/styles/tokens.css +283 -283
@@ -4,22 +4,25 @@
4
4
  import {
5
5
  type CurveAnchor, type CurveConfig,
6
6
  CURVE_H, CURVE_PAD_Y, CURVE_Y_PAD,
7
- isCornerAnchor, tangentAnchor, curveXToSvg, curveYToSvg, svgToX, svgToY,
7
+ isCornerAnchor, isAutoSmoothCurve, tangentAnchor, resmoothAnchor, resmoothAutoCurve,
8
+ curveXToSvg, curveYToSvg, svgToX, svgToY,
8
9
  evalBezier, buildCurvePath, curveTemplates,
9
- serializeCurve, deserializeCurve,
10
+ serializeCurve, deserializeCurve, clampAnchorsToRange,
10
11
  } from './curveEngine';
11
12
  import UIPillButton from './UIPillButton.svelte';
13
+ import Toggle from './Toggle.svelte';
12
14
 
13
15
  interface Props {
14
16
  anchors: CurveAnchor[];
15
17
  cfg: CurveConfig;
16
18
  stepCount: number;
17
- padX?: number;
18
19
  offset?: number;
19
20
  defaultAnchors?: CurveAnchor[] | null;
20
21
  lockedAnchorIndex?: number | null;
22
+ autoSmooth?: boolean;
21
23
  onAnchorsChange?: (anchors: CurveAnchor[]) => void;
22
24
  onOffsetChange?: (offset: number) => void;
25
+ onAutoSmoothChange?: (autoSmooth: boolean) => void;
23
26
  onLockedAnchorUnlock?: (() => void) | null;
24
27
  }
25
28
 
@@ -27,19 +30,36 @@
27
30
  anchors,
28
31
  cfg,
29
32
  stepCount,
30
- padX = 0,
31
33
  offset = 0,
32
34
  defaultAnchors = null,
33
35
  lockedAnchorIndex = null,
36
+ autoSmooth = true,
34
37
  onAnchorsChange = () => {},
35
38
  onOffsetChange = () => {},
39
+ onAutoSmoothChange = () => {},
36
40
  onLockedAnchorUnlock = null
37
41
  }: Props = $props();
38
42
 
43
+ /** Every mutation the editor makes to anchor positions runs through here, so
44
+ * while auto smoothing is on the stored handles always equal the derived
45
+ * ones. That is what makes switching it off leave the shape untouched. */
46
+ function commit(updated: CurveAnchor[]) {
47
+ onAnchorsChange(autoSmooth ? resmoothAutoCurve(updated) : updated);
48
+ }
49
+
50
+ function setAutoSmooth(on: boolean) {
51
+ onAutoSmoothChange(on);
52
+ // Switching off is a no-op on the shape; switching on discards hand-dragged handles.
53
+ if (on) onAnchorsChange(resmoothAutoCurve(anchors));
54
+ }
55
+
39
56
  function resetToDefault() {
40
57
  if (!defaultAnchors) return;
58
+ // The default is a shape in its own right, so it lands verbatim rather than
59
+ // through `commit`, and auto smoothing follows whatever that shape already is.
41
60
  onAnchorsChange(defaultAnchors.map(a => ({ ...a })));
42
61
  onOffsetChange(0);
62
+ onAutoSmoothChange(isAutoSmoothCurve(defaultAnchors));
43
63
  }
44
64
 
45
65
  const CURVE_W_DEFAULT = 720;
@@ -50,6 +70,9 @@
50
70
  const clipId = `curve-clip-${Math.random().toString(36).slice(2, 8)}`;
51
71
 
52
72
  let w = $derived(dims);
73
+ // Half a step column. The graph spans the swatch row edge to edge, so without this
74
+ // inset the curve's ends sit on the outer edges of the end swatches, not over them.
75
+ let padX = $derived(stepCount > 1 ? w / (2 * stepCount) : 0);
53
76
  let offsetPx = $derived(-(offset / ((cfg.yMax - cfg.yMin) * (1 + 2 * CURVE_Y_PAD))) * (CURVE_H - 2 * CURVE_PAD_Y));
54
77
 
55
78
  function stepToX(index: number): number {
@@ -114,7 +137,7 @@
114
137
  const { x, y } = svgCoords(e);
115
138
  const newX = svgToX(x, w, padX);
116
139
  const newY = Math.round(svgToY(y, cfg));
117
- const updated = [...anchors];
140
+ let updated = [...anchors];
118
141
 
119
142
  if (kind === 'anchor') {
120
143
  if (idx === lockedAnchorIndex) return; // locked: no x/y dragging
@@ -123,20 +146,28 @@
123
146
  else if (idx === updated.length - 1) ax = 100;
124
147
  else ax = Math.max(updated[idx - 1].x + 1, Math.min(updated[idx + 1].x - 1, ax));
125
148
  updated[idx] = { ...updated[idx], x: ax, y: newY };
149
+ // The locked anchor took its tangent from the curve's shape at pin time and
150
+ // cannot be dragged, so nothing else refreshes it. Left stale it holds a flat
151
+ // shelf through the middle of a ramp the user has since moved under it.
152
+ if (lockedAnchorIndex != null && lockedAnchorIndex !== idx) {
153
+ updated = resmoothAnchor(updated, lockedAnchorIndex);
154
+ }
126
155
  } else if (kind === 'handleOut') {
156
+ if (autoSmooth) onAutoSmoothChange(false);
127
157
  const a = updated[idx];
128
158
  const dx = newX - a.x, dy = newY - a.y;
129
159
  updated[idx] = breakHandle
130
160
  ? { ...a, outDx: dx, outDy: dy }
131
161
  : { ...a, outDx: dx, outDy: dy, inDx: -dx, inDy: -dy };
132
162
  } else {
163
+ if (autoSmooth) onAutoSmoothChange(false);
133
164
  const a = updated[idx];
134
165
  const dx = newX - a.x, dy = newY - a.y;
135
166
  updated[idx] = breakHandle
136
167
  ? { ...a, inDx: dx, inDy: dy }
137
168
  : { ...a, inDx: dx, inDy: dy, outDx: -dx, outDy: -dy };
138
169
  }
139
- onAnchorsChange(updated);
170
+ if (kind === 'anchor') commit(updated); else onAnchorsChange(updated);
140
171
  }
141
172
 
142
173
  function handlePointerUp() {
@@ -184,7 +215,7 @@
184
215
  x: Math.round(mx), y: Math.round(my),
185
216
  inDx: r0x - mx, inDy: r0y - my, outDx: r1x - mx, outDy: r1y - my,
186
217
  });
187
- onAnchorsChange(updated);
218
+ commit(updated);
188
219
  }
189
220
 
190
221
  function toggleAnchorSmooth(index: number) {
@@ -195,16 +226,16 @@
195
226
  } else {
196
227
  updated[index] = { ...a, inDx: 0, inDy: 0, outDx: 0, outDy: 0 };
197
228
  }
198
- onAnchorsChange(updated);
229
+ commit(updated);
199
230
  }
200
231
 
201
232
  function removePoint(index: number) {
202
233
  if (anchors.length <= 2) return;
203
- onAnchorsChange(anchors.filter((_, i) => i !== index));
234
+ commit(anchors.filter((_, i) => i !== index));
204
235
  }
205
236
 
206
237
  function applyTemplate(tpl: typeof curveTemplates[0]) {
207
- onAnchorsChange(tpl.anchors(cfg));
238
+ commit(tpl.anchors(cfg));
208
239
  }
209
240
 
210
241
  // --- Shift (vertical offset) drag ---
@@ -238,7 +269,7 @@
238
269
 
239
270
  async function copyToClipboard() {
240
271
  try {
241
- await navigator.clipboard.writeText(serializeCurve(anchors, offset));
272
+ await navigator.clipboard.writeText(serializeCurve(anchors, offset, autoSmooth));
242
273
  } catch {
243
274
  // clipboard write failed silently
244
275
  }
@@ -249,8 +280,12 @@
249
280
  const text = await navigator.clipboard.readText();
250
281
  const data = deserializeCurve(text);
251
282
  if (!data) return;
252
- onAnchorsChange(data.anchors.map(a => ({ ...a })));
283
+ // Clamping can move an anchor off its own derived tangent, so the pasted
284
+ // flag only survives a paste the axis left alone.
285
+ const pasted = clampAnchorsToRange(data.anchors.map(a => ({ ...a })), cfg);
286
+ onAnchorsChange(pasted);
253
287
  onOffsetChange(data.offset);
288
+ onAutoSmoothChange(data.autoSmooth && isAutoSmoothCurve(pasted));
254
289
  } catch {
255
290
  // clipboard read failed or permission denied
256
291
  }
@@ -258,19 +293,6 @@
258
293
  </script>
259
294
 
260
295
  <div class="curve-panel">
261
- <div class="curve-panel-header">
262
- <span class="curve-panel-label">{cfg.label}</span>
263
- <div class="curve-help">
264
- <button class="curve-help-badge" type="button" aria-label="Curve editor help">
265
- <i class="fas fa-circle-info" aria-hidden="true"></i>
266
- </button>
267
- <div class="curve-help-popover" role="tooltip">
268
- <div><strong>Click</strong> path to add a point</div>
269
- <div><strong>&#x2325; Click</strong> a point to remove</div>
270
- <div><strong>Double-click</strong> a point to toggle smooth/corner</div>
271
- </div>
272
- </div>
273
- </div>
274
296
  <div class="curve-container">
275
297
  <div class="curve-chart-overlay">
276
298
  <UIPillButton
@@ -282,8 +304,19 @@
282
304
  <svg viewBox="0 0 12 20" class="curve-tool-icon">
283
305
  <path d="M6,2 L10,7 L7,7 L7,13 L10,13 L6,18 L2,13 L5,13 L5,7 L2,7 Z" />
284
306
  </svg>
285
- <span>Offset{offset !== 0 ? ` ${offset > 0 ? '+' : ''}${offset}` : ''}</span>
307
+ <span>Offset{offset !== 0 ? ` ${offset > 0 ? '+' : ''}${offset}${cfg.unit ?? ''}` : ''}</span>
286
308
  </UIPillButton>
309
+ <div class="curve-help">
310
+ <button class="curve-help-badge" type="button" aria-label="Curve editor help">
311
+ <i class="fas fa-circle-info" aria-hidden="true"></i>
312
+ </button>
313
+ <div class="curve-help-popover" role="tooltip">
314
+ <div><strong>Click</strong> path to add a point</div>
315
+ <div><strong>&#x2325; Click</strong> a point to remove</div>
316
+ <div><strong>Double-click</strong> a point to toggle smooth/corner</div>
317
+ <div><strong>Drag a handle</strong> to leave auto smooth</div>
318
+ </div>
319
+ </div>
287
320
  </div>
288
321
  <svg
289
322
  bind:this={svgEl}
@@ -314,10 +347,7 @@
314
347
 
315
348
  <!-- Horizontal grid lines -->
316
349
  {#each cfg.gridLines as gl}
317
- <line x1={padX} y1={curveYToSvg(gl, cfg)} x2={w - padX} y2={curveYToSvg(gl, cfg)} class="curve-grid" />
318
- {/each}
319
- {#each cfg.dashedLines as dl}
320
- <line x1={padX} y1={curveYToSvg(dl, cfg)} x2={w - padX} y2={curveYToSvg(dl, cfg)} class="curve-grid dashed" />
350
+ <line x1={0} y1={curveYToSvg(gl, cfg)} x2={w} y2={curveYToSvg(gl, cfg)} class="curve-grid" />
321
351
  {/each}
322
352
 
323
353
  <!-- Curve content group — offset vertically, clipped -->
@@ -418,19 +448,22 @@
418
448
  <UIPillButton size="compact" variant="outline" title="Copy curve" onclick={copyToClipboard}>Copy</UIPillButton>
419
449
  <UIPillButton size="compact" variant="outline" title="Paste curve" onclick={pasteFromClipboard}>Paste</UIPillButton>
420
450
  </div>
421
- <div class="curve-templates">
422
- {#each curveTemplates as tpl}
423
- <button
424
- class="curve-template-btn"
425
- type="button"
426
- title={tpl.name}
427
- onclick={() => applyTemplate(tpl)}
428
- >
429
- <svg viewBox="0 0 20 12" class="curve-template-icon">
430
- <path d={tpl.icon} />
431
- </svg>
432
- </button>
433
- {/each}
451
+ <div class="curve-presets">
452
+ <Toggle checked={autoSmooth} label="Auto smooth" onchange={setAutoSmooth} />
453
+ <div class="curve-templates">
454
+ {#each curveTemplates as tpl}
455
+ <button
456
+ class="curve-template-btn"
457
+ type="button"
458
+ title={tpl.name}
459
+ onclick={() => applyTemplate(tpl)}
460
+ >
461
+ <svg viewBox="0 0 20 12" class="curve-template-icon">
462
+ <path d={tpl.icon} />
463
+ </svg>
464
+ </button>
465
+ {/each}
466
+ </div>
434
467
  </div>
435
468
  <div class="curve-toolbar-group">
436
469
  {#if defaultAnchors}
@@ -449,18 +482,6 @@
449
482
  gap: var(--ui-space-4);
450
483
  }
451
484
 
452
- .curve-panel-header {
453
- display: flex;
454
- align-items: center;
455
- gap: var(--ui-space-6);
456
- }
457
-
458
- .curve-panel-label {
459
- font-size: var(--ui-font-size-md);
460
- font-weight: var(--ui-font-weight-semibold);
461
- color: var(--ui-text-tertiary);
462
- }
463
-
464
485
  .curve-container {
465
486
  position: relative;
466
487
  width: 100%;
@@ -483,6 +504,7 @@
483
504
  .curve-help {
484
505
  position: relative;
485
506
  margin-left: auto;
507
+ align-self: flex-start;
486
508
  }
487
509
 
488
510
  .curve-help-badge {
@@ -549,7 +571,7 @@
549
571
  width: 100%;
550
572
  height: 100%;
551
573
  background: transparent;
552
- border: 1px solid var(--ui-border-low);
574
+ border: 1px solid var(--ui-border-high);
553
575
  border-radius: var(--ui-radius-sm);
554
576
  cursor: crosshair;
555
577
  display: block;
@@ -562,20 +584,15 @@
562
584
  }
563
585
 
564
586
  .curve-grid {
565
- stroke: var(--ui-border-low);
566
- stroke-width: 0.5;
587
+ stroke: var(--ui-border-high);
588
+ stroke-width: 1;
567
589
  vector-effect: non-scaling-stroke;
568
590
  }
569
591
 
570
- .curve-grid.dashed {
571
- stroke-dasharray: 3 3;
572
- }
573
-
574
592
  .curve-step-line {
575
593
  stroke: var(--ui-border-low);
576
- stroke-width: 0.5;
594
+ stroke-width: 1;
577
595
  vector-effect: non-scaling-stroke;
578
-
579
596
  }
580
597
 
581
598
  .shift-overlay {
@@ -680,6 +697,12 @@
680
697
  fill: currentColor;
681
698
  }
682
699
 
700
+ .curve-presets {
701
+ display: flex;
702
+ align-items: center;
703
+ gap: var(--ui-space-12);
704
+ }
705
+
683
706
  .curve-templates {
684
707
  display: flex;
685
708
  gap: var(--ui-space-2);
@@ -689,8 +712,8 @@
689
712
  display: flex;
690
713
  align-items: center;
691
714
  justify-content: center;
692
- width: 1.5rem;
693
- height: 1rem;
715
+ width: 2.625rem;
716
+ height: 1.75rem;
694
717
  padding: 0;
695
718
  border: 1px solid var(--ui-border-low);
696
719
  border-radius: var(--ui-radius-sm);
@@ -711,7 +734,7 @@
711
734
  .curve-template-icon path {
712
735
  fill: none;
713
736
  stroke: var(--ui-text-tertiary);
714
- stroke-width: 1.5;
737
+ stroke-width: 1;
715
738
  stroke-linecap: round;
716
739
  stroke-linejoin: round;
717
740
  }
@@ -167,6 +167,7 @@
167
167
  {@const protectedRow = isProtected(file)}
168
168
  <div
169
169
  class="load-item"
170
+ data-file-name={file.fileName}
170
171
  class:active={file.fileName === activeFileName}
171
172
  class:selected={file.fileName === selectedFileName}
172
173
  class:protected={protectedRow}
@@ -11,7 +11,7 @@
11
11
  SystemCascadePreset,
12
12
  } from '../core/themes/themeTypes';
13
13
  import { editorState, setFontStacks } from '../core/store/editorStore';
14
- import { applyFontStacks, SYSTEM_CASCADES } from '../core/fonts/fontLoader';
14
+ import { SYSTEM_CASCADES } from '../core/fonts/fontLoader';
15
15
 
16
16
  const SYSTEM_PRESETS: SystemCascadePreset[] = ['system-ui-sans', 'system-ui-serif', 'system-ui-mono'];
17
17
  // `cursive` and `fantasy` are CSS-spec generics whose rendering varies wildly
@@ -110,7 +110,6 @@
110
110
  function updateStack(variable: FontStackVariable, updater: (slots: FontStackSlot[]) => FontStackSlot[]) {
111
111
  const next = stacks.map((s) => (s.variable === variable ? { ...s, slots: updater([...s.slots]) } : s));
112
112
  setFontStacks(next);
113
- applyFontStacks(next, fontSourcesList);
114
113
  }
115
114
 
116
115
  function handleSelectChange(variable: FontStackVariable, index: number, value: string) {
@@ -274,7 +274,11 @@
274
274
  </script>
275
275
 
276
276
  {#if gradient}
277
- <div class="gradient-editor" class:has-pad={hasAside}>
277
+ <div
278
+ class="gradient-editor"
279
+ class:has-pad={hasAside}
280
+ data-token-variable={gradientSource.targetVariable}
281
+ >
278
282
  {#if sectionLabel || hasAside}
279
283
  <div class="editor-header editor-section-left">
280
284
  <span class="editor-section-label">{sectionLabel ?? ''}</span>