@motion-proto/live-tokens 0.96.0 → 0.98.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 (206) hide show
  1. package/.claude/skills/live-tokens-check-compliance/SKILL.md +5 -0
  2. package/.claude/skills/live-tokens-create-component/SKILL.md +4 -3
  3. package/.claude/skills/live-tokens-create-component/references/contract-tests.md +71 -11
  4. package/CHANGELOG.md +309 -0
  5. package/README.md +2 -2
  6. package/bin/check-component.mjs +8 -0
  7. package/bin/check-page.mjs +6 -0
  8. package/bin/cli.mjs +36 -6
  9. package/bin/contractRunner.mjs +142 -17
  10. package/bin/lib/findings.mjs +20 -4
  11. package/bin/rules/a11y.mjs +53 -0
  12. package/bin/set-colors.mjs +1 -0
  13. package/bin/setup-claude.mjs +2 -2
  14. package/dist-plugin/{chunk-A4TBP4MM.js → chunk-SLICH4IH.js} +2 -2
  15. package/dist-plugin/index.cjs +148 -3
  16. package/dist-plugin/index.js +250 -105
  17. package/dist-plugin/setColors/index.cjs +7 -1
  18. package/dist-plugin/setColors/index.d.cts +9 -4
  19. package/dist-plugin/setColors/index.d.ts +9 -4
  20. package/dist-plugin/setColors/index.js +8 -2
  21. package/dist-plugin/setGeometry/index.d.cts +1 -1
  22. package/dist-plugin/setGeometry/index.d.ts +1 -1
  23. package/dist-plugin/setType/index.d.cts +1 -1
  24. package/dist-plugin/setType/index.d.ts +1 -1
  25. package/dist-plugin/{themeTypes-B8_Idrp4.d.cts → themeTypes-BaTQUyac.d.cts} +10 -1
  26. package/dist-plugin/{themeTypes-B8_Idrp4.d.ts → themeTypes-BaTQUyac.d.ts} +10 -1
  27. package/package.json +49 -2
  28. package/src/demo/LabeledSelect.svelte +1 -1
  29. package/src/editor/bootstrap.ts +3 -1
  30. package/src/editor/component-editor/BadgeEditor.svelte +13 -0
  31. package/src/editor/component-editor/ButtonEditor.svelte +33 -2
  32. package/src/editor/component-editor/CalloutEditor.svelte +13 -0
  33. package/src/editor/component-editor/CardEditor.svelte +12 -2
  34. package/src/editor/component-editor/CodeSnippetEditor.svelte +11 -1
  35. package/src/editor/component-editor/CollapsibleSectionEditor.svelte +18 -1
  36. package/src/editor/component-editor/CornerBadgeEditor.svelte +13 -0
  37. package/src/editor/component-editor/DialogEditor.svelte +15 -0
  38. package/src/editor/component-editor/IconButtonEditor.svelte +29 -1
  39. package/src/editor/component-editor/ImageEditor.svelte +20 -9
  40. package/src/editor/component-editor/ImageLightboxEditor.svelte +44 -0
  41. package/src/editor/component-editor/InlineEditActionsEditor.svelte +13 -1
  42. package/src/editor/component-editor/InputEditor.svelte +23 -0
  43. package/src/editor/component-editor/MenuSelectEditor.svelte +27 -1
  44. package/src/editor/component-editor/NotificationEditor.svelte +15 -0
  45. package/src/editor/component-editor/PanelEditor.svelte +1 -1
  46. package/src/editor/component-editor/ProgressBarEditor.svelte +13 -0
  47. package/src/editor/component-editor/RadioButtonEditor.svelte +20 -1
  48. package/src/editor/component-editor/SectionDividerEditor.svelte +41 -13
  49. package/src/editor/component-editor/SegmentedControlEditor.svelte +29 -1
  50. package/src/editor/component-editor/SideNavigationEditor.svelte +40 -1
  51. package/src/editor/component-editor/SlidePagerEditor.svelte +20 -0
  52. package/src/editor/component-editor/SliderEditor.svelte +33 -0
  53. package/src/editor/component-editor/TabBarEditor.svelte +23 -2
  54. package/src/editor/component-editor/TableEditor.svelte +14 -0
  55. package/src/editor/component-editor/ToggleEditor.svelte +17 -0
  56. package/src/editor/component-editor/TooltipEditor.svelte +11 -2
  57. package/src/editor/component-editor/VideoFrameEditor.svelte +8 -0
  58. package/src/editor/component-editor/VideoLightboxEditor.svelte +10 -0
  59. package/src/editor/component-editor/registration.ts +2 -1
  60. package/src/editor/component-editor/registry.ts +69 -27
  61. package/src/editor/component-editor/scaffolding/DemoHeader.svelte +2 -0
  62. package/src/editor/component-editor/scaffolding/StateBlock.svelte +19 -8
  63. package/src/editor/component-editor/scaffolding/TokenLayout.svelte +3 -0
  64. package/src/editor/component-editor/scaffolding/VariantGroup.svelte +70 -10
  65. package/src/editor/component-editor/scaffolding/editorContext.ts +7 -0
  66. package/src/editor/core/a11y/a11yReport.ts +101 -0
  67. package/src/editor/core/a11y/a11yReportTypes.ts +69 -0
  68. package/src/editor/core/a11y/contrastFailures.ts +22 -0
  69. package/src/editor/core/components/contrastPairRegistry.ts +18 -0
  70. package/src/editor/core/palettes/contrast.ts +44 -0
  71. package/src/editor/core/palettes/contrastPairs.ts +79 -0
  72. package/src/editor/core/palettes/resolveColor.ts +77 -0
  73. package/src/editor/core/store/editorPersistence.ts +9 -1
  74. package/src/editor/core/store/editorRenderer.ts +2 -0
  75. package/src/editor/core/store/editorStore.ts +29 -0
  76. package/src/editor/core/store/editorTypes.ts +9 -0
  77. package/src/editor/core/store/editorViewStore.ts +2 -2
  78. package/src/editor/core/store/unsavedEdits.ts +10 -0
  79. package/src/editor/core/themes/buildColors.ts +16 -5
  80. package/src/editor/core/themes/liveStateStream.ts +7 -1
  81. package/src/editor/core/themes/parsers/gradient.ts +5 -2
  82. package/src/editor/core/themes/slices/customColors.ts +226 -0
  83. package/src/editor/core/themes/themeTypes.ts +10 -0
  84. package/src/editor/docs/chapters.ts +1 -0
  85. package/src/editor/docs/content/accessibility.md +362 -0
  86. package/src/editor/docs/content/editing-tokens.md +56 -1
  87. package/src/editor/docs/content.generated.ts +2 -1
  88. package/src/editor/pages/ComponentEditorPage.svelte +10 -1
  89. package/src/editor/pages/EditorShell.svelte +97 -10
  90. package/src/editor/skill-atlas/skillSources.generated.ts +3 -3
  91. package/src/editor/skill-atlas/trees/check-compliance.ts +3 -3
  92. package/src/editor/skill-atlas/trees/create-component.ts +12 -12
  93. package/src/editor/ui/CustomColorReplaceStep.svelte +118 -0
  94. package/src/editor/ui/EditorViewSwitcher.svelte +15 -2
  95. package/src/editor/ui/GradientEditor.svelte +9 -1
  96. package/src/editor/ui/ThemePanel.svelte +4 -4
  97. package/src/editor/ui/UIContrastReadout.svelte +186 -0
  98. package/src/editor/ui/UIInfoPopover.svelte +16 -2
  99. package/src/editor/ui/UIPaletteSelector.svelte +347 -15
  100. package/src/editor/ui/UITokenSelector.svelte +33 -14
  101. package/src/editor/ui/VariablesTab.svelte +3 -0
  102. package/src/editor/ui/a11y/A11yComponentIssues.svelte +103 -0
  103. package/src/editor/ui/a11y/A11yFindingRow.svelte +57 -0
  104. package/src/editor/ui/a11y/A11yIssueRow.svelte +121 -0
  105. package/src/editor/ui/a11y/A11yOverview.svelte +242 -0
  106. package/src/editor/ui/a11y/A11yPanel.svelte +128 -0
  107. package/src/editor/ui/a11y/A11yPropertyMark.svelte +84 -0
  108. package/src/editor/ui/a11y/A11yRailMark.svelte +34 -0
  109. package/src/editor/ui/a11y/AccessibilityTab.svelte +334 -0
  110. package/src/editor/ui/a11y/a11yView.ts +218 -0
  111. package/src/editor/ui/anchorToTrigger.ts +63 -0
  112. package/src/editor/ui/contrastReadout.ts +45 -0
  113. package/src/editor/ui/sections/CustomColorsSection.svelte +254 -0
  114. package/src/live-tokens/data/themes/autumn.json +20 -20
  115. package/src/live-tokens/data/themes/halloween.json +20 -20
  116. package/src/live-tokens/data/themes/midnight-study.json +20 -20
  117. package/src/live-tokens/data/themes/ocean.json +20 -20
  118. package/src/live-tokens/data/themes/royal-velvet.json +20 -20
  119. package/src/live-tokens/data/themes/sketchy.json +20 -20
  120. package/src/live-tokens/data/themes/spring-meadow.json +20 -20
  121. package/src/live-tokens/data/themes/sunset.json +20 -20
  122. package/src/system/components/Badge.svelte +3 -3
  123. package/src/system/components/Button.svelte +9 -3
  124. package/src/system/components/CodeSnippet.svelte +8 -1
  125. package/src/system/components/CornerBadge.svelte +3 -3
  126. package/src/system/components/Dialog.svelte +43 -14
  127. package/src/system/components/IconButton.svelte +1 -1
  128. package/src/system/components/Image.svelte +7 -0
  129. package/src/system/components/ImageLightbox.svelte +26 -26
  130. package/src/system/components/Input.svelte +8 -1
  131. package/src/system/components/MenuSelect.svelte +30 -2
  132. package/src/system/components/Notification.svelte +1 -1
  133. package/src/system/components/ProgressBar.svelte +6 -0
  134. package/src/system/components/RadioButton.svelte +36 -3
  135. package/src/system/components/SegmentedControl.svelte +36 -2
  136. package/src/system/components/SlidePager.svelte +2 -2
  137. package/src/system/components/Slider.svelte +13 -9
  138. package/src/system/components/TabBar.svelte +33 -3
  139. package/src/system/components/Toggle.svelte +2 -2
  140. package/src/system/components/VideoFrame.svelte +1 -1
  141. package/src/system/components/VideoLightbox.svelte +2 -2
  142. package/src/system/internal/focusTrap.ts +35 -0
  143. package/src/testing-js/__aria__/badge.yml +40 -0
  144. package/src/testing-js/__aria__/button.yml +88 -0
  145. package/src/testing-js/__aria__/callout.yml +12 -0
  146. package/src/testing-js/__aria__/card.yml +8 -0
  147. package/src/testing-js/__aria__/codesnippet.yml +21 -0
  148. package/src/testing-js/__aria__/collapsiblesection.yml +23 -0
  149. package/src/testing-js/__aria__/cornerbadge.yml +24 -0
  150. package/src/testing-js/__aria__/dialog.yml +42 -0
  151. package/src/testing-js/__aria__/iconbutton.yml +57 -0
  152. package/src/testing-js/__aria__/image.yml +10 -0
  153. package/src/testing-js/__aria__/imagelightbox.yml +50 -0
  154. package/src/testing-js/__aria__/inlineeditactions.yml +16 -0
  155. package/src/testing-js/__aria__/input.yml +61 -0
  156. package/src/testing-js/__aria__/menuselect.yml +30 -0
  157. package/src/testing-js/__aria__/notification.yml +30 -0
  158. package/src/testing-js/__aria__/panel.yml +2 -0
  159. package/src/testing-js/__aria__/progressbar.yml +2 -0
  160. package/src/testing-js/__aria__/radiobutton.yml +20 -0
  161. package/src/testing-js/__aria__/sectiondivider.yml +9 -0
  162. package/src/testing-js/__aria__/segmentedcontrol.yml +35 -0
  163. package/src/testing-js/__aria__/sidenavigation.yml +304 -0
  164. package/src/testing-js/__aria__/slidepager.yml +72 -0
  165. package/src/testing-js/__aria__/slider.yml +28 -0
  166. package/src/testing-js/__aria__/tabbar.yml +35 -0
  167. package/src/testing-js/__aria__/table.yml +144 -0
  168. package/src/testing-js/__aria__/toggle.yml +12 -0
  169. package/src/testing-js/__aria__/tooltip.yml +2 -0
  170. package/src/testing-js/__aria__/videoframe.yml +6 -0
  171. package/src/testing-js/__aria__/videolightbox.yml +12 -0
  172. package/src/testing-js/{chunk-WIZ6W7UT.js → chunk-3WCLMOM7.js} +2 -2
  173. package/src/testing-js/{chunk-SHBYZUPD.js → chunk-5HNZHIHG.js} +211 -14
  174. package/src/testing-js/chunk-5HNZHIHG.js.map +1 -0
  175. package/src/testing-js/{chunk-NB3NZRBM.js → chunk-7CM5D7PF.js} +5 -1
  176. package/src/testing-js/chunk-7CM5D7PF.js.map +1 -0
  177. package/src/testing-js/chunk-EWSGE27V.js +168 -0
  178. package/src/testing-js/chunk-EWSGE27V.js.map +1 -0
  179. package/src/testing-js/{chunk-GKO27NGN.js → chunk-R54I7YL6.js} +2 -2
  180. package/src/testing-js/{chunk-X6KHEVIG.js → chunk-RWH46IU5.js} +97 -29
  181. package/src/testing-js/chunk-RWH46IU5.js.map +1 -0
  182. package/src/testing-js/chunk-SHLPDNAQ.js +658 -0
  183. package/src/testing-js/chunk-SHLPDNAQ.js.map +1 -0
  184. package/src/testing-js/{chunk-3UKGXCDL.js → chunk-YVVR3GJZ.js} +1 -1
  185. package/src/testing-js/chunk-YVVR3GJZ.js.map +1 -0
  186. package/src/testing-js/component-a11y.contract.js +283 -0
  187. package/src/testing-js/component-a11y.contract.js.map +1 -0
  188. package/src/testing-js/component-alias.contract.js +2 -2
  189. package/src/testing-js/component-behavior.contract.js +2 -2
  190. package/src/testing-js/component-editor.contract.js +6 -5
  191. package/src/testing-js/component-editor.contract.js.map +1 -1
  192. package/src/testing-js/component-render.contract.js +10 -6
  193. package/src/testing-js/component-render.contract.js.map +1 -1
  194. package/src/testing-js/index.d.ts +44 -16
  195. package/src/testing-js/index.js +9 -9
  196. package/src/testing-js/page-compliance.contract.js +163 -18
  197. package/src/testing-js/page-compliance.contract.js.map +1 -1
  198. package/src/testing-js/vitest.js +3 -3
  199. package/template/package.json +9 -0
  200. package/src/editor/ui/keepInViewport.ts +0 -84
  201. package/src/testing-js/chunk-3UKGXCDL.js.map +0 -1
  202. package/src/testing-js/chunk-NB3NZRBM.js.map +0 -1
  203. package/src/testing-js/chunk-SHBYZUPD.js.map +0 -1
  204. package/src/testing-js/chunk-X6KHEVIG.js.map +0 -1
  205. /package/src/testing-js/{chunk-WIZ6W7UT.js.map → chunk-3WCLMOM7.js.map} +0 -0
  206. /package/src/testing-js/{chunk-GKO27NGN.js.map → chunk-R54I7YL6.js.map} +0 -0
@@ -2,66 +2,68 @@ import type { Component } from 'svelte';
2
2
  import type { CatalogueEntry, Token, IntrinsicSpec } from './scaffolding/types';
3
3
  import { registerComponentSchema } from '../core/store/editorStore';
4
4
  import { attachRegistry } from './registration';
5
+ import type { ContrastPair } from '../core/palettes/contrastPairs';
6
+ import { registerContrastPairs } from '../core/components/contrastPairRegistry';
5
7
 
6
8
  export { registerComponent } from './registration';
7
9
 
8
- import BadgeEditor, { allTokens as badgeTokens } from './BadgeEditor.svelte';
10
+ import BadgeEditor, { allTokens as badgeTokens, contrastPairs as badgeContrastPairs } from './BadgeEditor.svelte';
9
11
  import { catalogue as badgeCatalogue } from '../../system/components/Badge.svelte';
10
- import CalloutEditor, { allTokens as calloutTokens } from './CalloutEditor.svelte';
12
+ import CalloutEditor, { allTokens as calloutTokens, contrastPairs as calloutContrastPairs } from './CalloutEditor.svelte';
11
13
  import { catalogue as calloutCatalogue } from '../../system/components/Callout.svelte';
12
- import CornerBadgeEditor, { allTokens as cornerBadgeTokens } from './CornerBadgeEditor.svelte';
14
+ import CornerBadgeEditor, { allTokens as cornerBadgeTokens, contrastPairs as cornerBadgeContrastPairs } from './CornerBadgeEditor.svelte';
13
15
  import { catalogue as cornerBadgeCatalogue } from '../../system/components/CornerBadge.svelte';
14
- import ButtonEditor, { allTokens as buttonTokens } from './ButtonEditor.svelte';
16
+ import ButtonEditor, { allTokens as buttonTokens, intrinsics as buttonIntrinsics, contrastPairs as buttonContrastPairs } from './ButtonEditor.svelte';
15
17
  import { catalogue as buttonCatalogue } from '../../system/components/Button.svelte';
16
- import IconButtonEditor, { allTokens as iconButtonTokens } from './IconButtonEditor.svelte';
18
+ import IconButtonEditor, { allTokens as iconButtonTokens, intrinsics as iconButtonIntrinsics, contrastPairs as iconButtonContrastPairs } from './IconButtonEditor.svelte';
17
19
  import { catalogue as iconButtonCatalogue } from '../../system/components/IconButton.svelte';
18
- import CardEditor, { allTokens as cardTokens, intrinsics as cardIntrinsics } from './CardEditor.svelte';
20
+ import CardEditor, { allTokens as cardTokens, intrinsics as cardIntrinsics, contrastPairs as cardContrastPairs } from './CardEditor.svelte';
19
21
  import { catalogue as cardCatalogue } from '../../system/components/Card.svelte';
20
- import CodeSnippetEditor, { allTokens as codeSnippetTokens } from './CodeSnippetEditor.svelte';
22
+ import CodeSnippetEditor, { allTokens as codeSnippetTokens, contrastPairs as codeSnippetContrastPairs } from './CodeSnippetEditor.svelte';
21
23
  import { catalogue as codeSnippetCatalogue } from '../../system/components/CodeSnippet.svelte';
22
- import CollapsibleSectionEditor, { allTokens as collapsibleSectionTokens } from './CollapsibleSectionEditor.svelte';
24
+ import CollapsibleSectionEditor, { allTokens as collapsibleSectionTokens, contrastPairs as collapsibleSectionContrastPairs } from './CollapsibleSectionEditor.svelte';
23
25
  import { catalogue as collapsibleSectionCatalogue } from '../../system/components/CollapsibleSection.svelte';
24
- import DialogEditor, { allTokens as dialogTokens } from './DialogEditor.svelte';
26
+ import DialogEditor, { allTokens as dialogTokens, contrastPairs as dialogContrastPairs } from './DialogEditor.svelte';
25
27
  import { catalogue as dialogCatalogue } from '../../system/components/Dialog.svelte';
26
28
  import ImageEditor, { allTokens as imageTokens, intrinsics as imageIntrinsics } from './ImageEditor.svelte';
27
29
  import { catalogue as imageCatalogue } from '../../system/components/Image.svelte';
28
- import ImageLightboxEditor, { allTokens as imageLightboxTokens } from './ImageLightboxEditor.svelte';
30
+ import ImageLightboxEditor, { allTokens as imageLightboxTokens, intrinsics as imageLightboxIntrinsics, contrastPairs as imageLightboxContrastPairs } from './ImageLightboxEditor.svelte';
29
31
  import { catalogue as imageLightboxCatalogue } from '../../system/components/ImageLightbox.svelte';
30
- import VideoLightboxEditor, { allTokens as videoLightboxTokens } from './VideoLightboxEditor.svelte';
31
- import VideoFrameEditor, { allTokens as videoFrameTokens } from './VideoFrameEditor.svelte';
32
+ import VideoLightboxEditor, { allTokens as videoLightboxTokens, contrastPairs as videoLightboxContrastPairs } from './VideoLightboxEditor.svelte';
33
+ import VideoFrameEditor, { allTokens as videoFrameTokens, contrastPairs as videoFrameContrastPairs } from './VideoFrameEditor.svelte';
32
34
  import { catalogue as videoFrameCatalogue } from '../../system/components/VideoFrame.svelte';
33
- import SlidePagerEditor, { allTokens as slidePagerTokens } from './SlidePagerEditor.svelte';
35
+ import SlidePagerEditor, { allTokens as slidePagerTokens, contrastPairs as slidePagerContrastPairs } from './SlidePagerEditor.svelte';
34
36
  import { catalogue as slidePagerCatalogue } from '../../system/components/SlidePager.svelte';
35
37
  import { catalogue as videoLightboxCatalogue } from '../../system/components/VideoLightbox.svelte';
36
- import InlineEditActionsEditor, { allTokens as inlineEditActionsTokens } from './InlineEditActionsEditor.svelte';
38
+ import InlineEditActionsEditor, { allTokens as inlineEditActionsTokens, contrastPairs as inlineEditActionsContrastPairs } from './InlineEditActionsEditor.svelte';
37
39
  import { catalogue as inlineEditActionsCatalogue } from '../../system/components/InlineEditActions.svelte';
38
- import InputEditor, { allTokens as inputTokens } from './InputEditor.svelte';
40
+ import InputEditor, { allTokens as inputTokens, contrastPairs as inputContrastPairs } from './InputEditor.svelte';
39
41
  import { catalogue as inputCatalogue } from '../../system/components/Input.svelte';
40
- import MenuSelectEditor, { allTokens as menuSelectTokens } from './MenuSelectEditor.svelte';
42
+ import MenuSelectEditor, { allTokens as menuSelectTokens, intrinsics as menuSelectIntrinsics, contrastPairs as menuSelectContrastPairs } from './MenuSelectEditor.svelte';
41
43
  import { catalogue as menuSelectCatalogue } from '../../system/components/MenuSelect.svelte';
42
- import NotificationEditor, { allTokens as notificationTokens } from './NotificationEditor.svelte';
44
+ import NotificationEditor, { allTokens as notificationTokens, contrastPairs as notificationContrastPairs } from './NotificationEditor.svelte';
43
45
  import { catalogue as notificationCatalogue } from '../../system/components/Notification.svelte';
44
46
  import PanelEditor, { allTokens as panelTokens } from './PanelEditor.svelte';
45
47
  import { catalogue as panelCatalogue } from '../../system/components/Panel.svelte';
46
- import ProgressBarEditor, { allTokens as progressBarTokens } from './ProgressBarEditor.svelte';
48
+ import ProgressBarEditor, { allTokens as progressBarTokens, contrastPairs as progressBarContrastPairs } from './ProgressBarEditor.svelte';
47
49
  import { catalogue as progressBarCatalogue } from '../../system/components/ProgressBar.svelte';
48
- import SliderEditor, { allTokens as sliderTokens } from './SliderEditor.svelte';
50
+ import SliderEditor, { allTokens as sliderTokens, contrastPairs as sliderContrastPairs } from './SliderEditor.svelte';
49
51
  import { catalogue as sliderCatalogue } from '../../system/components/Slider.svelte';
50
- import RadioButtonEditor, { allTokens as radioButtonTokens } from './RadioButtonEditor.svelte';
52
+ import RadioButtonEditor, { allTokens as radioButtonTokens, contrastPairs as radioButtonContrastPairs } from './RadioButtonEditor.svelte';
51
53
  import { catalogue as radioButtonCatalogue } from '../../system/components/RadioButton.svelte';
52
- import SectionDividerEditor, { allTokens as sectionDividerTokens, intrinsics as sectionDividerIntrinsics } from './SectionDividerEditor.svelte';
54
+ import SectionDividerEditor, { allTokens as sectionDividerTokens, intrinsics as sectionDividerIntrinsics, contrastPairs as sectionDividerContrastPairs } from './SectionDividerEditor.svelte';
53
55
  import { catalogue as sectionDividerCatalogue } from '../../system/components/SectionDivider.svelte';
54
- import SegmentedControlEditor, { allTokens as segmentedControlTokens } from './SegmentedControlEditor.svelte';
56
+ import SegmentedControlEditor, { allTokens as segmentedControlTokens, intrinsics as segmentedControlIntrinsics, contrastPairs as segmentedControlContrastPairs } from './SegmentedControlEditor.svelte';
55
57
  import { catalogue as segmentedControlCatalogue } from '../../system/components/SegmentedControl.svelte';
56
- import SideNavigationEditor, { allTokens as sideNavigationTokens } from './SideNavigationEditor.svelte';
58
+ import SideNavigationEditor, { allTokens as sideNavigationTokens, intrinsics as sideNavigationIntrinsics, contrastPairs as sideNavigationContrastPairs } from './SideNavigationEditor.svelte';
57
59
  import { catalogue as sideNavigationCatalogue } from '../../system/components/SideNavigation.svelte';
58
- import TableEditor, { allTokens as tableTokens } from './TableEditor.svelte';
60
+ import TableEditor, { allTokens as tableTokens, contrastPairs as tableContrastPairs } from './TableEditor.svelte';
59
61
  import { catalogue as tableCatalogue } from '../../system/components/Table.svelte';
60
- import TabBarEditor, { allTokens as tabBarTokens } from './TabBarEditor.svelte';
62
+ import TabBarEditor, { allTokens as tabBarTokens, intrinsics as tabBarIntrinsics, contrastPairs as tabBarContrastPairs } from './TabBarEditor.svelte';
61
63
  import { catalogue as tabBarCatalogue } from '../../system/components/TabBar.svelte';
62
- import ToggleEditor, { allTokens as toggleTokens } from './ToggleEditor.svelte';
64
+ import ToggleEditor, { allTokens as toggleTokens, contrastPairs as toggleContrastPairs } from './ToggleEditor.svelte';
63
65
  import { catalogue as toggleCatalogue } from '../../system/components/Toggle.svelte';
64
- import TooltipEditor, { allTokens as tooltipTokens } from './TooltipEditor.svelte';
66
+ import TooltipEditor, { allTokens as tooltipTokens, contrastPairs as tooltipContrastPairs } from './TooltipEditor.svelte';
65
67
  import { catalogue as tooltipCatalogue } from '../../system/components/Tooltip.svelte';
66
68
 
67
69
  /** Internal narrowed union of the first-party component ids. Not exposed publicly. */
@@ -119,6 +121,10 @@ export interface RegistryEntry {
119
121
  most components have none. When present, each spec's per-variant default is
120
122
  pinned to the runtime `:global(:root)` by intrinsicsContract.test. */
121
123
  intrinsics?: IntrinsicSpec[];
124
+ /** Each foreground color and the layers the runtime paints behind it. The
125
+ palette selector reads them to show a contrast readout on the foreground's
126
+ row. contrastContract.test pins them to the schema. */
127
+ contrastPairs?: ContrastPair[];
122
128
  /** What the component is, what to use it for, and what not to use it for.
123
129
  Imported from the runtime file's own `catalogue` export — never copied —
124
130
  so registryContract.test's identity check pins it to that one source. */
@@ -142,6 +148,8 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
142
148
  sourceFile: 'src/system/components/SegmentedControl.svelte',
143
149
  editorComponent: SegmentedControlEditor,
144
150
  schema: segmentedControlTokens,
151
+ intrinsics: segmentedControlIntrinsics,
152
+ contrastPairs: segmentedControlContrastPairs,
145
153
  catalogue: segmentedControlCatalogue,
146
154
  origin: 'system',
147
155
  },
@@ -152,6 +160,8 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
152
160
  sourceFile: 'src/system/components/Button.svelte',
153
161
  editorComponent: ButtonEditor,
154
162
  schema: buttonTokens,
163
+ intrinsics: buttonIntrinsics,
164
+ contrastPairs: buttonContrastPairs,
155
165
  catalogue: buttonCatalogue,
156
166
  origin: 'system',
157
167
  },
@@ -162,6 +172,8 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
162
172
  sourceFile: 'src/system/components/IconButton.svelte',
163
173
  editorComponent: IconButtonEditor,
164
174
  schema: iconButtonTokens,
175
+ intrinsics: iconButtonIntrinsics,
176
+ contrastPairs: iconButtonContrastPairs,
165
177
  catalogue: iconButtonCatalogue,
166
178
  origin: 'system',
167
179
  },
@@ -172,6 +184,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
172
184
  sourceFile: 'src/system/components/Notification.svelte',
173
185
  editorComponent: NotificationEditor,
174
186
  schema: notificationTokens,
187
+ contrastPairs: notificationContrastPairs,
175
188
  catalogue: notificationCatalogue,
176
189
  origin: 'system',
177
190
  },
@@ -182,6 +195,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
182
195
  sourceFile: 'src/system/components/Dialog.svelte',
183
196
  editorComponent: DialogEditor,
184
197
  schema: dialogTokens,
198
+ contrastPairs: dialogContrastPairs,
185
199
  catalogue: dialogCatalogue,
186
200
  origin: 'system',
187
201
  },
@@ -192,6 +206,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
192
206
  sourceFile: 'src/system/components/RadioButton.svelte',
193
207
  editorComponent: RadioButtonEditor,
194
208
  schema: radioButtonTokens,
209
+ contrastPairs: radioButtonContrastPairs,
195
210
  catalogue: radioButtonCatalogue,
196
211
  origin: 'system',
197
212
  },
@@ -203,6 +218,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
203
218
  editorComponent: CardEditor,
204
219
  schema: cardTokens,
205
220
  intrinsics: cardIntrinsics,
221
+ contrastPairs: cardContrastPairs,
206
222
  catalogue: cardCatalogue,
207
223
  origin: 'system',
208
224
  },
@@ -213,6 +229,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
213
229
  sourceFile: 'src/system/components/Badge.svelte',
214
230
  editorComponent: BadgeEditor,
215
231
  schema: badgeTokens,
232
+ contrastPairs: badgeContrastPairs,
216
233
  catalogue: badgeCatalogue,
217
234
  origin: 'system',
218
235
  },
@@ -223,6 +240,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
223
240
  sourceFile: 'src/system/components/Callout.svelte',
224
241
  editorComponent: CalloutEditor,
225
242
  schema: calloutTokens,
243
+ contrastPairs: calloutContrastPairs,
226
244
  catalogue: calloutCatalogue,
227
245
  origin: 'system',
228
246
  },
@@ -233,6 +251,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
233
251
  sourceFile: 'src/system/components/CodeSnippet.svelte',
234
252
  editorComponent: CodeSnippetEditor,
235
253
  schema: codeSnippetTokens,
254
+ contrastPairs: codeSnippetContrastPairs,
236
255
  catalogue: codeSnippetCatalogue,
237
256
  origin: 'system',
238
257
  },
@@ -243,6 +262,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
243
262
  sourceFile: 'src/system/components/CornerBadge.svelte',
244
263
  editorComponent: CornerBadgeEditor,
245
264
  schema: cornerBadgeTokens,
265
+ contrastPairs: cornerBadgeContrastPairs,
246
266
  catalogue: cornerBadgeCatalogue,
247
267
  origin: 'system',
248
268
  },
@@ -264,6 +284,8 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
264
284
  sourceFile: 'src/system/components/ImageLightbox.svelte',
265
285
  editorComponent: ImageLightboxEditor,
266
286
  schema: imageLightboxTokens,
287
+ intrinsics: imageLightboxIntrinsics,
288
+ contrastPairs: imageLightboxContrastPairs,
267
289
  catalogue: imageLightboxCatalogue,
268
290
  origin: 'system',
269
291
  },
@@ -274,6 +296,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
274
296
  sourceFile: 'src/system/components/VideoLightbox.svelte',
275
297
  editorComponent: VideoLightboxEditor,
276
298
  schema: videoLightboxTokens,
299
+ contrastPairs: videoLightboxContrastPairs,
277
300
  catalogue: videoLightboxCatalogue,
278
301
  origin: 'system',
279
302
  },
@@ -284,6 +307,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
284
307
  sourceFile: 'src/system/components/VideoFrame.svelte',
285
308
  editorComponent: VideoFrameEditor,
286
309
  schema: videoFrameTokens,
310
+ contrastPairs: videoFrameContrastPairs,
287
311
  catalogue: videoFrameCatalogue,
288
312
  origin: 'system',
289
313
  },
@@ -294,6 +318,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
294
318
  sourceFile: 'src/system/components/SlidePager.svelte',
295
319
  editorComponent: SlidePagerEditor,
296
320
  schema: slidePagerTokens,
321
+ contrastPairs: slidePagerContrastPairs,
297
322
  catalogue: slidePagerCatalogue,
298
323
  origin: 'system',
299
324
  },
@@ -304,6 +329,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
304
329
  sourceFile: 'src/system/components/InlineEditActions.svelte',
305
330
  editorComponent: InlineEditActionsEditor,
306
331
  schema: inlineEditActionsTokens,
332
+ contrastPairs: inlineEditActionsContrastPairs,
307
333
  catalogue: inlineEditActionsCatalogue,
308
334
  origin: 'system',
309
335
  },
@@ -314,6 +340,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
314
340
  sourceFile: 'src/system/components/Input.svelte',
315
341
  editorComponent: InputEditor,
316
342
  schema: inputTokens,
343
+ contrastPairs: inputContrastPairs,
317
344
  catalogue: inputCatalogue,
318
345
  origin: 'system',
319
346
  },
@@ -324,6 +351,8 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
324
351
  sourceFile: 'src/system/components/MenuSelect.svelte',
325
352
  editorComponent: MenuSelectEditor,
326
353
  schema: menuSelectTokens,
354
+ intrinsics: menuSelectIntrinsics,
355
+ contrastPairs: menuSelectContrastPairs,
327
356
  catalogue: menuSelectCatalogue,
328
357
  origin: 'system',
329
358
  },
@@ -345,6 +374,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
345
374
  editorComponent: SectionDividerEditor,
346
375
  schema: sectionDividerTokens,
347
376
  intrinsics: sectionDividerIntrinsics,
377
+ contrastPairs: sectionDividerContrastPairs,
348
378
  catalogue: sectionDividerCatalogue,
349
379
  origin: 'system',
350
380
  },
@@ -355,6 +385,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
355
385
  sourceFile: 'src/system/components/CollapsibleSection.svelte',
356
386
  editorComponent: CollapsibleSectionEditor,
357
387
  schema: collapsibleSectionTokens,
388
+ contrastPairs: collapsibleSectionContrastPairs,
358
389
  catalogue: collapsibleSectionCatalogue,
359
390
  origin: 'system',
360
391
  },
@@ -365,6 +396,8 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
365
396
  sourceFile: 'src/system/components/SideNavigation.svelte',
366
397
  editorComponent: SideNavigationEditor,
367
398
  schema: sideNavigationTokens,
399
+ intrinsics: sideNavigationIntrinsics,
400
+ contrastPairs: sideNavigationContrastPairs,
368
401
  catalogue: sideNavigationCatalogue,
369
402
  origin: 'system',
370
403
  },
@@ -375,6 +408,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
375
408
  sourceFile: 'src/system/components/Table.svelte',
376
409
  editorComponent: TableEditor,
377
410
  schema: tableTokens,
411
+ contrastPairs: tableContrastPairs,
378
412
  catalogue: tableCatalogue,
379
413
  origin: 'system',
380
414
  },
@@ -385,6 +419,8 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
385
419
  sourceFile: 'src/system/components/TabBar.svelte',
386
420
  editorComponent: TabBarEditor,
387
421
  schema: tabBarTokens,
422
+ intrinsics: tabBarIntrinsics,
423
+ contrastPairs: tabBarContrastPairs,
388
424
  catalogue: tabBarCatalogue,
389
425
  origin: 'system',
390
426
  },
@@ -395,6 +431,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
395
431
  sourceFile: 'src/system/components/Toggle.svelte',
396
432
  editorComponent: ToggleEditor,
397
433
  schema: toggleTokens,
434
+ contrastPairs: toggleContrastPairs,
398
435
  catalogue: toggleCatalogue,
399
436
  origin: 'system',
400
437
  },
@@ -405,6 +442,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
405
442
  sourceFile: 'src/system/components/Tooltip.svelte',
406
443
  editorComponent: TooltipEditor,
407
444
  schema: tooltipTokens,
445
+ contrastPairs: tooltipContrastPairs,
408
446
  catalogue: tooltipCatalogue,
409
447
  origin: 'system',
410
448
  },
@@ -415,6 +453,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
415
453
  sourceFile: 'src/system/components/ProgressBar.svelte',
416
454
  editorComponent: ProgressBarEditor,
417
455
  schema: progressBarTokens,
456
+ contrastPairs: progressBarContrastPairs,
418
457
  catalogue: progressBarCatalogue,
419
458
  origin: 'system',
420
459
  },
@@ -425,6 +464,7 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
425
464
  sourceFile: 'src/system/components/Slider.svelte',
426
465
  editorComponent: SliderEditor,
427
466
  schema: sliderTokens,
467
+ contrastPairs: sliderContrastPairs,
428
468
  catalogue: sliderCatalogue,
429
469
  origin: 'system',
430
470
  },
@@ -445,6 +485,7 @@ function addCustomComponent(entry: RegisterComponentEntry): void {
445
485
  const stored: RegistryEntry = { ...entry, origin: 'custom' };
446
486
  customRegistry.set(entry.id, stored);
447
487
  registerComponentSchema(entry.id, entry.schema);
488
+ registerContrastPairs(entry.id, entry.contrastPairs ?? []);
448
489
  }
449
490
 
450
491
  /**
@@ -487,6 +528,7 @@ export function getComponentIds(): ReadonlyArray<string> {
487
528
  // editor instance mounts.
488
529
  for (const entry of Object.values(builtInRegistry)) {
489
530
  registerComponentSchema(entry.id, entry.schema);
531
+ registerContrastPairs(entry.id, entry.contrastPairs ?? []);
490
532
  }
491
533
  attachRegistry(addCustomComponent);
492
534
 
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import ComponentFileManager from './ComponentFileManager.svelte';
3
+ import A11yPanel from '../../ui/a11y/A11yPanel.svelte';
3
4
 
4
5
  interface Props {
5
6
  component: string;
@@ -17,6 +18,7 @@
17
18
  </script>
18
19
 
19
20
  <ComponentFileManager {component} {title} {resetVariables} />
21
+ <A11yPanel {component} />
20
22
 
21
23
  {#if description}
22
24
  <p class="demo-description">{@html description}</p>
@@ -12,6 +12,7 @@
12
12
  import TokenLayout from './TokenLayout.svelte';
13
13
  import TypeEditor from './TypeEditor.svelte';
14
14
  import type { Token, TypeGroupConfig } from './types';
15
+ import A11yPropertyMark from '../../ui/a11y/A11yPropertyMark.svelte';
15
16
 
16
17
 
17
18
 
@@ -22,6 +23,8 @@
22
23
  checked: boolean;
23
24
  label?: string;
24
25
  onchange: (checked: boolean) => void;
26
+ /** The intrinsic variables the toggle writes, which mark it and let the panel reach it. */
27
+ variables?: string[];
25
28
  }
26
29
 
27
30
  interface Props {
@@ -111,14 +114,17 @@
111
114
  <div class="element-heading-row">
112
115
  <h4 class="element-heading">{section.element}</h4>
113
116
  {#if toggle}
114
- <label class="element-show-toggle">
115
- <input
116
- type="checkbox"
117
- checked={toggle.checked}
118
- onchange={(e) => toggle.onchange((e.currentTarget as HTMLInputElement).checked)}
119
- />
120
- <span>{toggle.label ?? `Show ${section.element}`}</span>
121
- </label>
117
+ <span class="element-show-toggle-host" data-token-variables={toggle.variables?.join(' ')}>
118
+ <label class="element-show-toggle">
119
+ <input
120
+ type="checkbox"
121
+ checked={toggle.checked}
122
+ onchange={(e) => toggle.onchange((e.currentTarget as HTMLInputElement).checked)}
123
+ />
124
+ <span>{toggle.label ?? `Show ${section.element}`}</span>
125
+ </label>
126
+ {#if toggle.variables}<A11yPropertyMark variables={toggle.variables} />{/if}
127
+ </span>
122
128
  {/if}
123
129
  </div>
124
130
  {@render elementExtras?.(section.element)}
@@ -331,6 +337,11 @@
331
337
  /* Show toggle next to the section heading — drives preview visibility for
332
338
  the element. Property rows below stay visible so users can still tune the
333
339
  hidden element's tokens. */
340
+ .element-show-toggle-host {
341
+ display: inline-flex;
342
+ align-items: center;
343
+ }
344
+
334
345
  .element-show-toggle {
335
346
  display: inline-flex;
336
347
  align-items: center;
@@ -439,6 +439,9 @@
439
439
  grid-template-columns: max-content var(--token-selector-w) minmax(0, 1fr);
440
440
  column-gap: var(--ui-space-6);
441
441
  }
442
+ /* A contrast readout wraps onto a line of its own below the value name. */
443
+ .token-grid :global(.ui-ts-meta) { flex-wrap: wrap; }
444
+ .token-grid :global(.ui-ts-meta > .ui-ts-meta-text) { flex-basis: 100%; }
442
445
  }
443
446
 
444
447
  .zone-divider {
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { writable } from 'svelte/store';
3
- import type { Snippet } from 'svelte';
3
+ import { tick, untrack, type Snippet } from 'svelte';
4
4
  import TokenLayout from './TokenLayout.svelte';
5
5
  import StateBlock from './StateBlock.svelte';
6
6
  import CopyFromMenu from './CopyFromMenu.svelte';
@@ -10,7 +10,7 @@
10
10
  import { getDeclaredValue } from '../../core/palettes/tokenRegistry';
11
11
  import type { CssVarRef } from '../../core/store/editorTypes';
12
12
  import { cssStringToRef, refToCss } from '../../core/store/cssVarRef';
13
- import { getEditorContext } from './editorContext';
13
+ import { getEditorContext, type RevealRequest } from './editorContext';
14
14
  import { setSketchScope } from '../../core/sketch/sketchLayer';
15
15
  import { sketchEnabled, sketchSettings } from '../../core/sketch/sketchStore';
16
16
  import type { Token, TypeGroupConfig } from './types';
@@ -45,7 +45,7 @@
45
45
  live with the canvas rather than in a separate config block above. */
46
46
  canvasToolbarExtras?: Snippet;
47
47
  /** Per-element Show toggles, forwarded to StateBlock. Keyed by element name. */
48
- elementToggles?: Record<string, { checked: boolean; label?: string; onchange: (checked: boolean) => void }>;
48
+ elementToggles?: Record<string, { checked: boolean; label?: string; onchange: (checked: boolean) => void; variables?: string[] }>;
49
49
  /** Explicit order for element-grouped sections, forwarded to StateBlock. */
50
50
  elementOrder?: string[];
51
51
  /** Per-element extras snippet, forwarded to StateBlock. Receives the
@@ -101,6 +101,7 @@
101
101
  const focusedStateStore = editorCtx?.focusedState ?? writable<string | null>(null);
102
102
  const variantsStore = editorCtx?.variants ?? writable<{ value: string; label: string }[]>([]);
103
103
  const preserveColorFamilyStore = editorCtx?.preserveColorFamily ?? writable(false);
104
+ const revealVariableStore = editorCtx?.revealVariable ?? writable<RevealRequest | null>(null);
104
105
  let linkedOrder = $derived($linkedOrderStore ?? undefined);
105
106
 
106
107
  let activeTab: string = $state('');
@@ -372,6 +373,64 @@
372
373
  let amIFocused = $derived($focusedVariantStore === name);
373
374
  let shouldRender = $derived(!inFocusMode || amIFocused);
374
375
  let showVariantTabs = $derived(inFocusMode && $variantsStore.length >= 2);
376
+
377
+ const holds = (list: Token[] | undefined, variable: string) =>
378
+ !!list?.some((t) => !t.hidden && (t.variable === variable || t.mergeVariables?.includes(variable)));
379
+ const typeGroupHolds = (groups: TypeGroupConfig[] | undefined, variable: string) =>
380
+ !!groups?.some((tg) => TYPE_PROPS.some((prop) => tg[prop] === variable));
381
+
382
+ /** The tab whose rows include `variable`: '' for a group without tabs, null when it holds none. */
383
+ function tabHolding(variable: string): string | null {
384
+ if (!states) return holds(tokens, variable) ? '' : null;
385
+ return stateNames.find((s) => holds(states[s], variable) || typeGroupHolds(typeGroups[s], variable)) ?? null;
386
+ }
387
+
388
+ let searchedTab: string | null = $state(null);
389
+ let searchStage = $state<HTMLDivElement | undefined>(undefined);
390
+
391
+ /** The tab whose editor-authored rows include `variable`. Those rows come
392
+ from snippets, which show nothing of their variables until they render,
393
+ so each tab renders them out of sight in turn. */
394
+ async function snippetTabHolding(variable: string): Promise<string | null> {
395
+ const escaped = CSS.escape(variable);
396
+ const selector = `[data-token-variable="${escaped}"], [data-token-variables~="${escaped}"]`;
397
+ try {
398
+ for (const tab of stateNames) {
399
+ searchedTab = tab;
400
+ await tick();
401
+ if (searchStage?.querySelector(selector)) return tab;
402
+ }
403
+ return null;
404
+ } finally {
405
+ searchedTab = null;
406
+ }
407
+ }
408
+
409
+ function openTab(tab: string) {
410
+ if (inFocusMode) focusedVariantStore.set(name);
411
+ if (tab) {
412
+ activeTab = tab;
413
+ focusedStateStore.set(tab);
414
+ }
415
+ }
416
+
417
+ // Untracked so a later edit, which rebuilds `states`, never pulls the tabs back to an old request.
418
+ $effect(() => {
419
+ const request = $revealVariableStore;
420
+ if (!request) return;
421
+ untrack(() => {
422
+ const tab = tabHolding(request.variable);
423
+ if (tab !== null) {
424
+ openTab(tab);
425
+ return;
426
+ }
427
+ if (!shouldRender || !states || !(stateActions || extraPropertyRowsTop || extraPropertyRows)) return;
428
+ request.searches.push(snippetTabHolding(request.variable).then((found) => {
429
+ if (found !== null) openTab(found);
430
+ }));
431
+ });
432
+ });
433
+
375
434
  // Mirror state-tab clicks to the shared store so linked-block + chart track them.
376
435
  $effect(() => {
377
436
  if (amIFocused && activeTab && stateNames.includes(activeTab) && $focusedStateStore !== activeTab) {
@@ -484,6 +543,14 @@
484
543
  {/if}
485
544
  </div>
486
545
 
546
+ {#if searchedTab !== null}
547
+ <div hidden inert bind:this={searchStage}>
548
+ {@render stateActions?.(searchedTab)}
549
+ {@render extraPropertyRowsTop?.(searchedTab)}
550
+ {@render extraPropertyRows?.(searchedTab)}
551
+ </div>
552
+ {/if}
553
+
487
554
  {#if activeTab && states[activeTab]}
488
555
  {@const stateName = activeTab}
489
556
  {@render compositeControls?.(stateName)}
@@ -818,13 +885,6 @@
818
885
  color: var(--ui-text-tertiary);
819
886
  }
820
887
 
821
- /* Anchor dropdown to the trigger's right edge; the toolbar sits flush against
822
- the editor's right gutter, so a left-anchored dropdown would clip. */
823
- .canvas-toolbar :global(.ui-ts-dropdown) {
824
- left: auto;
825
- right: 0;
826
- }
827
-
828
888
  .variant-tabs {
829
889
  display: inline-flex;
830
890
  flex-wrap: wrap;
@@ -5,6 +5,9 @@ const KEY = Symbol('editor-context');
5
5
 
6
6
  export type VariantOption = { value: string; label: string };
7
7
 
8
+ /** A request to show a variable's row. A group that has to search its tabs adds the search, so the requester can wait for it. */
9
+ export type RevealRequest = { variable: string; searches: Promise<void>[] };
10
+
8
11
  export type EditorContext = {
9
12
  /** Per-variable rank for TokenLayout row alignment; null when no linked block. */
10
13
  linkedOrder: Readable<Map<string, number> | null>;
@@ -20,6 +23,8 @@ export type EditorContext = {
20
23
  on context (not local to CopyFromMenu) so it survives VariantGroup remounts
21
24
  when the user changes which variant is focused. */
22
25
  preserveColorFamily: Writable<boolean>;
26
+ /** Rebuilt per request. The VariantGroup holding the variable focuses its variant and opens its tab. */
27
+ revealVariable: Writable<RevealRequest | null>;
23
28
  };
24
29
 
25
30
  /** Mutable handle for ComponentEditorBase. */
@@ -35,6 +40,7 @@ export function createEditorContext(): EditorContextInternal {
35
40
  const focusedState = writable<string | null>(null);
36
41
  const hoveredLinkedVariable = writable<string | null>(null);
37
42
  const preserveColorFamily = writable<boolean>(false);
43
+ const revealVariable = writable<RevealRequest | null>(null);
38
44
  const ctx: EditorContextInternal = {
39
45
  linkedOrder: _linkedOrder,
40
46
  focusedVariant,
@@ -42,6 +48,7 @@ export function createEditorContext(): EditorContextInternal {
42
48
  focusedState,
43
49
  hoveredLinkedVariable,
44
50
  preserveColorFamily,
51
+ revealVariable,
45
52
  _linkedOrder,
46
53
  _variants,
47
54
  };