@motion-proto/live-tokens 0.6.2 → 0.8.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 (232) hide show
  1. package/README.md +14 -13
  2. package/dist-plugin/index.cjs +854 -226
  3. package/dist-plugin/index.d.cts +2 -1
  4. package/dist-plugin/index.d.ts +2 -1
  5. package/dist-plugin/index.js +852 -225
  6. package/package.json +26 -40
  7. package/src/{styles → app}/site.css +1 -1
  8. package/src/{component-editor → editor/component-editor}/BadgeEditor.svelte +8 -82
  9. package/src/{component-editor → editor/component-editor}/CalloutEditor.svelte +4 -4
  10. package/src/{component-editor → editor/component-editor}/CardEditor.svelte +28 -76
  11. package/src/{component-editor → editor/component-editor}/CollapsibleSectionEditor.svelte +37 -30
  12. package/src/{component-editor → editor/component-editor}/CornerBadgeEditor.svelte +31 -93
  13. package/src/{component-editor → editor/component-editor}/DialogEditor.svelte +60 -57
  14. package/src/editor/component-editor/ImageEditor.svelte +30 -0
  15. package/src/{component-editor → editor/component-editor}/InlineEditActionsEditor.svelte +6 -4
  16. package/src/editor/component-editor/MenuSelectEditor.svelte +160 -0
  17. package/src/{component-editor → editor/component-editor}/NotificationEditor.svelte +67 -38
  18. package/src/{component-editor → editor/component-editor}/ProgressBarEditor.svelte +5 -4
  19. package/src/{component-editor → editor/component-editor}/RadioButtonEditor.svelte +3 -3
  20. package/src/editor/component-editor/SectionDividerEditor.svelte +565 -0
  21. package/src/{component-editor → editor/component-editor}/SegmentedControlEditor.svelte +2 -2
  22. package/src/{component-editor → editor/component-editor}/StandardButtonsEditor.svelte +29 -21
  23. package/src/{component-editor → editor/component-editor}/TabBarEditor.svelte +9 -14
  24. package/src/{component-editor → editor/component-editor}/TableEditor.svelte +9 -18
  25. package/src/{component-editor → editor/component-editor}/TooltipEditor.svelte +11 -47
  26. package/src/editor/component-editor/editors.d.ts +10 -0
  27. package/src/{component-editor → editor/component-editor}/registry.ts +28 -18
  28. package/src/{component-editor → editor/component-editor}/scaffolding/AngleDial.svelte +54 -15
  29. package/src/{component-editor → editor/component-editor}/scaffolding/ComponentEditorBase.svelte +3 -51
  30. package/src/{component-editor → editor/component-editor}/scaffolding/ComponentFileManager.svelte +151 -424
  31. package/src/{component-editor → editor/component-editor}/scaffolding/ComponentFileMenu.svelte +18 -170
  32. package/src/{component-editor → editor/component-editor}/scaffolding/ComponentsTab.svelte +2 -2
  33. package/src/{component-editor → editor/component-editor}/scaffolding/CopyFromMenu.svelte +44 -4
  34. package/src/{component-editor → editor/component-editor}/scaffolding/FieldsetWrapper.svelte +1 -1
  35. package/src/{component-editor → editor/component-editor}/scaffolding/LinkageChart.svelte +6 -6
  36. package/src/{component-editor → editor/component-editor}/scaffolding/LinkedBlock.svelte +6 -12
  37. package/src/editor/component-editor/scaffolding/NonStylableConfig.svelte +38 -0
  38. package/src/editor/component-editor/scaffolding/RadialShapePad.svelte +483 -0
  39. package/src/{component-editor → editor/component-editor}/scaffolding/SaveAsDialog.svelte +66 -12
  40. package/src/editor/component-editor/scaffolding/ShadowBackdrop.svelte +85 -0
  41. package/src/editor/component-editor/scaffolding/ShadowBackdropControls.svelte +132 -0
  42. package/src/editor/component-editor/scaffolding/StateBlock.svelte +345 -0
  43. package/src/{component-editor → editor/component-editor}/scaffolding/TokenLayout.svelte +17 -12
  44. package/src/{component-editor → editor/component-editor}/scaffolding/TypeEditor.svelte +13 -1
  45. package/src/editor/component-editor/scaffolding/VariantGroup.svelte +858 -0
  46. package/src/{component-editor → editor/component-editor}/scaffolding/buildTypeGroupTokens.ts +1 -0
  47. package/src/{component-editor → editor/component-editor}/scaffolding/editorContext.ts +19 -9
  48. package/src/{component-editor → editor/component-editor}/scaffolding/linkedBlock.ts +2 -2
  49. package/src/{component-editor → editor/component-editor}/scaffolding/types.ts +25 -0
  50. package/src/{lib → editor/core/components}/componentConfigKeys.ts +8 -0
  51. package/src/{lib → editor/core/components}/componentConfigService.ts +3 -3
  52. package/src/{lib → editor/core/components}/componentPersist.ts +11 -9
  53. package/src/editor/core/flashStatus.ts +30 -0
  54. package/src/{lib → editor/core/fonts}/fontLoader.ts +2 -2
  55. package/src/{lib → editor/core/fonts}/fontMigration.ts +4 -4
  56. package/src/{lib → editor/core/fonts}/fontParse.ts +1 -1
  57. package/src/editor/core/manifests/manifestService.ts +171 -0
  58. package/src/editor/core/palettes/familySwap.ts +99 -0
  59. package/src/{lib → editor/core/palettes}/paletteDerivation.ts +71 -2
  60. package/src/{lib → editor/core/palettes}/tokenRegistry.ts +9 -6
  61. package/src/editor/core/productionPulse.ts +37 -0
  62. package/src/{lib → editor/core/routing}/router.ts +1 -1
  63. package/src/{lib/files/versionedFileResource.ts → editor/core/storage/files/versionedFileResourceClient.ts} +8 -1
  64. package/src/{lib → editor/core/store}/editorCore.ts +24 -8
  65. package/src/{lib → editor/core/store}/editorPersistence.ts +3 -3
  66. package/src/{lib → editor/core/store}/editorRenderer.ts +2 -2
  67. package/src/{lib → editor/core/store}/editorStore.ts +222 -28
  68. package/src/{lib → editor/core/store}/editorTypes.ts +56 -13
  69. package/src/editor/core/store/gradientSource.ts +192 -0
  70. package/src/editor/core/themes/migrations/2026-05-19-collapsiblesection-drop-frame-surface.ts +28 -0
  71. package/src/editor/core/themes/migrations/2026-05-19-sectiondivider-rich-gradient.ts +35 -0
  72. package/src/editor/core/themes/migrations/2026-05-20-sectiondivider-slim-variants.ts +82 -0
  73. package/src/editor/core/themes/migrations/2026-05-21-sectiondivider-spacing-to-padding.ts +24 -0
  74. package/src/editor/core/themes/migrations/2026-05-22-sectiondivider-intrinsics-to-css.ts +81 -0
  75. package/src/{lib → editor/core/themes}/migrations/index.ts +10 -0
  76. package/src/{lib → editor/core/themes}/slices/columns.ts +2 -2
  77. package/src/{lib → editor/core/themes}/slices/components.ts +20 -6
  78. package/src/{lib → editor/core/themes}/slices/fonts.ts +1 -1
  79. package/src/{lib → editor/core/themes}/slices/gradients.ts +89 -14
  80. package/src/{lib → editor/core/themes}/slices/overlays.ts +1 -1
  81. package/src/{lib → editor/core/themes}/slices/palettes.ts +1 -1
  82. package/src/{lib → editor/core/themes}/slices/shadows.ts +3 -3
  83. package/src/{lib → editor/core/themes}/themeInit.ts +8 -8
  84. package/src/{lib → editor/core/themes}/themeService.ts +6 -6
  85. package/src/{lib → editor/core/themes}/themeTypes.ts +67 -8
  86. package/src/editor/index.ts +69 -0
  87. package/src/{lib → editor/overlay}/ColumnsOverlay.svelte +0 -1
  88. package/src/{lib → editor/overlay}/LiveEditorOverlay.svelte +80 -129
  89. package/src/{lib → editor/overlay}/columnsOverlay.ts +2 -2
  90. package/src/{pages → editor/pages}/ComponentEditorPage.svelte +12 -12
  91. package/src/{pages → editor/pages}/Editor.svelte +4 -4
  92. package/src/{pages → editor/pages}/EditorShell.svelte +18 -36
  93. package/src/{styles → editor/styles}/ui-editor.css +43 -22
  94. package/src/{styles → editor/styles}/ui-form-controls.css +23 -24
  95. package/src/{ui → editor/ui}/BezierCurveEditor.svelte +119 -68
  96. package/src/{ui → editor/ui}/ColorEditPanel.svelte +13 -13
  97. package/src/{ui → editor/ui}/EditorViewSwitcher.svelte +7 -6
  98. package/src/editor/ui/FileLoadList.svelte +367 -0
  99. package/src/editor/ui/FilePill.svelte +80 -0
  100. package/src/editor/ui/FontStackEditor.svelte +499 -0
  101. package/src/editor/ui/GradientEditor.svelte +690 -0
  102. package/src/{ui → editor/ui}/GradientStopPicker.svelte +12 -4
  103. package/src/editor/ui/ManifestFileManager.svelte +438 -0
  104. package/src/{ui → editor/ui}/PaletteEditor.svelte +180 -673
  105. package/src/editor/ui/ProjectFontsSection.svelte +638 -0
  106. package/src/{ui → editor/ui}/SurfacesTab.svelte +3 -3
  107. package/src/{ui → editor/ui}/TextTab.svelte +3 -3
  108. package/src/editor/ui/ThemeFileManager.svelte +783 -0
  109. package/src/{ui → editor/ui}/UICopyPopover.svelte +4 -4
  110. package/src/{ui → editor/ui}/UIFontFamilySelector.svelte +6 -7
  111. package/src/{ui → editor/ui}/UIFontSizeSelector.svelte +4 -1
  112. package/src/editor/ui/UIInfoPopover.svelte +243 -0
  113. package/src/editor/ui/UILetterSpacingSelector.svelte +65 -0
  114. package/src/{ui → editor/ui}/UILineHeightSelector.svelte +5 -5
  115. package/src/{ui → editor/ui}/UILinkToggle.svelte +2 -2
  116. package/src/{ui → editor/ui}/UIPaddingSelector.svelte +6 -6
  117. package/src/{ui → editor/ui}/UIPaletteSelector.svelte +57 -30
  118. package/src/editor/ui/UIPillButton.svelte +168 -0
  119. package/src/{ui → editor/ui}/UIRadio.svelte +2 -2
  120. package/src/{ui → editor/ui}/UIRelinkConfirmPopover.svelte +4 -4
  121. package/src/editor/ui/UISegmentedControl.svelte +114 -0
  122. package/src/editor/ui/UISquareButton.svelte +172 -0
  123. package/src/{ui → editor/ui}/UITokenSelector.svelte +14 -11
  124. package/src/{ui → editor/ui}/UIVariantSelector.svelte +1 -1
  125. package/src/{ui → editor/ui}/VariablesTab.svelte +46 -17
  126. package/src/{ui → editor/ui}/palette/GradientStopEditor.svelte +13 -13
  127. package/src/{ui → editor/ui}/palette/OverridesPanel.svelte +24 -47
  128. package/src/{ui → editor/ui}/palette/PaletteBase.svelte +11 -8
  129. package/src/{ui → editor/ui}/palette/paletteEditorState.ts +1 -1
  130. package/src/editor/ui/palette/paletteMath.ts +275 -0
  131. package/src/{ui → editor/ui}/sections/ColumnsSection.svelte +137 -18
  132. package/src/{ui → editor/ui}/sections/GradientsSection.svelte +8 -8
  133. package/src/{ui → editor/ui}/sections/OverlaysSection.svelte +18 -18
  134. package/src/{ui → editor/ui}/sections/ShadowsSection.svelte +23 -23
  135. package/src/{ui → editor/ui}/sections/TokenScaleTable.svelte +3 -3
  136. package/src/{components → system/components}/Badge.svelte +0 -36
  137. package/src/{components → system/components}/Button.svelte +2 -2
  138. package/src/{components → system/components}/Card.svelte +34 -60
  139. package/src/{components → system/components}/CollapsibleSection.svelte +25 -2
  140. package/src/{components → system/components}/CornerBadge.svelte +8 -24
  141. package/src/{components → system/components}/Dialog.svelte +1 -1
  142. package/src/system/components/FloatingTokenTags.css +275 -0
  143. package/src/system/components/FloatingTokenTags.svelte +543 -0
  144. package/src/{components → system/components}/InlineEditActions.svelte +6 -4
  145. package/src/system/components/MenuSelect.svelte +229 -0
  146. package/src/{components → system/components}/Notification.svelte +8 -1
  147. package/src/{components → system/components}/ProgressBar.svelte +29 -11
  148. package/src/system/components/SectionDivider.svelte +560 -0
  149. package/src/{components → system/components}/SegmentedControl.svelte +49 -43
  150. package/src/{components → system/components}/TabBar.svelte +81 -65
  151. package/src/{components → system/components}/Table.svelte +17 -3
  152. package/src/{components → system/components}/Tooltip.svelte +6 -4
  153. package/src/system/styles/CONVENTIONS.md +178 -0
  154. package/src/system/styles/fonts.css +20 -0
  155. package/src/system/styles/tokens.css +601 -0
  156. package/src/system/styles/tokens.generated.css +544 -0
  157. package/src/component-editor/ImageEditor.svelte +0 -74
  158. package/src/component-editor/SectionDividerEditor.svelte +0 -265
  159. package/src/component-editor/scaffolding/DividerEditor.svelte +0 -94
  160. package/src/component-editor/scaffolding/GradientCard.svelte +0 -296
  161. package/src/component-editor/scaffolding/NonStylableConfig.svelte +0 -62
  162. package/src/component-editor/scaffolding/ShadowBackdrop.svelte +0 -37
  163. package/src/component-editor/scaffolding/ShadowBackdropControls.svelte +0 -61
  164. package/src/component-editor/scaffolding/StateBlock.svelte +0 -132
  165. package/src/component-editor/scaffolding/VariantGroup.svelte +0 -310
  166. package/src/components/SectionDivider.svelte +0 -483
  167. package/src/data/google-fonts.json +0 -75
  168. package/src/lib/index.ts +0 -68
  169. package/src/lib/presetService.ts +0 -214
  170. package/src/lib/productionPulse.ts +0 -32
  171. package/src/styles/fonts.css +0 -30
  172. package/src/styles/tokens.css +0 -1324
  173. package/src/ui/FontStackEditor.svelte +0 -361
  174. package/src/ui/GradientEditor.svelte +0 -470
  175. package/src/ui/PresetFileManager.svelte +0 -1116
  176. package/src/ui/ProjectFontsSection.svelte +0 -645
  177. package/src/ui/ThemeFileManager.svelte +0 -1020
  178. package/src/ui/UnsavedComponentsDialog.svelte +0 -315
  179. /package/src/{component-editor → editor/component-editor}/index.ts +0 -0
  180. /package/src/{component-editor → editor/component-editor}/scaffolding/DemoHeader.svelte +0 -0
  181. /package/src/{component-editor → editor/component-editor}/scaffolding/componentSectionType.ts +0 -0
  182. /package/src/{component-editor → editor/component-editor}/scaffolding/componentSources.ts +0 -0
  183. /package/src/{component-editor → editor/component-editor}/scaffolding/defaultSections.ts +0 -0
  184. /package/src/{component-editor → editor/component-editor}/scaffolding/siblings.ts +0 -0
  185. /package/src/{lib → editor/core}/cssVarSync.ts +0 -0
  186. /package/src/{lib → editor/core/palettes}/oklch.ts +0 -0
  187. /package/src/{lib → editor/core/routing}/navLinkTypes.ts +0 -0
  188. /package/src/{lib → editor/core/routing}/parentRouteStore.ts +0 -0
  189. /package/src/{lib → editor/core/storage}/storage.ts +0 -0
  190. /package/src/{lib → editor/core/store}/editorConfig.ts +0 -0
  191. /package/src/{lib → editor/core/store}/editorConfigStore.ts +0 -0
  192. /package/src/{lib → editor/core/store}/editorKeybindings.ts +0 -0
  193. /package/src/{lib → editor/core/store}/editorViewStore.ts +0 -0
  194. /package/src/{lib → editor/core/themes}/migrations/2026-04-24-component-prefix-and-suffix-renames.ts +0 -0
  195. /package/src/{lib → editor/core/themes}/migrations/2026-04-24-legacy-keys-and-bg-to-canvas.ts +0 -0
  196. /package/src/{lib → editor/core/themes}/migrations/2026-04-27-segmentedcontrol-disabled-flatten.ts +0 -0
  197. /package/src/{lib → editor/core/themes}/migrations/2026-05-08-collapsiblesection-frame-and-cleanup.ts +0 -0
  198. /package/src/{lib → editor/core/themes}/migrations/2026-05-08-collapsiblesection-variant-namespace.ts +0 -0
  199. /package/src/{lib → editor/core/themes}/migrations/2026-05-10-sectiondivider-gradient-stops.ts +0 -0
  200. /package/src/{lib → editor/core/themes}/migrations/2026-05-13-primary-to-brand.ts +0 -0
  201. /package/src/{lib → editor/core/themes}/parsers/globalRootBlock.ts +0 -0
  202. /package/src/{lib → editor/core/themes}/slices/domainVars.ts +0 -0
  203. /package/src/{lib → editor/overlay}/overlayState.ts +0 -0
  204. /package/src/{pages → editor/pages}/ComponentEditorPage.svelte.d.ts +0 -0
  205. /package/src/{pages → editor/pages}/Editor.svelte.d.ts +0 -0
  206. /package/src/{ui → editor/ui}/Toggle.svelte +0 -0
  207. /package/src/{ui → editor/ui}/UIDialog.svelte +0 -0
  208. /package/src/{ui → editor/ui}/UIFontWeightSelector.svelte +0 -0
  209. /package/src/{ui → editor/ui}/UIOptionItem.svelte +0 -0
  210. /package/src/{ui → editor/ui}/UIOptionList.svelte +0 -0
  211. /package/src/{ui → editor/ui}/UIRadioGroup.svelte +0 -0
  212. /package/src/{lib → editor/ui}/copyPopover.ts +0 -0
  213. /package/src/{ui → editor/ui}/curveEngine.ts +0 -0
  214. /package/src/{ui → editor/ui}/index.ts +0 -0
  215. /package/src/{ui → editor/ui}/keepInViewport.ts +0 -0
  216. /package/src/{ui → editor/ui}/palette/ScaleCurveEditor.svelte +0 -0
  217. /package/src/{lib → editor/ui}/scrollSection.ts +0 -0
  218. /package/src/{ui → editor/ui}/sections/tokenScales.ts +0 -0
  219. /package/src/{ui → editor/ui}/variantScales.ts +0 -0
  220. /package/src/{assets → system/assets}/newspaper.webp +0 -0
  221. /package/src/{assets → system/assets}/offering.webp +0 -0
  222. /package/src/{components → system/components}/Callout.svelte +0 -0
  223. /package/src/{components → system/components}/Image.svelte +0 -0
  224. /package/src/{components → system/components}/RadioButton.svelte +0 -0
  225. /package/src/{components → system/components}/types.ts +0 -0
  226. /package/src/{styles → system/styles}/_padding.scss +0 -0
  227. /package/src/{styles → system/styles}/fonts/Fraunces/Fraunces-italic-latin-ext.woff2 +0 -0
  228. /package/src/{styles → system/styles}/fonts/Fraunces/Fraunces-italic-latin.woff2 +0 -0
  229. /package/src/{styles → system/styles}/fonts/Fraunces/Fraunces-roman-latin-ext.woff2 +0 -0
  230. /package/src/{styles → system/styles}/fonts/Fraunces/Fraunces-roman-latin.woff2 +0 -0
  231. /package/src/{styles → system/styles}/fonts/Manrope/Manrope-latin-ext.woff2 +0 -0
  232. /package/src/{styles → system/styles}/fonts/Manrope/Manrope-latin.woff2 +0 -0
@@ -3,10 +3,10 @@
3
3
 
4
4
  import { slide } from 'svelte/transition';
5
5
  import { cubicOut, cubicIn } from 'svelte/easing';
6
- import { resolveAliasChain } from '../lib/tokenRegistry';
7
- import { editorState } from '../lib/editorStore';
8
- import { formatGradientStops } from '../lib/slices/gradients';
9
- import type { GradientToken } from '../lib/editorTypes';
6
+ import { resolveAliasChain } from '../core/palettes/tokenRegistry';
7
+ import { editorState } from '../core/store/editorStore';
8
+ import { formatGradientStops } from '../core/themes/slices/gradients';
9
+ import type { GradientToken } from '../core/store/editorTypes';
10
10
  import UITokenSelector from './UITokenSelector.svelte';
11
11
 
12
12
  /** Honor prefers-reduced-motion: `t()` zeroes durations when the OS asks for
@@ -36,6 +36,11 @@
36
36
  canBeLinked?: boolean;
37
37
  disabled?: boolean;
38
38
  selectionsLocked?: boolean;
39
+ /** When set, restrict picker family choices to this family (one of the
40
+ * entries in the `families` list). Other families render but are
41
+ * rendered disabled and not clickable. Out-of-family already-set
42
+ * choices still surface in the trigger meta. */
43
+ familyFilter?: string | null;
39
44
  onchange?: () => void;
40
45
  }
41
46
 
@@ -45,6 +50,7 @@
45
50
  canBeLinked = false,
46
51
  disabled = false,
47
52
  selectionsLocked = false,
53
+ familyFilter = null,
48
54
  onchange,
49
55
  }: Props = $props();
50
56
 
@@ -97,7 +103,7 @@
97
103
  const borderStepKeys = borderSteps.map(s => s.key);
98
104
  const textStepKeys = textSteps.map(s => s.key);
99
105
 
100
- const familiesWithText = ['neutral', 'canvas', 'brand', 'accent', 'special', 'success', 'warning', 'info', 'danger'];
106
+ const familiesWithText = ['neutral', 'alternate', 'canvas', 'brand', 'accent', 'special', 'success', 'warning', 'info', 'danger'];
101
107
 
102
108
  const allCategories: { id: Category; label: string }[] = [
103
109
  { id: 'palette', label: 'Palette' },
@@ -405,6 +411,7 @@
405
411
  }
406
412
 
407
413
  function selectFamily(name: string) {
414
+ if (familyFilter && name !== familyFilter) return;
408
415
  selectedFamily = name;
409
416
  if (name === chosenFamily && chosenCategory) {
410
417
  selectedTab = chosenCategory;
@@ -543,14 +550,23 @@
543
550
  <span class="family-label">None</span>
544
551
  </button>
545
552
  {#each families as fam}
546
- <button class="family-item" class:active={!chosenNone && chosenFamily === fam.name} onclick={() => selectFamily(fam.name)}>
553
+ {@const outOfFamily = familyFilter !== null && fam.name !== familyFilter}
554
+ <button
555
+ class="family-item"
556
+ class:active={!chosenNone && chosenFamily === fam.name}
557
+ class:out-of-family={outOfFamily}
558
+ disabled={outOfFamily}
559
+ onclick={() => selectFamily(fam.name)}
560
+ >
547
561
  <div class="family-swatches">
548
562
  <div class="mini-swatch" style="background: var(--color-{fam.name}-300);"></div>
549
563
  <div class="mini-swatch" style="background: var(--color-{fam.name}-500);"></div>
550
564
  <div class="mini-swatch" style="background: var(--color-{fam.name}-700);"></div>
551
565
  </div>
552
566
  <span class="family-label">{fam.label}</span>
553
- <i class="fas fa-chevron-right family-arrow"></i>
567
+ {#if !outOfFamily}
568
+ <i class="fas fa-chevron-right family-arrow"></i>
569
+ {/if}
554
570
  </button>
555
571
  {/each}
556
572
  {#if gradientsAllowed && gradientTokens.length > 0}
@@ -698,11 +714,11 @@
698
714
  align-self: stretch;
699
715
  flex: 1;
700
716
  border-radius: var(--ui-radius-sm);
701
- border: 1px solid var(--ui-border-faint);
702
- background-image: linear-gradient(45deg, var(--ui-border-subtle) 25%, transparent 25%),
703
- linear-gradient(-45deg, var(--ui-border-subtle) 25%, transparent 25%),
704
- linear-gradient(45deg, transparent 75%, var(--ui-border-subtle) 75%),
705
- linear-gradient(-45deg, transparent 75%, var(--ui-border-subtle) 75%);
717
+ border: 1px solid var(--ui-border-low);
718
+ background-image: linear-gradient(45deg, var(--ui-border-low) 25%, transparent 25%),
719
+ linear-gradient(-45deg, var(--ui-border-low) 25%, transparent 25%),
720
+ linear-gradient(45deg, transparent 75%, var(--ui-border-low) 75%),
721
+ linear-gradient(-45deg, transparent 75%, var(--ui-border-low) 75%);
706
722
  background-size: 8px 8px;
707
723
  background-position: 0 0, 0 4px, 4px -4px, -4px 0;
708
724
  overflow: hidden;
@@ -718,7 +734,7 @@
718
734
  align-items: center;
719
735
  gap: var(--ui-space-6);
720
736
  padding: var(--ui-space-6) var(--ui-space-8);
721
- border-bottom: 1px solid var(--ui-border-faint);
737
+ border-bottom: 1px solid var(--ui-border-low);
722
738
  }
723
739
 
724
740
  .opacity-control.hidden {
@@ -736,7 +752,7 @@
736
752
  height: 4px;
737
753
  -webkit-appearance: none;
738
754
  appearance: none;
739
- background: var(--ui-border-default);
755
+ background: var(--ui-border);
740
756
  border-radius: 2px;
741
757
  outline: none;
742
758
  cursor: pointer;
@@ -755,7 +771,7 @@
755
771
  width: 3rem;
756
772
  padding: var(--ui-space-2) var(--ui-space-4);
757
773
  background: var(--ui-surface-lowest);
758
- border: 1px solid var(--ui-border-subtle);
774
+ border: 1px solid var(--ui-border-low);
759
775
  border-radius: var(--ui-radius-sm);
760
776
  color: var(--ui-text-primary);
761
777
  font-size: var(--ui-font-size-xs);
@@ -784,7 +800,7 @@
784
800
  padding: var(--ui-space-8) var(--ui-space-10);
785
801
  background: none;
786
802
  border: none;
787
- border-bottom: 1px solid var(--ui-border-faint);
803
+ border-bottom: 1px solid var(--ui-border-low);
788
804
  color: var(--ui-text-secondary);
789
805
  font-size: var(--ui-font-size-sm);
790
806
  font-weight: var(--ui-font-weight-medium);
@@ -802,7 +818,7 @@
802
818
 
803
819
  .tab-bar {
804
820
  display: flex;
805
- border-bottom: 1px solid var(--ui-border-faint);
821
+ border-bottom: 1px solid var(--ui-border-low);
806
822
  }
807
823
 
808
824
  .tab-btn {
@@ -825,7 +841,7 @@
825
841
  }
826
842
 
827
843
  .tab-btn.assigned {
828
- border-color: var(--ui-border-default);
844
+ border-color: var(--ui-border);
829
845
  }
830
846
 
831
847
  .tab-btn.selected {
@@ -862,6 +878,18 @@
862
878
  box-shadow: inset 3px 0 0 var(--ui-text-accent);
863
879
  }
864
880
 
881
+ /* Family is filtered out by `familyFilter`. Greyed and unselectable so
882
+ the picker scopes new picks to the variant's family while keeping the
883
+ full palette visible (it isn't gone, it just isn't this gradient's
884
+ business). Pointer cursor is suppressed to match :disabled. */
885
+ .family-item.out-of-family {
886
+ opacity: 0.32;
887
+ cursor: not-allowed;
888
+ }
889
+ .family-item.out-of-family:hover {
890
+ background: none;
891
+ }
892
+
865
893
  .family-item.active .family-label {
866
894
  color: var(--ui-text-accent);
867
895
  }
@@ -881,7 +909,7 @@
881
909
  width: 2.5rem;
882
910
  height: 0.75rem;
883
911
  border-radius: 2px;
884
- border: 1px solid var(--ui-border-subtle);
912
+ border: 1px solid var(--ui-border-low);
885
913
  position: relative;
886
914
  overflow: hidden;
887
915
  }
@@ -890,7 +918,7 @@
890
918
  width: 2.5rem;
891
919
  height: 0.75rem;
892
920
  border-radius: 2px;
893
- border: 1px solid var(--ui-border-subtle);
921
+ border: 1px solid var(--ui-border-low);
894
922
  }
895
923
 
896
924
  .family-divider {
@@ -900,8 +928,7 @@
900
928
  font-family: var(--ui-font-mono);
901
929
  color: var(--ui-text-tertiary);
902
930
  text-transform: uppercase;
903
- letter-spacing: 0.04em;
904
- border-top: 1px solid var(--ui-border-faint);
931
+ border-top: 1px solid var(--ui-border-low);
905
932
  }
906
933
 
907
934
  .none-swatch::after {
@@ -915,8 +942,8 @@
915
942
  -45deg,
916
943
  transparent,
917
944
  transparent 3px,
918
- var(--ui-border-subtle) 3px,
919
- var(--ui-border-subtle) 4px
945
+ var(--ui-border-low) 3px,
946
+ var(--ui-border-low) 4px
920
947
  );
921
948
  }
922
949
 
@@ -954,7 +981,7 @@
954
981
 
955
982
  .step-item:hover {
956
983
  background: var(--ui-hover);
957
- border-color: var(--ui-border-default);
984
+ border-color: var(--ui-border);
958
985
  }
959
986
 
960
987
  .step-item.active {
@@ -973,7 +1000,7 @@
973
1000
  width: 2rem;
974
1001
  height: 1.5rem;
975
1002
  border-radius: var(--ui-radius-sm);
976
- border: 1px solid var(--ui-border-faint);
1003
+ border: 1px solid var(--ui-border-low);
977
1004
  }
978
1005
 
979
1006
  .step-label {
@@ -1020,7 +1047,7 @@
1020
1047
 
1021
1048
  .orientation-reset.active {
1022
1049
  color: var(--ui-link-broken, var(--ui-text-secondary));
1023
- border-color: var(--ui-border-subtle);
1050
+ border-color: var(--ui-border-low);
1024
1051
  }
1025
1052
 
1026
1053
  .orientation-reset:hover:not(:disabled) {
@@ -1055,7 +1082,7 @@
1055
1082
  justify-content: center;
1056
1083
  padding: 0;
1057
1084
  background: var(--ui-surface-lowest);
1058
- border: 1px solid var(--ui-border-subtle);
1085
+ border: 1px solid var(--ui-border-low);
1059
1086
  border-radius: var(--ui-radius-sm);
1060
1087
  color: var(--ui-text-secondary);
1061
1088
  font-size: 0.875rem;
@@ -1066,7 +1093,7 @@
1066
1093
 
1067
1094
  .dir-btn:hover {
1068
1095
  background: var(--ui-hover);
1069
- border-color: var(--ui-border-default);
1096
+ border-color: var(--ui-border);
1070
1097
  color: var(--ui-text-primary);
1071
1098
  }
1072
1099
 
@@ -1086,7 +1113,7 @@
1086
1113
  width: 3rem;
1087
1114
  padding: var(--ui-space-2) var(--ui-space-4);
1088
1115
  background: var(--ui-surface-lowest);
1089
- border: 1px solid var(--ui-border-subtle);
1116
+ border: 1px solid var(--ui-border-low);
1090
1117
  border-radius: var(--ui-radius-sm);
1091
1118
  color: var(--ui-text-primary);
1092
1119
  font-size: var(--ui-font-size-xs);
@@ -0,0 +1,168 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface Props {
5
+ variant?: 'primary' | 'default' | 'secondary' | 'outline';
6
+ size?: 'default' | 'compact';
7
+ icon?: string;
8
+ href?: string;
9
+ target?: string;
10
+ disabled?: boolean;
11
+ title?: string;
12
+ type?: 'button' | 'submit' | 'reset';
13
+ onclick?: (e: MouseEvent) => void;
14
+ children?: Snippet;
15
+ }
16
+
17
+ let {
18
+ variant = 'default',
19
+ size = 'default',
20
+ icon,
21
+ href,
22
+ target,
23
+ disabled = false,
24
+ title,
25
+ type = 'button',
26
+ onclick,
27
+ children,
28
+ }: Props = $props();
29
+ </script>
30
+
31
+ {#if href}
32
+ <a
33
+ class="ui-pill ui-pill-{variant} ui-pill-{size}"
34
+ {href}
35
+ {target}
36
+ {title}
37
+ {onclick}
38
+ rel={target === '_blank' ? 'noopener noreferrer' : undefined}
39
+ aria-disabled={disabled ? 'true' : undefined}
40
+ >
41
+ {#if icon}<i class="fas {icon}" aria-hidden="true"></i>{/if}
42
+ {#if children}<span class="ui-pill-label">{@render children()}</span>{/if}
43
+ </a>
44
+ {:else}
45
+ <button
46
+ class="ui-pill ui-pill-{variant} ui-pill-{size}"
47
+ {type}
48
+ {disabled}
49
+ {title}
50
+ {onclick}
51
+ >
52
+ {#if icon}<i class="fas {icon}" aria-hidden="true"></i>{/if}
53
+ {#if children}<span class="ui-pill-label">{@render children()}</span>{/if}
54
+ </button>
55
+ {/if}
56
+
57
+ <style>
58
+ .ui-pill {
59
+ display: inline-flex;
60
+ align-items: center;
61
+ gap: var(--ui-space-6, 6px);
62
+ max-width: 100%;
63
+ min-width: 0;
64
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.15) 0%, rgba(255, 255, 255, 0.25) 100%);
65
+ border: 1px solid rgba(255, 255, 255, 0.5);
66
+ color: var(--ui-text-primary, #fff);
67
+ font-family: inherit;
68
+ font-size: var(--ui-font-size-md, 16px);
69
+ font-weight: var(--ui-font-weight-medium, 500);
70
+ line-height: 1;
71
+ padding: var(--ui-space-6, 6px) var(--ui-space-16, 16px);
72
+ border-radius: var(--ui-radius-full, 9999px);
73
+ cursor: pointer;
74
+ text-decoration: none;
75
+ transition:
76
+ background var(--ui-transition-fast, 120ms ease),
77
+ border-color var(--ui-transition-fast, 120ms ease);
78
+ }
79
+
80
+ .ui-pill-label {
81
+ min-width: 0;
82
+ overflow: hidden;
83
+ white-space: nowrap;
84
+ text-overflow: ellipsis;
85
+ }
86
+
87
+ .ui-pill:hover:not(:disabled):not([aria-disabled='true']) {
88
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.25) 0%, rgba(255, 255, 255, 0.45) 100%);
89
+ border-color: rgba(255, 255, 255, 0.75);
90
+ }
91
+
92
+ .ui-pill:focus-visible {
93
+ outline: none;
94
+ border-color: rgba(255, 255, 255, 0.9);
95
+ box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.18);
96
+ }
97
+
98
+ .ui-pill:disabled,
99
+ .ui-pill[aria-disabled='true'] {
100
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.06) 0%, rgba(255, 255, 255, 0.10) 100%);
101
+ border-color: rgba(255, 255, 255, 0.22);
102
+ color: var(--ui-text-muted, #4d4d4d);
103
+ cursor: not-allowed;
104
+ pointer-events: none;
105
+ }
106
+ .ui-pill:disabled i,
107
+ .ui-pill[aria-disabled='true'] i {
108
+ color: rgba(255, 255, 255, 0.28);
109
+ }
110
+
111
+ .ui-pill-primary:disabled,
112
+ .ui-pill-primary[aria-disabled='true'] {
113
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.07) 0%, rgba(255, 255, 255, 0.03) 100%);
114
+ border-color: rgba(255, 255, 255, 0.24);
115
+ }
116
+
117
+ .ui-pill-secondary:disabled,
118
+ .ui-pill-secondary[aria-disabled='true'] {
119
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.03) 0%, rgba(255, 255, 255, 0.01) 100%);
120
+ border-color: rgba(255, 255, 255, 0.14);
121
+ }
122
+
123
+ .ui-pill i {
124
+ font-size: var(--ui-font-size-xs, 12px);
125
+ color: rgba(255, 255, 255, 0.65);
126
+ }
127
+
128
+ /* Variant: primary — heavier gradient + brighter border for CTAs */
129
+ .ui-pill-primary {
130
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.18) 0%, rgba(255, 255, 255, 0.08) 100%);
131
+ border-color: rgba(255, 255, 255, 0.55);
132
+ }
133
+ .ui-pill-primary:hover:not(:disabled):not([aria-disabled='true']) {
134
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.26) 0%, rgba(255, 255, 255, 0.12) 100%);
135
+ border-color: rgba(255, 255, 255, 0.7);
136
+ }
137
+
138
+ /* Variant: secondary — lighter, for low-emphasis actions */
139
+ .ui-pill-secondary {
140
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.06) 0%, rgba(255, 255, 255, 0.02) 100%);
141
+ border-color: rgba(255, 255, 255, 0.30);
142
+ }
143
+ .ui-pill-secondary:hover:not(:disabled):not([aria-disabled='true']) {
144
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.12) 0%, rgba(255, 255, 255, 0.05) 100%);
145
+ border-color: rgba(255, 255, 255, 0.5);
146
+ }
147
+
148
+ /* Variant: outline — transparent fill, just a border; subtle fill on hover */
149
+ .ui-pill-outline {
150
+ background: none;
151
+ border-color: rgba(255, 255, 255, 0.4);
152
+ }
153
+ .ui-pill-outline:hover:not(:disabled):not([aria-disabled='true']) {
154
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.16) 0%, rgba(255, 255, 255, 0.08) 100%);
155
+ border-color: rgba(255, 255, 255, 0.65);
156
+ }
157
+ .ui-pill-outline:disabled,
158
+ .ui-pill-outline[aria-disabled='true'] {
159
+ background: none;
160
+ border-color: rgba(255, 255, 255, 0.18);
161
+ }
162
+
163
+ /* Size: compact — for header bars / chrome rails */
164
+ .ui-pill-compact {
165
+ font-size: var(--ui-font-size-sm, 14px);
166
+ padding: var(--ui-space-2, 2px) var(--ui-space-12, 12px);
167
+ }
168
+ </style>
@@ -1,6 +1,6 @@
1
1
  <!--
2
2
  Custom-styled radio that matches the editor's selection language: a quiet ring
3
- in the unselected state (--ui-border-strong stroke, soft black inner fill) and
3
+ in the unselected state (--ui-border-higher stroke, soft black inner fill) and
4
4
  the highlight amber when selected (ring + dot, transparent inside).
5
5
 
6
6
  Usage:
@@ -50,7 +50,7 @@
50
50
  flex-shrink: 0;
51
51
  width: 14px;
52
52
  height: 14px;
53
- border: 1.5px solid var(--ui-border-strong);
53
+ border: 1.5px solid var(--ui-border-higher);
54
54
  border-radius: 50%;
55
55
  background: rgba(0, 0, 0, 0.3);
56
56
  cursor: pointer;
@@ -120,7 +120,7 @@
120
120
  top: calc(100% + var(--ui-space-4));
121
121
  right: 0;
122
122
  background: var(--ui-surface-higher);
123
- border: 1px solid var(--ui-border-medium);
123
+ border: 1px solid var(--ui-border-high);
124
124
  border-radius: var(--ui-radius-md);
125
125
  box-shadow: var(--ui-shadow-lg);
126
126
  z-index: 20;
@@ -138,7 +138,7 @@
138
138
  }
139
139
 
140
140
  .ui-relink-header {
141
- border-bottom: 1px solid var(--ui-border-faint);
141
+ border-bottom: 1px solid var(--ui-border-low);
142
142
  padding-bottom: var(--ui-space-6);
143
143
  }
144
144
 
@@ -205,7 +205,7 @@
205
205
  justify-content: flex-end;
206
206
  gap: var(--ui-space-6);
207
207
  padding-top: var(--ui-space-4);
208
- border-top: 1px solid var(--ui-border-faint);
208
+ border-top: 1px solid var(--ui-border-low);
209
209
  }
210
210
 
211
211
  .ui-relink-btn {
@@ -219,7 +219,7 @@
219
219
 
220
220
  .ui-relink-btn-cancel {
221
221
  background: transparent;
222
- border: 1px solid var(--ui-border-default);
222
+ border: 1px solid var(--ui-border);
223
223
  color: var(--ui-text-secondary);
224
224
  }
225
225
 
@@ -0,0 +1,114 @@
1
+ <script lang="ts" generics="V extends string">
2
+ interface Option {
3
+ value: V;
4
+ label: string;
5
+ icon?: string;
6
+ title?: string;
7
+ }
8
+
9
+ interface Props {
10
+ value: V;
11
+ options: ReadonlyArray<Option>;
12
+ /** Native radio group name. Auto-generated per instance if omitted. */
13
+ name?: string;
14
+ ariaLabel?: string;
15
+ onchange?: (value: V) => void;
16
+ }
17
+
18
+ let { value = $bindable(), options, name, ariaLabel, onchange }: Props = $props();
19
+
20
+ // Stable per-instance fallback so internal radios group correctly when no
21
+ // `name` is passed. Not reactive: the group identity shouldn't change.
22
+ const fallbackName = `ui-seg-${Math.random().toString(36).slice(2, 9)}`;
23
+ let groupName = $derived(name ?? fallbackName);
24
+
25
+ function select(v: V) {
26
+ if (v === value) return;
27
+ value = v;
28
+ onchange?.(v);
29
+ }
30
+ </script>
31
+
32
+ <div class="ui-seg" role="radiogroup" aria-label={ariaLabel}>
33
+ {#each options as opt (opt.value)}
34
+ <label
35
+ class="ui-seg-item"
36
+ class:active={value === opt.value}
37
+ title={opt.title}
38
+ >
39
+ <input
40
+ type="radio"
41
+ name={groupName}
42
+ value={opt.value}
43
+ checked={value === opt.value}
44
+ onchange={() => select(opt.value)}
45
+ />
46
+ {#if opt.icon}<i class="fas {opt.icon}" aria-hidden="true"></i>{/if}
47
+ <span>{opt.label}</span>
48
+ </label>
49
+ {/each}
50
+ </div>
51
+
52
+ <style>
53
+ .ui-seg {
54
+ display: inline-flex;
55
+ align-self: flex-start;
56
+ align-items: stretch;
57
+ border: 1px solid rgba(255, 255, 255, 0.5);
58
+ border-radius: var(--ui-radius-xl, 8px);
59
+ overflow: hidden;
60
+ }
61
+
62
+ .ui-seg-item {
63
+ position: relative;
64
+ display: inline-flex;
65
+ align-items: center;
66
+ gap: var(--ui-space-6, 6px);
67
+ padding: var(--ui-space-4, 4px) var(--ui-space-12, 12px);
68
+ color: var(--ui-text-secondary, rgba(255, 255, 255, 0.65));
69
+ font-family: inherit;
70
+ font-size: var(--ui-font-size-sm, 14px);
71
+ font-weight: var(--ui-font-weight-medium, 500);
72
+ line-height: 1.5;
73
+ cursor: pointer;
74
+ user-select: none;
75
+ transition:
76
+ background var(--ui-transition-fast, 120ms ease),
77
+ color var(--ui-transition-fast, 120ms ease);
78
+ }
79
+
80
+ .ui-seg-item + .ui-seg-item {
81
+ border-left: 1px solid rgba(255, 255, 255, 0.18);
82
+ }
83
+
84
+ .ui-seg-item input {
85
+ position: absolute;
86
+ opacity: 0;
87
+ pointer-events: none;
88
+ width: 1px;
89
+ height: 1px;
90
+ margin: 0;
91
+ }
92
+
93
+ .ui-seg-item:hover:not(.active) {
94
+ background: rgba(255, 255, 255, 0.06);
95
+ color: var(--ui-text-primary, #fff);
96
+ }
97
+
98
+ .ui-seg-item.active {
99
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.15) 0%, rgba(255, 255, 255, 0.25) 100%);
100
+ color: var(--ui-text-primary, #fff);
101
+ }
102
+
103
+ .ui-seg-item:has(input:focus-visible) {
104
+ box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.55);
105
+ }
106
+
107
+ .ui-seg-item i {
108
+ font-size: var(--ui-font-size-xs, 12px);
109
+ color: rgba(255, 255, 255, 0.65);
110
+ }
111
+ .ui-seg-item.active i {
112
+ color: rgba(255, 255, 255, 0.85);
113
+ }
114
+ </style>