@motion-proto/live-tokens 0.1.1 → 0.3.2

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 (224) hide show
  1. package/README.md +168 -21
  2. package/dist-plugin/index.cjs +823 -336
  3. package/dist-plugin/index.d.cts +9 -7
  4. package/dist-plugin/index.d.ts +9 -7
  5. package/dist-plugin/index.js +822 -335
  6. package/package.json +46 -20
  7. package/src/assets/newspaper.webp +0 -0
  8. package/src/assets/offering.webp +0 -0
  9. package/src/component-editor/BadgeEditor.svelte +170 -0
  10. package/src/component-editor/CalloutEditor.svelte +103 -0
  11. package/src/component-editor/CardEditor.svelte +184 -0
  12. package/src/component-editor/CollapsibleSectionEditor.svelte +167 -0
  13. package/src/component-editor/CornerBadgeEditor.svelte +207 -0
  14. package/src/component-editor/DialogEditor.svelte +172 -0
  15. package/src/component-editor/ImageEditor.svelte +72 -0
  16. package/src/component-editor/InlineEditActionsEditor.svelte +83 -0
  17. package/src/component-editor/NotificationEditor.svelte +160 -0
  18. package/src/component-editor/ProgressBarEditor.svelte +124 -0
  19. package/src/component-editor/RadioButtonEditor.svelte +140 -0
  20. package/src/component-editor/SectionDividerEditor.svelte +263 -0
  21. package/src/component-editor/SegmentedControlEditor.svelte +154 -0
  22. package/src/component-editor/StandardButtonsEditor.svelte +178 -0
  23. package/src/component-editor/TabBarEditor.svelte +137 -0
  24. package/src/component-editor/TableEditor.svelte +128 -0
  25. package/src/component-editor/TooltipEditor.svelte +122 -0
  26. package/src/component-editor/editorTokens.test.ts +93 -0
  27. package/src/component-editor/groupKeySlots.test.ts +67 -0
  28. package/src/component-editor/groupKeySnapshot.test.ts +52 -0
  29. package/src/component-editor/index.ts +5 -0
  30. package/src/component-editor/registry.ts +246 -0
  31. package/src/component-editor/scaffolding/AngleDial.svelte +185 -0
  32. package/src/component-editor/scaffolding/ComponentEditorBase.svelte +96 -0
  33. package/src/component-editor/scaffolding/ComponentFileManager.svelte +682 -0
  34. package/src/component-editor/scaffolding/ComponentFileMenu.svelte +312 -0
  35. package/src/component-editor/scaffolding/ComponentsTab.svelte +69 -0
  36. package/src/component-editor/scaffolding/CopyFromMenu.svelte +246 -0
  37. package/src/component-editor/scaffolding/DemoHeader.svelte +21 -0
  38. package/src/component-editor/scaffolding/DividerEditor.svelte +81 -0
  39. package/src/component-editor/scaffolding/FieldsetWrapper.svelte +46 -0
  40. package/src/component-editor/scaffolding/GradientCard.svelte +291 -0
  41. package/src/component-editor/scaffolding/LinkageChart.svelte +297 -0
  42. package/src/component-editor/scaffolding/LinkedBlock.svelte +418 -0
  43. package/src/component-editor/scaffolding/NonStylableConfig.svelte +57 -0
  44. package/src/component-editor/scaffolding/SaveAsDialog.svelte +177 -0
  45. package/src/component-editor/scaffolding/ShadowBackdrop.svelte +25 -0
  46. package/src/component-editor/scaffolding/ShadowBackdropControls.svelte +56 -0
  47. package/src/component-editor/scaffolding/StateBlock.svelte +115 -0
  48. package/src/component-editor/scaffolding/TokenLayout.svelte +511 -0
  49. package/src/component-editor/scaffolding/TypeEditor.svelte +82 -0
  50. package/src/component-editor/scaffolding/VariantGroup.svelte +277 -0
  51. package/src/component-editor/scaffolding/buildTypeGroupTokens.ts +97 -0
  52. package/src/component-editor/scaffolding/componentSectionType.ts +8 -0
  53. package/src/component-editor/scaffolding/componentSources.ts +9 -0
  54. package/src/component-editor/scaffolding/defaultSections.ts +16 -0
  55. package/src/component-editor/scaffolding/editorContext.ts +44 -0
  56. package/src/component-editor/scaffolding/linkedBlock.ts +226 -0
  57. package/src/component-editor/scaffolding/siblings.ts +33 -0
  58. package/src/component-editor/scaffolding/types.ts +39 -0
  59. package/src/components/Badge.svelte +231 -42
  60. package/src/components/Button.svelte +324 -124
  61. package/src/components/Callout.svelte +145 -0
  62. package/src/components/Card.svelte +123 -25
  63. package/src/components/CollapsibleSection.svelte +213 -35
  64. package/src/components/CornerBadge.svelte +224 -0
  65. package/src/components/Dialog.svelte +137 -114
  66. package/src/components/Image.svelte +43 -0
  67. package/src/components/InlineEditActions.svelte +74 -14
  68. package/src/components/Notification.svelte +184 -163
  69. package/src/components/ProgressBar.svelte +216 -22
  70. package/src/components/RadioButton.svelte +110 -40
  71. package/src/components/SectionDivider.svelte +428 -74
  72. package/src/components/SegmentedControl.svelte +203 -0
  73. package/src/components/TabBar.svelte +146 -21
  74. package/src/components/Table.svelte +102 -0
  75. package/src/components/Tooltip.svelte +45 -19
  76. package/src/components/types.ts +51 -0
  77. package/src/data/google-fonts.json +75 -0
  78. package/src/lib/ColumnsOverlay.svelte +20 -7
  79. package/src/lib/LiveEditorOverlay.svelte +257 -78
  80. package/src/lib/columnsOverlay.ts +21 -17
  81. package/src/lib/componentConfig.test.ts +204 -0
  82. package/src/lib/componentConfigKeys.ts +19 -0
  83. package/src/lib/componentConfigService.ts +88 -0
  84. package/src/lib/copyPopover.ts +30 -0
  85. package/src/lib/cssVarSync.ts +59 -7
  86. package/src/lib/editorConfigStore.ts +0 -10
  87. package/src/lib/editorCore.ts +402 -0
  88. package/src/lib/editorKeybindings.ts +52 -0
  89. package/src/lib/editorPersistence.ts +106 -0
  90. package/src/lib/editorRenderer.ts +74 -0
  91. package/src/lib/editorStore.test.ts +328 -0
  92. package/src/lib/editorStore.ts +412 -0
  93. package/src/lib/editorTypes.ts +100 -0
  94. package/src/lib/editorViewStore.ts +55 -0
  95. package/src/lib/files/versionedFileResource.ts +140 -0
  96. package/src/lib/fontLoader.ts +130 -0
  97. package/src/lib/fontMigration.ts +140 -0
  98. package/src/lib/fontParse.ts +168 -0
  99. package/src/lib/index.ts +48 -30
  100. package/src/lib/lazyConfig.test.ts +54 -0
  101. package/src/lib/migrations/2026-04-24-component-prefix-and-suffix-renames.ts +64 -0
  102. package/src/lib/migrations/2026-04-24-legacy-keys-and-bg-to-canvas.ts +71 -0
  103. package/src/lib/migrations/2026-04-27-segmentedcontrol-disabled-flatten.ts +43 -0
  104. package/src/lib/migrations/2026-05-08-collapsiblesection-frame-and-cleanup.ts +68 -0
  105. package/src/lib/migrations/2026-05-08-collapsiblesection-variant-namespace.ts +35 -0
  106. package/src/lib/migrations/2026-05-10-sectiondivider-gradient-stops.ts +50 -0
  107. package/src/lib/migrations/2026-05-13-primary-to-brand.ts +90 -0
  108. package/src/lib/migrations/index.ts +93 -0
  109. package/src/lib/migrations/migrations.test.ts +341 -0
  110. package/src/lib/navLinkTypes.ts +1 -0
  111. package/src/lib/overlayState.ts +3 -0
  112. package/src/lib/paletteDerivation.ts +300 -0
  113. package/src/lib/parentRouteStore.ts +42 -0
  114. package/src/lib/parsers/globalRootBlock.ts +32 -0
  115. package/src/lib/presetService.ts +94 -0
  116. package/src/lib/router.ts +42 -10
  117. package/src/lib/scrollSection.ts +45 -0
  118. package/src/lib/slices/columns.ts +59 -0
  119. package/src/lib/slices/components.ts +362 -0
  120. package/src/lib/slices/domainVars.ts +15 -0
  121. package/src/lib/slices/fonts.ts +30 -0
  122. package/src/lib/slices/gradients.ts +153 -0
  123. package/src/lib/slices/overlays.ts +132 -0
  124. package/src/lib/slices/palettes.ts +26 -0
  125. package/src/lib/slices/shadows.ts +123 -0
  126. package/src/lib/storage.ts +88 -0
  127. package/src/lib/themeInit.ts +74 -0
  128. package/src/lib/themeService.ts +101 -0
  129. package/src/lib/themeTypes.ts +146 -0
  130. package/src/lib/tokenRegistry.ts +148 -0
  131. package/src/pages/ComponentEditorPage.svelte +384 -0
  132. package/src/pages/ComponentEditorPage.svelte.d.ts +2 -0
  133. package/src/pages/Editor.svelte +98 -0
  134. package/src/pages/Editor.svelte.d.ts +2 -0
  135. package/src/pages/EditorShell.svelte +348 -0
  136. package/src/styles/_padding.scss +34 -0
  137. package/src/styles/fonts/Fraunces/Fraunces-italic-latin-ext.woff2 +0 -0
  138. package/src/styles/fonts/Fraunces/Fraunces-italic-latin.woff2 +0 -0
  139. package/src/styles/fonts/Fraunces/Fraunces-roman-latin-ext.woff2 +0 -0
  140. package/src/styles/fonts/Fraunces/Fraunces-roman-latin.woff2 +0 -0
  141. package/src/styles/fonts/Manrope/Manrope-latin-ext.woff2 +0 -0
  142. package/src/styles/fonts/Manrope/Manrope-latin.woff2 +0 -0
  143. package/src/styles/fonts.css +22 -10
  144. package/src/styles/form-controls.css +14 -16
  145. package/src/styles/tokens.css +1322 -0
  146. package/src/styles/ui-editor.css +126 -0
  147. package/src/{showcase → ui}/BezierCurveEditor.svelte +14 -14
  148. package/src/{showcase → ui}/ColorEditPanel.svelte +42 -36
  149. package/src/ui/EditorViewSwitcher.svelte +180 -0
  150. package/src/ui/FontStackEditor.svelte +360 -0
  151. package/src/ui/GradientEditor.svelte +461 -0
  152. package/src/ui/GradientStopPicker.svelte +74 -0
  153. package/src/ui/PaletteEditor.svelte +1590 -0
  154. package/src/ui/PaletteEditor.test.ts +108 -0
  155. package/src/ui/PresetFileManager.svelte +567 -0
  156. package/src/ui/ProjectFontsSection.svelte +645 -0
  157. package/src/{showcase → ui}/SurfacesTab.svelte +39 -39
  158. package/src/{showcase → ui}/TextTab.svelte +27 -27
  159. package/src/{showcase/TokenFileManager.svelte → ui/ThemeFileManager.svelte} +196 -112
  160. package/src/ui/Toggle.svelte +108 -0
  161. package/src/ui/UICopyPopover.svelte +78 -0
  162. package/src/{showcase/EditorDialog.svelte → ui/UIDialog.svelte} +66 -25
  163. package/src/ui/UIFontFamilySelector.svelte +309 -0
  164. package/src/ui/UIFontSizeSelector.svelte +165 -0
  165. package/src/ui/UIFontWeightSelector.svelte +52 -0
  166. package/src/ui/UILineHeightSelector.svelte +47 -0
  167. package/src/ui/UILinkToggle.svelte +60 -0
  168. package/src/ui/UIOptionItem.svelte +74 -0
  169. package/src/ui/UIOptionList.svelte +27 -0
  170. package/src/ui/UIPaddingSelector.svelte +661 -0
  171. package/src/ui/UIPaletteSelector.svelte +1084 -0
  172. package/src/ui/UIRadio.svelte +72 -0
  173. package/src/ui/UIRadioGroup.svelte +59 -0
  174. package/src/ui/UIRelinkConfirmPopover.svelte +235 -0
  175. package/src/ui/UITokenSelector.svelte +509 -0
  176. package/src/ui/UIVariantSelector.svelte +145 -0
  177. package/src/ui/VariablesTab.svelte +252 -0
  178. package/src/ui/index.ts +31 -0
  179. package/src/ui/keepInViewport.ts +84 -0
  180. package/src/ui/palette/GradientStopEditor.svelte +482 -0
  181. package/src/ui/palette/OverridesPanel.svelte +526 -0
  182. package/src/ui/palette/PaletteBase.svelte +165 -0
  183. package/src/ui/palette/ScaleCurveEditor.svelte +38 -0
  184. package/src/ui/palette/paletteEditorState.ts +89 -0
  185. package/src/ui/sections/ColumnsSection.svelte +273 -0
  186. package/src/ui/sections/GradientsSection.svelte +147 -0
  187. package/src/ui/sections/OverlaysSection.svelte +670 -0
  188. package/src/ui/sections/ShadowsSection.svelte +1250 -0
  189. package/src/ui/sections/TokenScaleTable.svelte +332 -0
  190. package/src/ui/sections/tokenScales.ts +81 -0
  191. package/src/ui/variantScales.ts +108 -0
  192. package/src/components/DetailNav.svelte +0 -78
  193. package/src/components/Toggle.svelte +0 -86
  194. package/src/lib/tokenInit.ts +0 -29
  195. package/src/lib/tokenService.ts +0 -144
  196. package/src/lib/tokenTypes.ts +0 -45
  197. package/src/pages/Admin.svelte +0 -100
  198. package/src/pages/ShowcasePage.svelte +0 -144
  199. package/src/showcase/BackupBrowser.svelte +0 -617
  200. package/src/showcase/ComponentsTab.svelte +0 -105
  201. package/src/showcase/PaletteEditor.svelte +0 -2579
  202. package/src/showcase/PaletteSelector.svelte +0 -627
  203. package/src/showcase/TokenMap.svelte +0 -54
  204. package/src/showcase/VariablesTab.svelte +0 -2655
  205. package/src/showcase/VisualsTab.svelte +0 -231
  206. package/src/showcase/demos/BadgeDemo.svelte +0 -56
  207. package/src/showcase/demos/CardDemo.svelte +0 -50
  208. package/src/showcase/demos/ChoiceButtonsDemo.svelte +0 -192
  209. package/src/showcase/demos/CollapsibleSectionDemo.svelte +0 -54
  210. package/src/showcase/demos/DialogDemo.svelte +0 -42
  211. package/src/showcase/demos/InlineEditActionsDemo.svelte +0 -25
  212. package/src/showcase/demos/NotificationDemo.svelte +0 -147
  213. package/src/showcase/demos/ProgressBarDemo.svelte +0 -54
  214. package/src/showcase/demos/RadioButtonDemo.svelte +0 -56
  215. package/src/showcase/demos/SectionDividerDemo.svelte +0 -77
  216. package/src/showcase/demos/StandardButtonsDemo.svelte +0 -455
  217. package/src/showcase/demos/TabBarDemo.svelte +0 -58
  218. package/src/showcase/demos/TooltipDemo.svelte +0 -52
  219. package/src/showcase/editor.css +0 -93
  220. package/src/showcase/index.ts +0 -17
  221. package/src/styles/fonts/Domine/Domine-VariableFont_wght.ttf +0 -0
  222. package/src/styles/fonts/Domine/OFL.txt +0 -97
  223. package/src/styles/fonts/Domine/README.txt +0 -66
  224. /package/src/{showcase → ui}/curveEngine.ts +0 -0
@@ -0,0 +1,126 @@
1
+ /* Editor UI chrome — `--ui-*` tokens. Theme-immune; see CONVENTIONS.md. */
2
+
3
+ .editor-page {
4
+ --ui-font-sans: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
5
+ --ui-font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
6
+
7
+ font-family: var(--ui-font-sans);
8
+ }
9
+
10
+ /* Override tokens.css's global :where(*) font-family. */
11
+ .editor-page *:not([class*="fa-"]) {
12
+ font-family: inherit;
13
+ }
14
+
15
+ .editor-page {
16
+ /* Grayscale ramp — source of truth; lower number = darker. */
17
+ --ui-gray-50: #050505;
18
+ --ui-gray-100: #0a0a0a;
19
+ --ui-gray-150: #0f0f0f;
20
+ --ui-gray-200: #141414;
21
+ --ui-gray-250: #1a1a1a;
22
+ --ui-gray-300: #212121;
23
+ --ui-gray-350: #292929;
24
+ --ui-gray-400: #333333;
25
+ --ui-gray-500: #4d4d4d;
26
+ --ui-gray-600: #666666;
27
+ --ui-gray-700: #808080;
28
+ --ui-gray-750: #999999;
29
+ --ui-gray-800: #bfbfbf;
30
+ --ui-gray-850: #c7c7c7;
31
+ --ui-gray-950: #f2f2f2;
32
+
33
+ --ui-text-primary: #ffffff;
34
+ --ui-text-secondary: var(--ui-gray-800);
35
+ --ui-text-tertiary: var(--ui-gray-700);
36
+ --ui-text-muted: var(--ui-gray-500);
37
+ --ui-text-disabled: var(--ui-gray-400);
38
+ --ui-text-accent: var(--ui-gray-950);
39
+ --ui-text-success: var(--ui-gray-850);
40
+
41
+ /* Bright amber used for selection dots, focus halos, and "unsaved" / "dirty"
42
+ state indicators. Single token shared by all "this is the live thing"
43
+ surfaces so the editor speaks one selection language. */
44
+ --ui-highlight: #ffac28;
45
+
46
+ /* Link-state signals — bar attached to a control's left edge when its value
47
+ is shared with siblings (active), popped off into the column gap when the
48
+ control has broken away from its sibling group (broken). */
49
+ --ui-link-active: #6cd0c2;
50
+ --ui-link-broken: #f0c34a;
51
+ --ui-link-broken-glow: rgba(240, 195, 74, 0.28);
52
+
53
+ --ui-border-faint: var(--ui-gray-400);
54
+ --ui-border-subtle: var(--ui-gray-500);
55
+ --ui-border-default: var(--ui-gray-600);
56
+ --ui-border-medium: var(--ui-gray-700);
57
+ --ui-border-strong: var(--ui-gray-800);
58
+
59
+ --ui-surface-lowest: var(--ui-gray-50);
60
+ --ui-surface-lower: var(--ui-gray-100);
61
+ --ui-surface-low: var(--ui-gray-150);
62
+ --ui-surface: var(--ui-gray-200);
63
+ --ui-surface-high: var(--ui-gray-250);
64
+ --ui-surface-higher: var(--ui-gray-300);
65
+ --ui-surface-highest: var(--ui-gray-350);
66
+
67
+ --ui-toggle: var(--ui-gray-700);
68
+
69
+ --ui-hover-lowest: #000000;
70
+ --ui-hover-low: var(--ui-gray-100);
71
+ --ui-hover: var(--ui-gray-150);
72
+ --ui-hover-high: var(--ui-gray-250);
73
+
74
+ --ui-radius-none: 0;
75
+ --ui-radius-sm: 0.125rem;
76
+ --ui-radius-md: 0.25rem;
77
+ --ui-radius-lg: 0.375rem;
78
+ --ui-radius-xl: 0.5rem;
79
+ --ui-radius-2xl: 0.625rem;
80
+ --ui-radius-full: 9999px;
81
+
82
+ --ui-space-2: 0.125rem;
83
+ --ui-space-4: 0.25rem;
84
+ --ui-space-6: 0.375rem;
85
+ --ui-space-8: 0.5rem;
86
+ --ui-space-10: 0.625rem;
87
+ --ui-space-12: 0.75rem;
88
+ --ui-space-16: 1rem;
89
+ --ui-space-20: 1.25rem;
90
+ --ui-space-24: 1.5rem;
91
+ --ui-space-32: 2rem;
92
+ --ui-space-48: 3rem;
93
+
94
+ --ui-font-size-xs: 0.8125rem; /* 13px */
95
+ --ui-font-size-sm: 0.875rem; /* 14px */
96
+ --ui-font-size-md: 0.9375rem; /* 15px */
97
+ --ui-font-size-lg: 1.0625rem; /* 17px */
98
+ --ui-font-size-xl: 1.1875rem; /* 19px */
99
+ --ui-font-size-2xl: 1.3125rem; /* 21px */
100
+ --ui-font-size-3xl: 1.625rem; /* 26px */
101
+ --ui-font-size-4xl: 2rem; /* 32px */
102
+
103
+ --ui-font-weight-normal: 400;
104
+ --ui-font-weight-medium: 500;
105
+ --ui-font-weight-semibold: 600;
106
+ --ui-font-weight-bold: 700;
107
+
108
+ --ui-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5);
109
+ --ui-shadow-md: 0 2px 6px rgba(0, 0, 0, 0.5);
110
+ --ui-shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.6);
111
+ --ui-shadow-overlay: 0 10px 40px rgba(0, 0, 0, 0.7);
112
+
113
+ --ui-transition-fast: 120ms ease;
114
+ --ui-transition-base: 180ms ease;
115
+
116
+ --ui-line-height-normal: 1.25;
117
+ --ui-line-height-relaxed: 1.5;
118
+ --ui-opacity-disabled: 0.5;
119
+ }
120
+
121
+ /* Dev overlay tokens — scoped to .lt-app to reach chrome outside .editor-page. */
122
+ .lt-app {
123
+ --ui-overlay-fill: rgba(128, 128, 128, 0.06);
124
+ --ui-overlay-border: rgba(128, 128, 128, 0.32);
125
+ --ui-overlay-num: rgba(128, 128, 128, 0.75);
126
+ }
@@ -413,7 +413,7 @@
413
413
  .curve-panel {
414
414
  display: flex;
415
415
  flex-direction: column;
416
- gap: var(--space-4);
416
+ gap: var(--ui-space-4);
417
417
  }
418
418
 
419
419
  .curve-panel-header {
@@ -423,8 +423,8 @@
423
423
  }
424
424
 
425
425
  .curve-panel-label {
426
- font-size: var(--font-md);
427
- font-weight: var(--font-weight-semibold);
426
+ font-size: var(--ui-font-size-md);
427
+ font-weight: var(--ui-font-weight-semibold);
428
428
  color: var(--ui-text-tertiary);
429
429
  }
430
430
 
@@ -439,7 +439,7 @@
439
439
  height: 100%;
440
440
  background: transparent;
441
441
  border: 1px solid var(--ui-border-subtle);
442
- border-radius: var(--radius-sm);
442
+ border-radius: var(--ui-radius-sm);
443
443
  cursor: crosshair;
444
444
  display: block;
445
445
  }
@@ -549,28 +549,28 @@
549
549
  align-items: center;
550
550
  justify-content: space-between;
551
551
  flex-wrap: wrap;
552
- gap: var(--space-2);
553
- padding-top: var(--space-2);
552
+ gap: var(--ui-space-2);
553
+ padding-top: var(--ui-space-2);
554
554
  }
555
555
 
556
556
  .curve-toolbar-left {
557
557
  display: flex;
558
558
  align-items: center;
559
- gap: var(--space-4);
559
+ gap: var(--ui-space-4);
560
560
  flex-wrap: wrap;
561
561
  }
562
562
 
563
563
  .curve-tool-btn {
564
564
  display: flex;
565
565
  align-items: center;
566
- gap: var(--space-4);
567
- padding: var(--space-2) var(--space-6);
566
+ gap: var(--ui-space-4);
567
+ padding: var(--ui-space-2) var(--ui-space-6);
568
568
  border: 1px solid var(--ui-border-subtle);
569
- border-radius: var(--radius-sm);
569
+ border-radius: var(--ui-radius-sm);
570
570
  background: var(--ui-surface-lowest);
571
571
  cursor: pointer;
572
572
  color: var(--ui-text-muted);
573
- font-size: var(--font-md);
573
+ font-size: var(--ui-font-size-md);
574
574
  }
575
575
 
576
576
  .curve-tool-btn:hover {
@@ -601,14 +601,14 @@
601
601
  }
602
602
 
603
603
  .curve-hint {
604
- font-size: var(--font-md);
604
+ font-size: var(--ui-font-size-md);
605
605
  color: var(--ui-text-muted);
606
606
  opacity: 0.6;
607
607
  }
608
608
 
609
609
  .curve-templates {
610
610
  display: flex;
611
- gap: var(--space-2);
611
+ gap: var(--ui-space-2);
612
612
  }
613
613
 
614
614
  .curve-template-btn {
@@ -619,7 +619,7 @@
619
619
  height: 1rem;
620
620
  padding: 0;
621
621
  border: 1px solid var(--ui-border-subtle);
622
- border-radius: var(--radius-sm);
622
+ border-radius: var(--ui-radius-sm);
623
623
  background: var(--ui-surface-lowest);
624
624
  cursor: pointer;
625
625
  }
@@ -10,6 +10,12 @@
10
10
  export let onConfirm: () => void = () => {};
11
11
  export let onCancel: () => void = () => {};
12
12
  export let onRemoveOverride: () => void = () => {};
13
+ /**
14
+ * Optional pointerdown hook for slider drags — lets parents open a store
15
+ * transaction so the whole drag collapses to one undo step. If the parent
16
+ * doesn't route slider writes through the editor store, leave this unset.
17
+ */
18
+ export let onSliderStart: () => void = () => {};
13
19
 
14
20
  // Hue-chroma mode props (for neutral/gray base editing)
15
21
  export let mode: 'hsl' | 'hue-chroma' = 'hsl';
@@ -179,7 +185,7 @@
179
185
  <button class="hsl-hex" on:click={startHexEdit} title="Click to edit hex">{previewHex}</button>
180
186
  {/if}
181
187
  {#if mode === 'hue-chroma'}
182
- <code class="hsl-values">oklch({PREVIEW_LIGHTNESS}, {chroma.toFixed(3)}, {hue})</code>
188
+ <code class="hsl-values">oklch({PREVIEW_LIGHTNESS}, {chroma.toFixed(3)}, {Math.round(hue)})</code>
183
189
  {:else}
184
190
  <code class="hsl-values">hsl({hsl[0]}, {hsl[1]}%, {hsl[2]}%)</code>
185
191
  {/if}
@@ -205,7 +211,7 @@
205
211
  {#if mode === 'hue-chroma'}
206
212
  <div class="hsl-slider-row">
207
213
  <span class="hsl-slider-label">H</span>
208
- <div class="slider-track" style="background: {hueGradient}">
214
+ <div class="slider-track" style="background: {hueGradient}" on:pointerdown={onSliderStart}>
209
215
  <input type="range" min="0" max="360" value={hue}
210
216
  on:input={(e) => onHueChromaChange(+e.currentTarget.value, chroma)} />
211
217
  </div>
@@ -220,7 +226,7 @@
220
226
  </div>
221
227
  <div class="hsl-slider-row">
222
228
  <span class="hsl-slider-label">C</span>
223
- <div class="slider-track" style="background: {chromaGradient}">
229
+ <div class="slider-track" style="background: {chromaGradient}" on:pointerdown={onSliderStart}>
224
230
  <input type="range" min="0" max={CHROMA_MAX} step="0.001" value={chroma}
225
231
  on:input={(e) => onHueChromaChange(hue, +e.currentTarget.value)} />
226
232
  </div>
@@ -237,7 +243,7 @@
237
243
  {:else}
238
244
  <div class="hsl-slider-row">
239
245
  <span class="hsl-slider-label">H</span>
240
- <div class="slider-track" style="background: {hueGrad(hsl[1], hsl[2])}">
246
+ <div class="slider-track" style="background: {hueGrad(hsl[1], hsl[2])}" on:pointerdown={onSliderStart}>
241
247
  <input type="range" min="0" max="360" value={hsl[0]}
242
248
  on:input={(e) => updateHsl(0, +e.currentTarget.value)} />
243
249
  </div>
@@ -252,7 +258,7 @@
252
258
  </div>
253
259
  <div class="hsl-slider-row">
254
260
  <span class="hsl-slider-label">S</span>
255
- <div class="slider-track" style="background: {satGrad(hsl[0], hsl[2])}">
261
+ <div class="slider-track" style="background: {satGrad(hsl[0], hsl[2])}" on:pointerdown={onSliderStart}>
256
262
  <input type="range" min="0" max="100" value={hsl[1]}
257
263
  on:input={(e) => updateHsl(1, +e.currentTarget.value)} />
258
264
  </div>
@@ -267,7 +273,7 @@
267
273
  </div>
268
274
  <div class="hsl-slider-row">
269
275
  <span class="hsl-slider-label">L</span>
270
- <div class="slider-track" style="background: {lightGrad(hsl[0], hsl[1])}">
276
+ <div class="slider-track" style="background: {lightGrad(hsl[0], hsl[1])}" on:pointerdown={onSliderStart}>
271
277
  <input type="range" min="0" max="100" value={hsl[2]}
272
278
  on:input={(e) => updateHsl(2, +e.currentTarget.value)} />
273
279
  </div>
@@ -288,24 +294,24 @@
288
294
  .hsl-panel {
289
295
  display: flex;
290
296
  flex-direction: column;
291
- gap: var(--space-12);
292
- padding: var(--space-12);
297
+ gap: var(--ui-space-12);
298
+ padding: var(--ui-space-12);
293
299
  background: var(--ui-surface-lowest);
294
300
  border: 1px solid var(--ui-border-subtle);
295
- border-radius: var(--radius-md);
301
+ border-radius: var(--ui-radius-md);
296
302
  }
297
303
 
298
304
  .hsl-panel-header {
299
305
  display: flex;
300
306
  align-items: center;
301
- gap: var(--space-8);
307
+ gap: var(--ui-space-8);
302
308
  flex-wrap: wrap;
303
309
  }
304
310
 
305
311
  .hsl-preview {
306
312
  width: 1.5rem;
307
313
  height: 1.5rem;
308
- border-radius: var(--radius-sm);
314
+ border-radius: var(--ui-radius-sm);
309
315
  border: 1px solid var(--ui-border-faint);
310
316
  flex-shrink: 0;
311
317
  }
@@ -318,11 +324,11 @@
318
324
  height: 1.5rem;
319
325
  padding: 0;
320
326
  border: 1px solid var(--ui-border-default);
321
- border-radius: var(--radius-sm);
327
+ border-radius: var(--ui-radius-sm);
322
328
  background: var(--ui-hover);
323
329
  color: var(--ui-text-secondary);
324
330
  cursor: pointer;
325
- font-size: var(--font-md);
331
+ font-size: var(--ui-font-size-md);
326
332
  flex-shrink: 0;
327
333
 
328
334
  &:hover {
@@ -333,21 +339,21 @@
333
339
  }
334
340
 
335
341
  .hsl-panel-title {
336
- font-size: var(--font-md);
337
- font-weight: var(--font-weight-semibold);
342
+ font-size: var(--ui-font-size-md);
343
+ font-weight: var(--ui-font-weight-semibold);
338
344
  color: var(--ui-text-secondary);
339
345
  }
340
346
 
341
347
  .hsl-hex {
342
- font-size: var(--font-md);
348
+ font-size: var(--ui-font-size-md);
343
349
  color: var(--ui-text-accent);
344
350
  font-family: var(--ui-font-mono);
345
351
  background: none;
346
352
  border: 1px solid transparent;
347
- border-radius: var(--radius-sm);
348
- padding: var(--space-2) var(--space-4);
353
+ border-radius: var(--ui-radius-sm);
354
+ padding: var(--ui-space-2) var(--ui-space-4);
349
355
  cursor: pointer;
350
- transition: all var(--transition-fast);
356
+ transition: all var(--ui-transition-fast);
351
357
  }
352
358
 
353
359
  .hsl-hex:hover {
@@ -356,19 +362,19 @@
356
362
  }
357
363
 
358
364
  .hsl-hex-input {
359
- font-size: var(--font-md);
365
+ font-size: var(--ui-font-size-md);
360
366
  color: var(--ui-text-accent);
361
367
  font-family: var(--ui-font-mono);
362
368
  background: var(--ui-surface-low);
363
369
  border: 1px solid var(--ui-border-strong);
364
- border-radius: var(--radius-sm);
365
- padding: var(--space-2) var(--space-4);
370
+ border-radius: var(--ui-radius-sm);
371
+ padding: var(--ui-space-2) var(--ui-space-4);
366
372
  width: 5.5rem;
367
373
  outline: none;
368
374
  }
369
375
 
370
376
  .hsl-values {
371
- font-size: var(--font-md);
377
+ font-size: var(--ui-font-size-md);
372
378
  color: var(--ui-text-tertiary);
373
379
  font-family: var(--ui-font-mono);
374
380
  }
@@ -376,7 +382,7 @@
376
382
  .hsl-panel-actions {
377
383
  display: flex;
378
384
  align-items: center;
379
- gap: var(--space-6);
385
+ gap: var(--ui-space-6);
380
386
  margin-left: auto;
381
387
  flex-wrap: wrap;
382
388
  }
@@ -384,18 +390,18 @@
384
390
  .hsl-sliders {
385
391
  display: flex;
386
392
  flex-direction: column;
387
- gap: var(--space-6);
393
+ gap: var(--ui-space-6);
388
394
  }
389
395
 
390
396
  .hsl-slider-row {
391
397
  display: flex;
392
398
  align-items: center;
393
- gap: var(--space-8);
399
+ gap: var(--ui-space-8);
394
400
  }
395
401
 
396
402
  .hsl-slider-label {
397
- font-size: var(--font-md);
398
- font-weight: var(--font-weight-semibold);
403
+ font-size: var(--ui-font-size-md);
404
+ font-weight: var(--ui-font-weight-semibold);
399
405
  color: var(--ui-text-tertiary);
400
406
  width: 2.5rem;
401
407
  text-align: right;
@@ -405,7 +411,7 @@
405
411
  .slider-track {
406
412
  position: relative;
407
413
  height: 1.25rem;
408
- border-radius: var(--radius-md);
414
+ border-radius: var(--ui-radius-md);
409
415
  border: 1px solid var(--ui-border-faint);
410
416
  flex: 1;
411
417
  min-width: 6rem;
@@ -421,14 +427,14 @@
421
427
  margin: 0;
422
428
  background: transparent;
423
429
  cursor: pointer;
424
- border-radius: var(--radius-md);
430
+ border-radius: var(--ui-radius-md);
425
431
  }
426
432
 
427
433
  .slider-track input[type="range"]::-webkit-slider-thumb {
428
434
  -webkit-appearance: none;
429
435
  width: 0.5rem;
430
436
  height: 1.25rem;
431
- border-radius: var(--radius-sm);
437
+ border-radius: var(--ui-radius-sm);
432
438
  background: white;
433
439
  border: 2px solid rgba(0, 0, 0, 0.3);
434
440
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
@@ -438,7 +444,7 @@
438
444
  .slider-track input[type="range"]::-moz-range-thumb {
439
445
  width: 0.5rem;
440
446
  height: 1.25rem;
441
- border-radius: var(--radius-sm);
447
+ border-radius: var(--ui-radius-sm);
442
448
  background: white;
443
449
  border: 2px solid rgba(0, 0, 0, 0.3);
444
450
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
@@ -460,7 +466,7 @@
460
466
  }
461
467
 
462
468
  .hsl-slider-input {
463
- font-size: var(--font-md);
469
+ font-size: var(--ui-font-size-md);
464
470
  color: var(--ui-text-primary);
465
471
  font-family: var(--ui-font-mono);
466
472
  width: 2.5rem;
@@ -468,8 +474,8 @@
468
474
  flex-shrink: 0;
469
475
  background: var(--ui-surface-lowest);
470
476
  border: 1px solid var(--ui-border-subtle);
471
- border-radius: var(--radius-sm);
472
- padding: var(--space-2) var(--space-4);
477
+ border-radius: var(--ui-radius-sm);
478
+ padding: var(--ui-space-2) var(--ui-space-4);
473
479
  -moz-appearance: textfield;
474
480
  }
475
481
 
@@ -489,7 +495,7 @@
489
495
  }
490
496
 
491
497
  .hsl-slider-unit {
492
- font-size: var(--font-md);
498
+ font-size: var(--ui-font-size-md);
493
499
  color: var(--ui-text-muted);
494
500
  font-family: var(--ui-font-mono);
495
501
  width: 0.75rem;
@@ -0,0 +1,180 @@
1
+ <script lang="ts">
2
+ import { editorView } from '../lib/editorViewStore';
3
+ import { parentRoute } from '../lib/parentRouteStore';
4
+
5
+ export let condensed = false;
6
+
7
+ // On /components the host page is already the components editor — the
8
+ // overlay's components view would just stack on top of it, so disable the
9
+ // switch. The switcher renders inside the editor iframe, so we read the
10
+ // *parent* route, not this iframe's own route.
11
+ $: componentsDisabled = $parentRoute === '/components';
12
+
13
+ function set(v: 'tokens' | 'components') {
14
+ editorView.set(v);
15
+ }
16
+
17
+ function toggle() {
18
+ if (componentsDisabled) return;
19
+ editorView.update((v) => (v === 'tokens' ? 'components' : 'tokens'));
20
+ }
21
+ </script>
22
+
23
+ {#if condensed}
24
+ <button
25
+ type="button"
26
+ class="compact"
27
+ aria-label={$editorView === 'tokens' ? 'Switch to components' : 'Switch to tokens'}
28
+ title={$editorView === 'tokens' ? 'Tokens (click for components)' : 'Components (click for tokens)'}
29
+ on:click={toggle}
30
+ >
31
+ <i class="fas {$editorView === 'tokens' ? 'fa-palette' : 'fa-cubes'}"></i>
32
+ </button>
33
+ {:else}
34
+ <div class="seg-group">
35
+ <span class="seg-label">Editor</span>
36
+ <div class="seg" role="tablist" aria-label="Editor view">
37
+ <button
38
+ type="button"
39
+ role="tab"
40
+ class="seg-btn"
41
+ class:active={$editorView === 'tokens'}
42
+ aria-selected={$editorView === 'tokens'}
43
+ on:click={() => set('tokens')}
44
+ >
45
+ <span class="radio" aria-hidden="true"></span>
46
+ <span>Tokens</span>
47
+ </button>
48
+ <button
49
+ type="button"
50
+ role="tab"
51
+ class="seg-btn"
52
+ class:active={$editorView === 'components'}
53
+ aria-selected={$editorView === 'components'}
54
+ disabled={componentsDisabled}
55
+ title={componentsDisabled ? 'Already viewing the Components page' : undefined}
56
+ on:click={() => set('components')}
57
+ >
58
+ <span class="radio" aria-hidden="true"></span>
59
+ <span>Components</span>
60
+ </button>
61
+ </div>
62
+ </div>
63
+ {/if}
64
+
65
+ <style>
66
+ .seg-group {
67
+ display: flex;
68
+ flex-direction: column;
69
+ gap: var(--ui-space-4);
70
+ margin: var(--ui-space-12) var(--ui-space-12) var(--ui-space-8);
71
+ }
72
+
73
+ .seg-label {
74
+ font-size: 10px;
75
+ font-weight: var(--ui-font-weight-semibold);
76
+ letter-spacing: 0.08em;
77
+ text-transform: uppercase;
78
+ color: #fff;
79
+ padding-left: var(--ui-space-2);
80
+ }
81
+
82
+ .seg {
83
+ display: flex;
84
+ flex-direction: column;
85
+ gap: 2px;
86
+ padding: 3px;
87
+ background: var(--ui-surface-low);
88
+ border: 1px solid var(--ui-border-faint);
89
+ border-radius: var(--ui-radius-lg);
90
+ /* Fill the sidebar's content area so the box width is fixed by the rail,
91
+ not by which label happens to be active. Buttons inherit this width via
92
+ the default `align-items: stretch` on the column flex. */
93
+ width: 100%;
94
+ box-sizing: border-box;
95
+ }
96
+
97
+ .seg-btn {
98
+ display: flex;
99
+ align-items: center;
100
+ justify-content: flex-start;
101
+ gap: var(--ui-space-8);
102
+ width: 100%;
103
+ height: 28px;
104
+ padding: 0 var(--ui-space-10);
105
+ background: none;
106
+ border: none;
107
+ border-radius: var(--ui-radius-md);
108
+ color: var(--ui-text-tertiary);
109
+ font-family: inherit;
110
+ font-size: var(--ui-font-size-sm);
111
+ font-weight: var(--ui-font-weight-medium);
112
+ text-align: left;
113
+ box-sizing: border-box;
114
+ cursor: pointer;
115
+ transition: background var(--ui-transition-fast), color var(--ui-transition-fast);
116
+ }
117
+
118
+ .radio {
119
+ flex-shrink: 0;
120
+ width: 12px;
121
+ height: 12px;
122
+ border-radius: var(--ui-radius-full);
123
+ border: 1.5px solid var(--ui-text-tertiary);
124
+ background: transparent;
125
+ transition: border-color var(--ui-transition-fast), background var(--ui-transition-fast),
126
+ box-shadow var(--ui-transition-fast);
127
+ }
128
+
129
+ .seg-btn.active .radio {
130
+ border-color: var(--ui-text-primary);
131
+ /* Inner dot via inset shadow keeps the box-model identical to the inactive
132
+ ring — no border-thickness shift between states. */
133
+ box-shadow: inset 0 0 0 2.5px var(--ui-surface-high), inset 0 0 0 6px var(--ui-text-primary);
134
+ }
135
+
136
+ .seg-btn:hover:not(.active) .radio {
137
+ border-color: var(--ui-text-secondary);
138
+ }
139
+
140
+ .seg-btn:hover {
141
+ color: var(--ui-text-secondary);
142
+ }
143
+
144
+ .seg-btn.active {
145
+ background: var(--ui-surface-high);
146
+ color: var(--ui-text-primary);
147
+ box-shadow: 0 1px 0 rgba(255, 255, 255, 0.04);
148
+ }
149
+
150
+ .seg-btn:disabled {
151
+ cursor: not-allowed;
152
+ opacity: 0.4;
153
+ }
154
+
155
+ .seg-btn:disabled:hover {
156
+ color: var(--ui-text-tertiary);
157
+ }
158
+
159
+ .seg-btn:disabled:hover .radio {
160
+ border-color: var(--ui-text-tertiary);
161
+ }
162
+
163
+ .compact {
164
+ display: flex;
165
+ align-items: center;
166
+ justify-content: center;
167
+ width: 48px;
168
+ height: 36px;
169
+ margin: var(--ui-space-8) 0 var(--ui-space-4);
170
+ background: none;
171
+ border: none;
172
+ color: var(--ui-text-primary);
173
+ cursor: pointer;
174
+ transition: background var(--ui-transition-fast);
175
+ }
176
+
177
+ .compact:hover {
178
+ background: var(--ui-hover);
179
+ }
180
+ </style>