@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
@@ -12,7 +12,7 @@
12
12
  * captures coherent edits. The store's subscriber fans values to :root
13
13
  * via cssVarSync.
14
14
  */
15
- import { onMount, createEventDispatcher } from 'svelte';
15
+ import { onMount } from 'svelte';
16
16
  import {
17
17
  editorState, mutate, beginScope, commitScope, beginSliderGesture,
18
18
  seedShadowsFromDom, shadowTokenCss, computeShadowXY,
@@ -21,10 +21,14 @@
21
21
  } from '../../lib/editorStore';
22
22
  import type { ShadowToken, ShadowOverrideFlags, EditorState } from '../../lib/editorTypes';
23
23
 
24
- export let copiedVar: string | null = null;
24
+ interface Props {
25
+ copiedVar?: string | null;
26
+ oncopy?: (variable: string) => void;
27
+ }
28
+
29
+ let { copiedVar = null, oncopy }: Props = $props();
25
30
 
26
- const dispatch = createEventDispatcher<{ copy: string }>();
27
- function copy(v: string) { dispatch('copy', v); }
31
+ function copy(v: string) { oncopy?.(v); }
28
32
 
29
33
  function getShadowOverride(s: EditorState, variable: string): ShadowOverrideFlags {
30
34
  let ov = s.shadows.overrides[variable];
@@ -221,19 +225,19 @@
221
225
  }
222
226
 
223
227
  // HSL gradient helpers (read from globals for their background-color cues).
224
- $: sg = $editorState.shadows.globals;
225
- $: shadowHueGrad = `linear-gradient(to right, ${
228
+ let sg = $derived($editorState.shadows.globals);
229
+ let shadowHueGrad = $derived(`linear-gradient(to right, ${
226
230
  [0, 60, 120, 180, 240, 300, 360].map(h => `hsl(${h},${sg.saturation}%,${sg.lightness}%)`).join(',')
227
- })`;
228
- $: shadowSatGrad = `linear-gradient(to right, hsl(${sg.hue},0%,${sg.lightness}%), hsl(${sg.hue},100%,${sg.lightness}%))`;
229
- $: shadowLightGrad = `linear-gradient(to right, hsl(${sg.hue},${sg.saturation}%,0%), hsl(${sg.hue},${sg.saturation}%,50%), hsl(${sg.hue},${sg.saturation}%,100%))`;
231
+ })`);
232
+ let shadowSatGrad = $derived(`linear-gradient(to right, hsl(${sg.hue},0%,${sg.lightness}%), hsl(${sg.hue},100%,${sg.lightness}%))`);
233
+ let shadowLightGrad = $derived(`linear-gradient(to right, hsl(${sg.hue},${sg.saturation}%,0%), hsl(${sg.hue},${sg.saturation}%,50%), hsl(${sg.hue},${sg.saturation}%,100%))`);
230
234
 
231
- let editingShadow: string | null = null;
235
+ let editingShadow: string | null = $state(null);
232
236
 
233
- $: shadowTokens = $editorState.shadows.tokens;
234
- $: editingToken = editingShadow ? shadowTokens.find(t => t.variable === editingShadow) ?? null : null;
235
- $: editingIdx = editingToken ? shadowTokens.indexOf(editingToken) : -1;
236
- $: editingIsScale = editingToken ? SCALE_SHADOW_VARIABLES.has(editingToken.variable) : false;
237
+ let shadowTokens = $derived($editorState.shadows.tokens);
238
+ let editingToken = $derived(editingShadow ? shadowTokens.find(t => t.variable === editingShadow) ?? null : null);
239
+ let editingIdx = $derived(editingToken ? shadowTokens.indexOf(editingToken) : -1);
240
+ let editingIsScale = $derived(editingToken ? SCALE_SHADOW_VARIABLES.has(editingToken.variable) : false);
237
241
 
238
242
  function angleFromPointer(event: PointerEvent, dialEl: SVGSVGElement): number {
239
243
  const rect = dialEl.getBoundingClientRect();
@@ -383,9 +387,9 @@
383
387
  },
384
388
  ];
385
389
 
386
- let shadowBg = 'var(--ui-surface-highest)';
387
- let bgPickerOpen = false;
388
- let expandedGroup: string | null = null;
390
+ let shadowBg = $state('var(--ui-surface-highest)');
391
+ let bgPickerOpen = $state(false);
392
+ let expandedGroup: string | null = $state(null);
389
393
 
390
394
  function pickBg(value: string) {
391
395
  shadowBg = value;
@@ -415,10 +419,10 @@
415
419
  <div class="shadow-item" class:active={editingShadow === token.variable}>
416
420
  <div class="shadow-box" style="box-shadow: {shadowTokenCss(token)};"></div>
417
421
  <div class="token-info">
418
- <button class="token-variable copyable" class:copied={copiedVar === token.variable} on:click={() => copy(token.variable)}>{copiedVar === token.variable ? 'copied!' : token.variable}</button>
422
+ <button class="token-variable copyable" class:copied={copiedVar === token.variable} onclick={() => copy(token.variable)}>{copiedVar === token.variable ? 'copied!' : token.variable}</button>
419
423
  <span class="token-value">{shadowTokenValueLabel(token)}</span>
420
424
  </div>
421
- <button class="shadow-edit-btn" on:click={() => editingShadow = editingShadow === token.variable ? null : token.variable}>
425
+ <button class="shadow-edit-btn" onclick={() => editingShadow = editingShadow === token.variable ? null : token.variable}>
422
426
  {editingShadow === token.variable ? 'Close' : 'Edit'}
423
427
  </button>
424
428
  </div>
@@ -430,10 +434,10 @@
430
434
  <div class="shadow-item" class:active={editingShadow === token.variable}>
431
435
  <div class="shadow-box" style="box-shadow: {shadowTokenCss(token)};"></div>
432
436
  <div class="token-info">
433
- <button class="token-variable copyable" class:copied={copiedVar === token.variable} on:click={() => copy(token.variable)}>{copiedVar === token.variable ? 'copied!' : token.variable}</button>
437
+ <button class="token-variable copyable" class:copied={copiedVar === token.variable} onclick={() => copy(token.variable)}>{copiedVar === token.variable ? 'copied!' : token.variable}</button>
434
438
  <span class="token-value">{shadowTokenValueLabel(token)}</span>
435
439
  </div>
436
- <button class="shadow-edit-btn" on:click={() => editingShadow = editingShadow === token.variable ? null : token.variable}>
440
+ <button class="shadow-edit-btn" onclick={() => editingShadow = editingShadow === token.variable ? null : token.variable}>
437
441
  {editingShadow === token.variable ? 'Close' : 'Edit'}
438
442
  </button>
439
443
  </div>
@@ -447,17 +451,18 @@
447
451
  {#if editingToken}
448
452
  <div class="editor-header">
449
453
  <h4 class="global-shadow-title">{editingToken.variable}</h4>
450
- <button class="shadow-edit-btn" on:click={() => editingShadow = null}>Close</button>
454
+ <button class="shadow-edit-btn" onclick={() => editingShadow = null}>Close</button>
451
455
  </div>
452
456
  {#if editingIsScale}
453
- <button class="reset-btn" on:click={resetToGlobal}>Reset to Global</button>
457
+ <button class="reset-btn" onclick={resetToGlobal}>Reset to Global</button>
454
458
  {/if}
455
459
  <div class="global-shadow-row">
456
460
  <span class="shadow-slider-label" title="Direction the light source is coming from — controls which side the shadow falls on">Angle</span>
461
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
457
462
  <svg class="angle-dial" viewBox="0 0 48 48" width="48" height="48"
458
- on:pointerdown={(e) => handleDialDown(e, editingIdx)}
459
- on:pointermove={(e) => handleDialMove(e, editingIdx)}
460
- on:pointerup={handleDialUp}
463
+ onpointerdown={(e) => handleDialDown(e, editingIdx)}
464
+ onpointermove={(e) => handleDialMove(e, editingIdx)}
465
+ onpointerup={handleDialUp}
461
466
  >
462
467
  <circle cx="24" cy="24" r="20" class="dial-ring" />
463
468
  <line x1="24" y1="24"
@@ -471,47 +476,47 @@
471
476
  </svg>
472
477
  <input class="shadow-slider-input" type="number" min="0" max="360"
473
478
  value={editingToken.angle}
474
- on:change={(e) => setTokenField(editingIdx, 'angle', +e.currentTarget.value)} />
479
+ onchange={(e) => setTokenField(editingIdx, 'angle', +e.currentTarget.value)} />
475
480
  <span class="shadow-slider-unit">&deg;</span>
476
481
  </div>
477
482
  <div class="global-shadow-row">
478
483
  <span class="shadow-slider-label" title="How far the shadow is cast from the element — simulates height off the surface">Dist</span>
479
484
  <input type="range" min="0" max="60" value={editingToken.distance}
480
- on:pointerdown={() => beginSliderGesture('edit shadow distance')}
481
- on:input={(e) => setTokenField(editingIdx, 'distance', +e.currentTarget.value)} />
485
+ onpointerdown={() => beginSliderGesture('edit shadow distance')}
486
+ oninput={(e) => setTokenField(editingIdx, 'distance', +e.currentTarget.value)} />
482
487
  <input class="shadow-slider-input" type="number" min="0" max="100"
483
488
  value={editingToken.distance}
484
- on:change={(e) => setTokenField(editingIdx, 'distance', +e.currentTarget.value)} />
489
+ onchange={(e) => setTokenField(editingIdx, 'distance', +e.currentTarget.value)} />
485
490
  <span class="shadow-slider-unit">px</span>
486
491
  </div>
487
492
  <div class="global-shadow-row">
488
493
  <span class="shadow-slider-label" title="Grows or shrinks the shadow before blurring — positive makes it larger than the element, negative makes it smaller">Spread</span>
489
494
  <input type="range" min="-50" max="50" value={editingToken.spread}
490
- on:pointerdown={() => beginSliderGesture('edit shadow spread')}
491
- on:input={(e) => setTokenField(editingIdx, 'spread', +e.currentTarget.value)} />
495
+ onpointerdown={() => beginSliderGesture('edit shadow spread')}
496
+ oninput={(e) => setTokenField(editingIdx, 'spread', +e.currentTarget.value)} />
492
497
  <input class="shadow-slider-input" type="number" min="-50" max="50"
493
498
  value={editingToken.spread}
494
- on:change={(e) => setTokenField(editingIdx, 'spread', +e.currentTarget.value)} />
499
+ onchange={(e) => setTokenField(editingIdx, 'spread', +e.currentTarget.value)} />
495
500
  <span class="shadow-slider-unit">px</span>
496
501
  </div>
497
502
  <div class="global-shadow-row">
498
503
  <span class="shadow-slider-label" title="How soft the shadow edge is — higher values make a wider, more diffused shadow">Blur</span>
499
504
  <input type="range" min="0" max="100" value={editingToken.blur}
500
- on:pointerdown={() => beginSliderGesture('edit shadow blur')}
501
- on:input={(e) => setTokenField(editingIdx, 'blur', +e.currentTarget.value)} />
505
+ onpointerdown={() => beginSliderGesture('edit shadow blur')}
506
+ oninput={(e) => setTokenField(editingIdx, 'blur', +e.currentTarget.value)} />
502
507
  <input class="shadow-slider-input" type="number" min="0" max="100"
503
508
  value={editingToken.blur}
504
- on:change={(e) => setTokenField(editingIdx, 'blur', +e.currentTarget.value)} />
509
+ onchange={(e) => setTokenField(editingIdx, 'blur', +e.currentTarget.value)} />
505
510
  <span class="shadow-slider-unit">px</span>
506
511
  </div>
507
512
  <div class="global-shadow-row">
508
513
  <span class="shadow-slider-label" title="How visible the shadow is — 0% is invisible, 100% is fully opaque">Op.</span>
509
514
  <input type="range" min="0" max="100" value={Math.round(editingToken.opacity * 100)}
510
- on:pointerdown={() => beginSliderGesture('edit shadow opacity')}
511
- on:input={(e) => setTokenField(editingIdx, 'opacity', +e.currentTarget.value / 100)} />
515
+ onpointerdown={() => beginSliderGesture('edit shadow opacity')}
516
+ oninput={(e) => setTokenField(editingIdx, 'opacity', +e.currentTarget.value / 100)} />
512
517
  <input class="shadow-slider-input" type="number" min="0" max="100"
513
518
  value={Math.round(editingToken.opacity * 100)}
514
- on:change={(e) => setTokenField(editingIdx, 'opacity', +e.currentTarget.value / 100)} />
519
+ onchange={(e) => setTokenField(editingIdx, 'opacity', +e.currentTarget.value / 100)} />
515
520
  <span class="shadow-slider-unit">%</span>
516
521
  </div>
517
522
  <div class="global-color-group">
@@ -521,43 +526,43 @@
521
526
  <span class="shadow-slider-label" title="Hue — the base color of the shadow (0°=red, 120°=green, 240°=blue)">H</span>
522
527
  <div class="slider-track" style="background: {shadowHueGrad}">
523
528
  <input type="range" min="0" max="360" value={editingToken.hue}
524
- on:pointerdown={() => beginSliderGesture('edit shadow hue')}
525
- on:input={(e) => setTokenColor(editingIdx, 'hue', +e.currentTarget.value)} />
529
+ onpointerdown={() => beginSliderGesture('edit shadow hue')}
530
+ oninput={(e) => setTokenColor(editingIdx, 'hue', +e.currentTarget.value)} />
526
531
  </div>
527
532
  <input class="shadow-slider-input" type="number" min="0" max="360"
528
533
  value={editingToken.hue}
529
- on:change={(e) => setTokenColor(editingIdx, 'hue', +e.currentTarget.value)} />
534
+ onchange={(e) => setTokenColor(editingIdx, 'hue', +e.currentTarget.value)} />
530
535
  <span class="shadow-slider-unit">&deg;</span>
531
536
  </div>
532
537
  <div class="global-shadow-row">
533
538
  <span class="shadow-slider-label" title="Saturation — 0% is gray, 100% is full color intensity">S</span>
534
539
  <div class="slider-track" style="background: linear-gradient(to right, hsl({editingToken.hue},0%,{editingToken.lightness}%), hsl({editingToken.hue},100%,{editingToken.lightness}%))">
535
540
  <input type="range" min="0" max="100" value={editingToken.saturation}
536
- on:pointerdown={() => beginSliderGesture('edit shadow saturation')}
537
- on:input={(e) => setTokenColor(editingIdx, 'saturation', +e.currentTarget.value)} />
541
+ onpointerdown={() => beginSliderGesture('edit shadow saturation')}
542
+ oninput={(e) => setTokenColor(editingIdx, 'saturation', +e.currentTarget.value)} />
538
543
  </div>
539
544
  <input class="shadow-slider-input" type="number" min="0" max="100"
540
545
  value={editingToken.saturation}
541
- on:change={(e) => setTokenColor(editingIdx, 'saturation', +e.currentTarget.value)} />
546
+ onchange={(e) => setTokenColor(editingIdx, 'saturation', +e.currentTarget.value)} />
542
547
  <span class="shadow-slider-unit">%</span>
543
548
  </div>
544
549
  <div class="global-shadow-row">
545
550
  <span class="shadow-slider-label" title="Lightness — 0% is black, 100% is white">L</span>
546
551
  <div class="slider-track" style="background: linear-gradient(to right, hsl({editingToken.hue},{editingToken.saturation}%,0%), hsl({editingToken.hue},{editingToken.saturation}%,50%), hsl({editingToken.hue},{editingToken.saturation}%,100%))">
547
552
  <input type="range" min="0" max="100" value={editingToken.lightness}
548
- on:pointerdown={() => beginSliderGesture('edit shadow lightness')}
549
- on:input={(e) => setTokenColor(editingIdx, 'lightness', +e.currentTarget.value)} />
553
+ onpointerdown={() => beginSliderGesture('edit shadow lightness')}
554
+ oninput={(e) => setTokenColor(editingIdx, 'lightness', +e.currentTarget.value)} />
550
555
  </div>
551
556
  <input class="shadow-slider-input" type="number" min="0" max="100"
552
557
  value={editingToken.lightness}
553
- on:change={(e) => setTokenColor(editingIdx, 'lightness', +e.currentTarget.value)} />
558
+ onchange={(e) => setTokenColor(editingIdx, 'lightness', +e.currentTarget.value)} />
554
559
  <span class="shadow-slider-unit">%</span>
555
560
  </div>
556
561
  </div>
557
562
  </div>
558
563
  <div class="shadow-css-output">
559
564
  <code>{shadowTokenCss(editingToken)}</code>
560
- <button class="shadow-copy-btn" on:click={() => copy(shadowTokenCss(editingToken))}>
565
+ <button class="shadow-copy-btn" onclick={() => copy(shadowTokenCss(editingToken))}>
561
566
  {copiedVar === shadowTokenCss(editingToken) ? 'Copied!' : 'Copy CSS'}
562
567
  </button>
563
568
  </div>
@@ -565,10 +570,11 @@
565
570
  <h4 class="global-shadow-title">Global Light</h4>
566
571
  <div class="global-shadow-row">
567
572
  <span class="shadow-slider-label" title="Direction the light source is coming from — controls which side the shadow falls on">Angle</span>
573
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
568
574
  <svg class="angle-dial" viewBox="0 0 48 48" width="48" height="48"
569
- on:pointerdown={handleGlobalDialDown}
570
- on:pointermove={handleGlobalDialMove}
571
- on:pointerup={handleGlobalDialUp}
575
+ onpointerdown={handleGlobalDialDown}
576
+ onpointermove={handleGlobalDialMove}
577
+ onpointerup={handleGlobalDialUp}
572
578
  >
573
579
  <circle cx="24" cy="24" r="20" class="dial-ring" />
574
580
  <line x1="24" y1="24"
@@ -582,40 +588,40 @@
582
588
  </svg>
583
589
  <input class="shadow-slider-input" type="number" min="0" max="360"
584
590
  value={sg.angle}
585
- on:change={(e) => setGlobalAngle(+e.currentTarget.value)} />
591
+ onchange={(e) => setGlobalAngle(+e.currentTarget.value)} />
586
592
  <span class="shadow-slider-unit">&deg;</span>
587
593
  </div>
588
594
  <div class="global-shadow-row">
589
595
  <span class="shadow-slider-label" title="How far the shadow is cast — simulates height off the surface">Dist Min</span>
590
596
  <input type="range" min="0" max="60" value={sg.distanceMin}
591
- on:pointerdown={() => beginSliderGesture('drag global dist min')}
592
- on:input={(e) => setGlobalDistance('distanceMin', +e.currentTarget.value)} />
597
+ onpointerdown={() => beginSliderGesture('drag global dist min')}
598
+ oninput={(e) => setGlobalDistance('distanceMin', +e.currentTarget.value)} />
593
599
  <input class="shadow-slider-input" type="number" min="0" max="100"
594
600
  value={sg.distanceMin}
595
- on:change={(e) => setGlobalDistance('distanceMin', +e.currentTarget.value)} />
601
+ onchange={(e) => setGlobalDistance('distanceMin', +e.currentTarget.value)} />
596
602
  <span class="shadow-slider-unit">px</span>
597
603
  </div>
598
604
  <div class="global-shadow-row">
599
605
  <span class="shadow-slider-label" title="How far the shadow is cast — simulates height off the surface">Dist Max</span>
600
606
  <input type="range" min="0" max="60" value={sg.distanceMax}
601
- on:pointerdown={() => beginSliderGesture('drag global dist max')}
602
- on:input={(e) => setGlobalDistance('distanceMax', +e.currentTarget.value)} />
607
+ onpointerdown={() => beginSliderGesture('drag global dist max')}
608
+ oninput={(e) => setGlobalDistance('distanceMax', +e.currentTarget.value)} />
603
609
  <input class="shadow-slider-input" type="number" min="0" max="100"
604
610
  value={sg.distanceMax}
605
- on:change={(e) => setGlobalDistance('distanceMax', +e.currentTarget.value)} />
611
+ onchange={(e) => setGlobalDistance('distanceMax', +e.currentTarget.value)} />
606
612
  <span class="shadow-slider-unit">px</span>
607
613
  </div>
608
614
  {#if sg.sizeLocked}
609
615
  <div class="global-shadow-row">
610
616
  <span class="shadow-slider-label" title="Grows or shrinks the shadow before blurring — positive makes it larger than the element, negative makes it smaller">Spread</span>
611
617
  <input type="range" min="-50" max="50" value={sg.sizeMin}
612
- on:pointerdown={() => beginSliderGesture('drag global spread')}
613
- on:input={(e) => setGlobalSize('sizeMin', +e.currentTarget.value)} />
618
+ onpointerdown={() => beginSliderGesture('drag global spread')}
619
+ oninput={(e) => setGlobalSize('sizeMin', +e.currentTarget.value)} />
614
620
  <input class="shadow-slider-input" type="number" min="-50" max="50"
615
621
  value={sg.sizeMin}
616
- on:change={(e) => setGlobalSize('sizeMin', +e.currentTarget.value)} />
622
+ onchange={(e) => setGlobalSize('sizeMin', +e.currentTarget.value)} />
617
623
  <span class="shadow-slider-unit">px</span>
618
- <button class="lock-btn" title="Unlock min/max" on:click={() => toggleLock('sizeLocked')}>
624
+ <button class="lock-btn" title="Unlock min/max" onclick={() => toggleLock('sizeLocked')}>
619
625
  <svg viewBox="0 0 16 16" width="14" height="14"><path d="M4 7V5a4 4 0 118 0v2h1a1 1 0 011 1v5a1 1 0 01-1 1H3a1 1 0 01-1-1V8a1 1 0 011-1h1zm2 0h4V5a2 2 0 10-4 0v2z" fill="currentColor"/></svg>
620
626
  </button>
621
627
  </div>
@@ -623,24 +629,24 @@
623
629
  <div class="global-shadow-row">
624
630
  <span class="shadow-slider-label" title="Grows or shrinks the shadow before blurring — positive makes it larger than the element, negative makes it smaller">Spread Min</span>
625
631
  <input type="range" min="-50" max="50" value={sg.sizeMin}
626
- on:pointerdown={() => beginSliderGesture('drag global spread min')}
627
- on:input={(e) => setGlobalSize('sizeMin', +e.currentTarget.value)} />
632
+ onpointerdown={() => beginSliderGesture('drag global spread min')}
633
+ oninput={(e) => setGlobalSize('sizeMin', +e.currentTarget.value)} />
628
634
  <input class="shadow-slider-input" type="number" min="-50" max="50"
629
635
  value={sg.sizeMin}
630
- on:change={(e) => setGlobalSize('sizeMin', +e.currentTarget.value)} />
636
+ onchange={(e) => setGlobalSize('sizeMin', +e.currentTarget.value)} />
631
637
  <span class="shadow-slider-unit">px</span>
632
- <button class="lock-btn unlocked" title="Lock to single value" on:click={() => toggleLock('sizeLocked')}>
638
+ <button class="lock-btn unlocked" title="Lock to single value" onclick={() => toggleLock('sizeLocked')}>
633
639
  <svg viewBox="0 0 16 16" width="14" height="14"><path d="M10 7V5a2 2 0 10-4 0v.5H4V5a4 4 0 118 0v2h1a1 1 0 011 1v5a1 1 0 01-1 1H3a1 1 0 01-1-1V8a1 1 0 011-1h7z" fill="currentColor"/></svg>
634
640
  </button>
635
641
  </div>
636
642
  <div class="global-shadow-row">
637
643
  <span class="shadow-slider-label" title="Grows or shrinks the shadow before blurring — positive makes it larger than the element, negative makes it smaller">Spread Max</span>
638
644
  <input type="range" min="-50" max="50" value={sg.sizeMax}
639
- on:pointerdown={() => beginSliderGesture('drag global spread max')}
640
- on:input={(e) => setGlobalSize('sizeMax', +e.currentTarget.value)} />
645
+ onpointerdown={() => beginSliderGesture('drag global spread max')}
646
+ oninput={(e) => setGlobalSize('sizeMax', +e.currentTarget.value)} />
641
647
  <input class="shadow-slider-input" type="number" min="-50" max="50"
642
648
  value={sg.sizeMax}
643
- on:change={(e) => setGlobalSize('sizeMax', +e.currentTarget.value)} />
649
+ onchange={(e) => setGlobalSize('sizeMax', +e.currentTarget.value)} />
644
650
  <span class="shadow-slider-unit">px</span>
645
651
  </div>
646
652
  {/if}
@@ -648,13 +654,13 @@
648
654
  <div class="global-shadow-row">
649
655
  <span class="shadow-slider-label" title="How soft the shadow edge is — higher values make a wider, more diffused shadow">Blur</span>
650
656
  <input type="range" min="0" max="100" value={sg.blurMin}
651
- on:pointerdown={() => beginSliderGesture('drag global blur')}
652
- on:input={(e) => setGlobalBlur('blurMin', +e.currentTarget.value)} />
657
+ onpointerdown={() => beginSliderGesture('drag global blur')}
658
+ oninput={(e) => setGlobalBlur('blurMin', +e.currentTarget.value)} />
653
659
  <input class="shadow-slider-input" type="number" min="0" max="100"
654
660
  value={sg.blurMin}
655
- on:change={(e) => setGlobalBlur('blurMin', +e.currentTarget.value)} />
661
+ onchange={(e) => setGlobalBlur('blurMin', +e.currentTarget.value)} />
656
662
  <span class="shadow-slider-unit">px</span>
657
- <button class="lock-btn" title="Unlock min/max" on:click={() => toggleLock('blurLocked')}>
663
+ <button class="lock-btn" title="Unlock min/max" onclick={() => toggleLock('blurLocked')}>
658
664
  <svg viewBox="0 0 16 16" width="14" height="14"><path d="M4 7V5a4 4 0 118 0v2h1a1 1 0 011 1v5a1 1 0 01-1 1H3a1 1 0 01-1-1V8a1 1 0 011-1h1zm2 0h4V5a2 2 0 10-4 0v2z" fill="currentColor"/></svg>
659
665
  </button>
660
666
  </div>
@@ -662,24 +668,24 @@
662
668
  <div class="global-shadow-row">
663
669
  <span class="shadow-slider-label" title="How soft the shadow edge is — higher values make a wider, more diffused shadow">Blur Min</span>
664
670
  <input type="range" min="0" max="100" value={sg.blurMin}
665
- on:pointerdown={() => beginSliderGesture('drag global blur min')}
666
- on:input={(e) => setGlobalBlur('blurMin', +e.currentTarget.value)} />
671
+ onpointerdown={() => beginSliderGesture('drag global blur min')}
672
+ oninput={(e) => setGlobalBlur('blurMin', +e.currentTarget.value)} />
667
673
  <input class="shadow-slider-input" type="number" min="0" max="100"
668
674
  value={sg.blurMin}
669
- on:change={(e) => setGlobalBlur('blurMin', +e.currentTarget.value)} />
675
+ onchange={(e) => setGlobalBlur('blurMin', +e.currentTarget.value)} />
670
676
  <span class="shadow-slider-unit">px</span>
671
- <button class="lock-btn unlocked" title="Lock to single value" on:click={() => toggleLock('blurLocked')}>
677
+ <button class="lock-btn unlocked" title="Lock to single value" onclick={() => toggleLock('blurLocked')}>
672
678
  <svg viewBox="0 0 16 16" width="14" height="14"><path d="M10 7V5a2 2 0 10-4 0v.5H4V5a4 4 0 118 0v2h1a1 1 0 011 1v5a1 1 0 01-1 1H3a1 1 0 01-1-1V8a1 1 0 011-1h7z" fill="currentColor"/></svg>
673
679
  </button>
674
680
  </div>
675
681
  <div class="global-shadow-row">
676
682
  <span class="shadow-slider-label" title="How soft the shadow edge is — higher values make a wider, more diffused shadow">Blur Max</span>
677
683
  <input type="range" min="0" max="100" value={sg.blurMax}
678
- on:pointerdown={() => beginSliderGesture('drag global blur max')}
679
- on:input={(e) => setGlobalBlur('blurMax', +e.currentTarget.value)} />
684
+ onpointerdown={() => beginSliderGesture('drag global blur max')}
685
+ oninput={(e) => setGlobalBlur('blurMax', +e.currentTarget.value)} />
680
686
  <input class="shadow-slider-input" type="number" min="0" max="100"
681
687
  value={sg.blurMax}
682
- on:change={(e) => setGlobalBlur('blurMax', +e.currentTarget.value)} />
688
+ onchange={(e) => setGlobalBlur('blurMax', +e.currentTarget.value)} />
683
689
  <span class="shadow-slider-unit">px</span>
684
690
  </div>
685
691
  {/if}
@@ -687,13 +693,13 @@
687
693
  <div class="global-shadow-row">
688
694
  <span class="shadow-slider-label" title="How visible the shadow is — 0% is invisible, 100% is fully opaque">Op.</span>
689
695
  <input type="range" min="0" max="100" value={Math.round(sg.opacityMin * 100)}
690
- on:pointerdown={() => beginSliderGesture('drag global opacity')}
691
- on:input={(e) => setGlobalOpacity('opacityMin', +e.currentTarget.value / 100)} />
696
+ onpointerdown={() => beginSliderGesture('drag global opacity')}
697
+ oninput={(e) => setGlobalOpacity('opacityMin', +e.currentTarget.value / 100)} />
692
698
  <input class="shadow-slider-input" type="number" min="0" max="100"
693
699
  value={Math.round(sg.opacityMin * 100)}
694
- on:change={(e) => setGlobalOpacity('opacityMin', +e.currentTarget.value / 100)} />
700
+ onchange={(e) => setGlobalOpacity('opacityMin', +e.currentTarget.value / 100)} />
695
701
  <span class="shadow-slider-unit">%</span>
696
- <button class="lock-btn" title="Unlock min/max" on:click={() => toggleLock('opacityLocked')}>
702
+ <button class="lock-btn" title="Unlock min/max" onclick={() => toggleLock('opacityLocked')}>
697
703
  <svg viewBox="0 0 16 16" width="14" height="14"><path d="M4 7V5a4 4 0 118 0v2h1a1 1 0 011 1v5a1 1 0 01-1 1H3a1 1 0 01-1-1V8a1 1 0 011-1h1zm2 0h4V5a2 2 0 10-4 0v2z" fill="currentColor"/></svg>
698
704
  </button>
699
705
  </div>
@@ -701,24 +707,24 @@
701
707
  <div class="global-shadow-row">
702
708
  <span class="shadow-slider-label" title="How visible the shadow is — 0% is invisible, 100% is fully opaque">Op. Min</span>
703
709
  <input type="range" min="0" max="100" value={Math.round(sg.opacityMin * 100)}
704
- on:pointerdown={() => beginSliderGesture('drag global opacity min')}
705
- on:input={(e) => setGlobalOpacity('opacityMin', +e.currentTarget.value / 100)} />
710
+ onpointerdown={() => beginSliderGesture('drag global opacity min')}
711
+ oninput={(e) => setGlobalOpacity('opacityMin', +e.currentTarget.value / 100)} />
706
712
  <input class="shadow-slider-input" type="number" min="0" max="100"
707
713
  value={Math.round(sg.opacityMin * 100)}
708
- on:change={(e) => setGlobalOpacity('opacityMin', +e.currentTarget.value / 100)} />
714
+ onchange={(e) => setGlobalOpacity('opacityMin', +e.currentTarget.value / 100)} />
709
715
  <span class="shadow-slider-unit">%</span>
710
- <button class="lock-btn unlocked" title="Lock to single value" on:click={() => toggleLock('opacityLocked')}>
716
+ <button class="lock-btn unlocked" title="Lock to single value" onclick={() => toggleLock('opacityLocked')}>
711
717
  <svg viewBox="0 0 16 16" width="14" height="14"><path d="M10 7V5a2 2 0 10-4 0v.5H4V5a4 4 0 118 0v2h1a1 1 0 011 1v5a1 1 0 01-1 1H3a1 1 0 01-1-1V8a1 1 0 011-1h7z" fill="currentColor"/></svg>
712
718
  </button>
713
719
  </div>
714
720
  <div class="global-shadow-row">
715
721
  <span class="shadow-slider-label" title="How visible the shadow is — 0% is invisible, 100% is fully opaque">Op. Max</span>
716
722
  <input type="range" min="0" max="100" value={Math.round(sg.opacityMax * 100)}
717
- on:pointerdown={() => beginSliderGesture('drag global opacity max')}
718
- on:input={(e) => setGlobalOpacity('opacityMax', +e.currentTarget.value / 100)} />
723
+ onpointerdown={() => beginSliderGesture('drag global opacity max')}
724
+ oninput={(e) => setGlobalOpacity('opacityMax', +e.currentTarget.value / 100)} />
719
725
  <input class="shadow-slider-input" type="number" min="0" max="100"
720
726
  value={Math.round(sg.opacityMax * 100)}
721
- on:change={(e) => setGlobalOpacity('opacityMax', +e.currentTarget.value / 100)} />
727
+ onchange={(e) => setGlobalOpacity('opacityMax', +e.currentTarget.value / 100)} />
722
728
  <span class="shadow-slider-unit">%</span>
723
729
  </div>
724
730
  {/if}
@@ -729,52 +735,52 @@
729
735
  <span class="shadow-slider-label" title="Hue — the base color of the shadow (0°=red, 120°=green, 240°=blue)">H</span>
730
736
  <div class="slider-track" style="background: {shadowHueGrad}">
731
737
  <input type="range" min="0" max="360" value={sg.hue}
732
- on:pointerdown={() => beginSliderGesture('drag global hue')}
733
- on:input={(e) => setGlobalColor('hue', +e.currentTarget.value)} />
738
+ onpointerdown={() => beginSliderGesture('drag global hue')}
739
+ oninput={(e) => setGlobalColor('hue', +e.currentTarget.value)} />
734
740
  </div>
735
741
  <input class="shadow-slider-input" type="number" min="0" max="360"
736
742
  value={sg.hue}
737
- on:change={(e) => setGlobalColor('hue', +e.currentTarget.value)} />
743
+ onchange={(e) => setGlobalColor('hue', +e.currentTarget.value)} />
738
744
  <span class="shadow-slider-unit">&deg;</span>
739
745
  </div>
740
746
  <div class="global-shadow-row">
741
747
  <span class="shadow-slider-label" title="Saturation — 0% is gray, 100% is full color intensity">S</span>
742
748
  <div class="slider-track" style="background: {shadowSatGrad}">
743
749
  <input type="range" min="0" max="100" value={sg.saturation}
744
- on:pointerdown={() => beginSliderGesture('drag global saturation')}
745
- on:input={(e) => setGlobalColor('saturation', +e.currentTarget.value)} />
750
+ onpointerdown={() => beginSliderGesture('drag global saturation')}
751
+ oninput={(e) => setGlobalColor('saturation', +e.currentTarget.value)} />
746
752
  </div>
747
753
  <input class="shadow-slider-input" type="number" min="0" max="100"
748
754
  value={sg.saturation}
749
- on:change={(e) => setGlobalColor('saturation', +e.currentTarget.value)} />
755
+ onchange={(e) => setGlobalColor('saturation', +e.currentTarget.value)} />
750
756
  <span class="shadow-slider-unit">%</span>
751
757
  </div>
752
758
  <div class="global-shadow-row">
753
759
  <span class="shadow-slider-label" title="Lightness — 0% is black, 100% is white">L</span>
754
760
  <div class="slider-track" style="background: {shadowLightGrad}">
755
761
  <input type="range" min="0" max="100" value={sg.lightness}
756
- on:pointerdown={() => beginSliderGesture('drag global lightness')}
757
- on:input={(e) => setGlobalColor('lightness', +e.currentTarget.value)} />
762
+ onpointerdown={() => beginSliderGesture('drag global lightness')}
763
+ oninput={(e) => setGlobalColor('lightness', +e.currentTarget.value)} />
758
764
  </div>
759
765
  <input class="shadow-slider-input" type="number" min="0" max="100"
760
766
  value={sg.lightness}
761
- on:change={(e) => setGlobalColor('lightness', +e.currentTarget.value)} />
767
+ onchange={(e) => setGlobalColor('lightness', +e.currentTarget.value)} />
762
768
  <span class="shadow-slider-unit">%</span>
763
769
  </div>
764
770
  </div>
765
771
  </div>
766
- <button class="bg-picker-btn" on:click={toggleBgPicker}>BG</button>
772
+ <button class="bg-picker-btn" onclick={toggleBgPicker}>BG</button>
767
773
  {#if bgPickerOpen}
768
774
  <div class="bg-picker-menu">
769
775
  {#each bgColorGroups as group}
770
- <button class="bg-group-header" on:click={() => expandedGroup = expandedGroup === group.label ? null : group.label}>
776
+ <button class="bg-group-header" onclick={() => expandedGroup = expandedGroup === group.label ? null : group.label}>
771
777
  <span>{group.label}</span>
772
778
  <span class="bg-group-arrow">{expandedGroup === group.label ? '▴' : '▾'}</span>
773
779
  </button>
774
780
  {#if expandedGroup === group.label}
775
781
  <div class="bg-group-colors">
776
782
  {#each group.colors as color}
777
- <button class="bg-color-option" on:click={() => pickBg(color.value)}>
783
+ <button class="bg-color-option" onclick={() => pickBg(color.value)}>
778
784
  <span class="bg-color-swatch" style="background: {color.value};"></span>
779
785
  <span>{color.label}</span>
780
786
  </button>