@astryxdesign/core 0.7.1-canary.ff40b78 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (348) hide show
  1. package/CHANGELOG.md +116 -0
  2. package/dist/Button/Button.d.ts +1 -1
  3. package/dist/Button/Button.d.ts.map +1 -1
  4. package/dist/Button/Button.js +5 -2
  5. package/dist/Calendar/Calendar.d.ts.map +1 -1
  6. package/dist/Calendar/Calendar.js +191 -32
  7. package/dist/Chat/ChatComposerInput.d.ts +9 -0
  8. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  9. package/dist/Chat/ChatComposerInput.js +5 -0
  10. package/dist/Chat/ChatMessage.d.ts +11 -0
  11. package/dist/Chat/ChatMessage.d.ts.map +1 -1
  12. package/dist/Chat/ChatMessage.js +18 -9
  13. package/dist/Chat/useTriggerMenu.d.ts +9 -2
  14. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  15. package/dist/Chat/useTriggerMenu.js +222 -50
  16. package/dist/CodeBlock/CodeBlock.d.ts +10 -1
  17. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  18. package/dist/CodeBlock/CodeBlock.js +158 -38
  19. package/dist/CodeBlock/tokenizer.d.ts +39 -0
  20. package/dist/CodeBlock/tokenizer.d.ts.map +1 -1
  21. package/dist/CodeBlock/tokenizer.js +108 -0
  22. package/dist/CommandPalette/CommandPalette.d.ts +9 -5
  23. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  24. package/dist/CommandPalette/CommandPalette.js +38 -20
  25. package/dist/CommandPalette/CommandPaletteEmpty.d.ts +4 -3
  26. package/dist/CommandPalette/CommandPaletteEmpty.d.ts.map +1 -1
  27. package/dist/CommandPalette/CommandPaletteEmpty.js +4 -3
  28. package/dist/CommandPalette/CommandPaletteInput.d.ts +5 -4
  29. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  30. package/dist/CommandPalette/CommandPaletteInput.js +35 -18
  31. package/dist/CommandPalette/CommandPaletteItem.d.ts +11 -6
  32. package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
  33. package/dist/CommandPalette/CommandPaletteItem.js +8 -9
  34. package/dist/CommandPalette/CommandPaletteList.d.ts +4 -2
  35. package/dist/CommandPalette/CommandPaletteList.d.ts.map +1 -1
  36. package/dist/CommandPalette/CommandPaletteList.js +10 -5
  37. package/dist/ComplexSelector/ComplexSelector.d.ts +8 -5
  38. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  39. package/dist/ComplexSelector/ComplexSelector.js +12 -3
  40. package/dist/ContextMenu/ContextMenu.d.ts +3 -3
  41. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  42. package/dist/ContextMenu/ContextMenu.js +62 -48
  43. package/dist/DateInput/DateInput.js +1 -1
  44. package/dist/DateInput/MonthScroller.d.ts.map +1 -1
  45. package/dist/DateInput/MonthScroller.js +12 -4
  46. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  47. package/dist/DateRangeInput/DateRangeInput.js +12 -2
  48. package/dist/Dialog/Dialog.d.ts +1 -1
  49. package/dist/Dialog/Dialog.d.ts.map +1 -1
  50. package/dist/Dialog/Dialog.js +16 -5
  51. package/dist/Dialog/DialogHeader.d.ts +1 -1
  52. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  53. package/dist/Dialog/DialogHeader.js +7 -7
  54. package/dist/Divider/Divider.d.ts +1 -0
  55. package/dist/Divider/Divider.d.ts.map +1 -1
  56. package/dist/Divider/Divider.js +5 -4
  57. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  58. package/dist/DropdownMenu/DropdownMenu.js +161 -65
  59. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +7 -5
  60. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  61. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +12 -5
  62. package/dist/Field/InputClearButton.d.ts +8 -4
  63. package/dist/Field/InputClearButton.d.ts.map +1 -1
  64. package/dist/Field/InputClearButton.js +23 -7
  65. package/dist/FormLayout/FormLayout.d.ts.map +1 -1
  66. package/dist/FormLayout/FormLayout.js +1 -0
  67. package/dist/Grid/Grid.d.ts +13 -4
  68. package/dist/Grid/Grid.d.ts.map +1 -1
  69. package/dist/Grid/Grid.js +7 -1
  70. package/dist/HoverCard/useHoverCard.d.ts +1 -1
  71. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  72. package/dist/HoverCard/useHoverCard.js +67 -49
  73. package/dist/InputGroup/InputGroup.d.ts +2 -4
  74. package/dist/InputGroup/InputGroup.d.ts.map +1 -1
  75. package/dist/InputGroup/InputGroup.js +2 -4
  76. package/dist/InputGroup/groupStyles.d.ts +10 -2
  77. package/dist/InputGroup/groupStyles.d.ts.map +1 -1
  78. package/dist/InputGroup/groupStyles.js +19 -2
  79. package/dist/Layer/useLayerDismissal.d.ts +9 -9
  80. package/dist/Layer/useLayerDismissal.js +9 -9
  81. package/dist/Markdown/Markdown.d.ts.map +1 -1
  82. package/dist/Markdown/Markdown.js +25 -4
  83. package/dist/MobileNav/MobileNav.d.ts +7 -0
  84. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  85. package/dist/MobileNav/MobileNav.js +45 -2
  86. package/dist/MultiSelector/MultiSelector.d.ts +7 -4
  87. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  88. package/dist/MultiSelector/MultiSelector.js +24 -3
  89. package/dist/NumberInput/NumberInput.js +1 -1
  90. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  91. package/dist/PowerSearch/PowerSearchEditPopover.js +6 -0
  92. package/dist/Resizable/ResizeHandle.d.ts +1 -1
  93. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  94. package/dist/Resizable/ResizeHandle.js +83 -15
  95. package/dist/Resizable/useResizable.d.ts +23 -0
  96. package/dist/Resizable/useResizable.d.ts.map +1 -1
  97. package/dist/Resizable/useResizable.js +78 -0
  98. package/dist/Selector/Selector.d.ts +6 -3
  99. package/dist/Selector/Selector.d.ts.map +1 -1
  100. package/dist/Selector/Selector.js +28 -6
  101. package/dist/SideNav/SideNav.d.ts.map +1 -1
  102. package/dist/SideNav/SideNav.js +10 -2
  103. package/dist/Slider/Slider.d.ts.map +1 -1
  104. package/dist/Slider/Slider.js +18 -7
  105. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  106. package/dist/Tokenizer/Tokenizer.js +16 -4
  107. package/dist/Toolbar/Toolbar.d.ts +2 -1
  108. package/dist/Toolbar/Toolbar.d.ts.map +1 -1
  109. package/dist/Toolbar/Toolbar.js +3 -1
  110. package/dist/TreeList/TreeList.d.ts.map +1 -1
  111. package/dist/TreeList/TreeList.js +6 -3
  112. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  113. package/dist/TreeList/TreeListItem.js +7 -1
  114. package/dist/astryx.css +22 -0
  115. package/dist/hooks/useScrollOverflow.d.ts.map +1 -1
  116. package/dist/hooks/useScrollOverflow.js +55 -12
  117. package/dist/hooks/useTreeFocus.d.ts +21 -0
  118. package/dist/hooks/useTreeFocus.d.ts.map +1 -1
  119. package/dist/hooks/useTreeFocus.js +40 -2
  120. package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
  121. package/dist/i18n/generated-locales/en.generated.js +3 -0
  122. package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
  123. package/dist/i18n/generated-locales/pseudo.generated.js +3 -0
  124. package/dist/reset.a11y.chromium.spec.js +6 -1
  125. package/dist/reset.until-found.a11y.browser.spec.d.ts +2 -0
  126. package/dist/reset.until-found.a11y.browser.spec.d.ts.map +1 -0
  127. package/dist/reset.until-found.a11y.browser.spec.js +71 -0
  128. package/dist/theme/syntax/SyntaxTheme.d.ts.map +1 -1
  129. package/dist/theme/syntax/SyntaxTheme.js +43 -2
  130. package/dist/theme/syntax/defineSyntaxTheme.d.ts +18 -5
  131. package/dist/theme/syntax/defineSyntaxTheme.d.ts.map +1 -1
  132. package/dist/theme/syntax/defineSyntaxTheme.js +38 -9
  133. package/dist/theme/syntax/index.d.ts +1 -1
  134. package/dist/theme/syntax/index.d.ts.map +1 -1
  135. package/dist/theme/syntax/tokens.d.ts +12 -2
  136. package/dist/theme/syntax/tokens.d.ts.map +1 -1
  137. package/dist/theme/syntax/tokens.js +25 -4
  138. package/dist/utils/plainDate.d.ts +12 -0
  139. package/dist/utils/plainDate.d.ts.map +1 -1
  140. package/dist/utils/plainDate.js +63 -10
  141. package/locales/en.json +13 -1
  142. package/locales/pseudo.json +9 -0
  143. package/package.json +4 -4
  144. package/src/AlertDialog/AlertDialog.doc.mjs +6 -0
  145. package/src/AlertDialog/AlertDialog.spec.md +205 -0
  146. package/src/AlertDialog/AlertDialog.test.tsx +3 -14
  147. package/src/AlertDialog/__tests__/AlertDialog.a11y.chromium.spec.ts +115 -0
  148. package/src/AlertDialog/__tests__/AlertDialog.a11y.renders.tsx +52 -0
  149. package/src/AlertDialog/__tests__/AlertDialog.a11y.states.ts +68 -0
  150. package/src/AlertDialog/__tests__/AlertDialog.a11y.test.tsx +144 -0
  151. package/src/Button/Button.test.tsx +37 -0
  152. package/src/Button/Button.tsx +5 -1
  153. package/src/Calendar/Calendar.doc.mjs +234 -60
  154. package/src/Calendar/Calendar.spec.md +209 -0
  155. package/src/Calendar/Calendar.test.tsx +559 -20
  156. package/src/Calendar/Calendar.tsx +258 -41
  157. package/src/Calendar/__tests__/Calendar.a11y.chromium.spec.ts +126 -0
  158. package/src/Calendar/__tests__/Calendar.a11y.known-failures.ts +12 -0
  159. package/src/Calendar/__tests__/Calendar.a11y.renders.tsx +57 -0
  160. package/src/Calendar/__tests__/Calendar.a11y.states.ts +139 -0
  161. package/src/Calendar/__tests__/Calendar.a11y.test.tsx +137 -0
  162. package/src/Carousel/Carousel.test.tsx +54 -71
  163. package/src/Carousel/__tests__/Carousel.a11y.chromium.spec.ts +192 -0
  164. package/src/Carousel/__tests__/Carousel.a11y.known-failures.ts +27 -0
  165. package/src/Carousel/__tests__/Carousel.a11y.renders.tsx +39 -0
  166. package/src/Carousel/__tests__/Carousel.a11y.states.ts +139 -0
  167. package/src/Carousel/__tests__/Carousel.a11y.test.tsx +127 -0
  168. package/src/Chat/ChatComposerInput.doc.mjs +1 -1
  169. package/src/Chat/ChatComposerInput.spec.md +94 -55
  170. package/src/Chat/ChatComposerInput.test.tsx +202 -1
  171. package/src/Chat/ChatComposerInput.tsx +13 -0
  172. package/src/Chat/ChatMessage.doc.mjs +31 -16
  173. package/src/Chat/ChatMessage.spec.md +265 -0
  174. package/src/Chat/ChatMessage.test.tsx +246 -0
  175. package/src/Chat/ChatMessage.tsx +30 -7
  176. package/src/Chat/ChatSystemMessage.spec.md +36 -37
  177. package/src/Chat/ChatSystemMessage.test.tsx +4 -4
  178. package/src/Chat/useTriggerMenu.test.tsx +994 -0
  179. package/src/Chat/useTriggerMenu.tsx +278 -46
  180. package/src/CodeBlock/CodeBlock.doc.mjs +7 -0
  181. package/src/CodeBlock/CodeBlock.spec.md +40 -41
  182. package/src/CodeBlock/CodeBlock.test.tsx +89 -9
  183. package/src/CodeBlock/CodeBlock.tsx +205 -25
  184. package/src/CodeBlock/__tests__/CodeBlockOverflowStop.a11y.chromium.spec.ts +125 -0
  185. package/src/CodeBlock/__tests__/DiffRowPaint.a11y.chromium.spec.ts +93 -0
  186. package/src/CodeBlock/tokenizer.test.ts +112 -0
  187. package/src/CodeBlock/tokenizer.ts +106 -0
  188. package/src/Collapsible/CollapsibleGroup.spec.md +17 -8
  189. package/src/Collapsible/__tests__/CollapsibleGroup.a11y.renders.tsx +45 -0
  190. package/src/Collapsible/__tests__/CollapsibleGroup.a11y.states.ts +139 -0
  191. package/src/Collapsible/__tests__/CollapsibleGroup.a11y.test.tsx +135 -0
  192. package/src/Collapsible/__tests__/CollapsibleGroupAccordion.a11y.chromium.spec.ts +128 -0
  193. package/src/CommandPalette/CommandPalette.doc.mjs +126 -23
  194. package/src/CommandPalette/CommandPalette.spec.md +100 -49
  195. package/src/CommandPalette/CommandPalette.test.tsx +241 -2
  196. package/src/CommandPalette/CommandPalette.tsx +47 -21
  197. package/src/CommandPalette/CommandPaletteEmpty.tsx +4 -3
  198. package/src/CommandPalette/CommandPaletteInput.doc.mjs +61 -4
  199. package/src/CommandPalette/CommandPaletteInput.spec.md +215 -0
  200. package/src/CommandPalette/CommandPaletteInput.test.tsx +375 -51
  201. package/src/CommandPalette/CommandPaletteInput.tsx +74 -21
  202. package/src/CommandPalette/CommandPaletteItem.doc.mjs +73 -22
  203. package/src/CommandPalette/CommandPaletteItem.spec.md +223 -0
  204. package/src/CommandPalette/CommandPaletteItem.test.tsx +200 -5
  205. package/src/CommandPalette/CommandPaletteItem.tsx +16 -11
  206. package/src/CommandPalette/CommandPaletteList.doc.mjs +3 -3
  207. package/src/CommandPalette/CommandPaletteList.spec.md +41 -36
  208. package/src/CommandPalette/CommandPaletteList.test.tsx +80 -0
  209. package/src/CommandPalette/CommandPaletteList.tsx +10 -5
  210. package/src/CommandPalette/__tests__/CommandPalette.a11y.chromium.spec.ts +599 -0
  211. package/src/ComplexSelector/ComplexSelector.doc.mjs +10 -8
  212. package/src/ComplexSelector/ComplexSelector.spec.md +14 -9
  213. package/src/ComplexSelector/ComplexSelector.test.tsx +64 -16
  214. package/src/ComplexSelector/ComplexSelector.tsx +37 -8
  215. package/src/ContextMenu/ContextMenu.doc.mjs +6 -0
  216. package/src/ContextMenu/ContextMenu.spec.md +51 -53
  217. package/src/ContextMenu/ContextMenu.test.tsx +132 -1
  218. package/src/ContextMenu/ContextMenu.tsx +78 -48
  219. package/src/DateInput/DateInput.doc.mjs +52 -0
  220. package/src/DateInput/DateInput.spec.md +27 -15
  221. package/src/DateInput/DateInput.test.tsx +38 -0
  222. package/src/DateInput/DateInput.tsx +1 -1
  223. package/src/DateInput/DateInputTouch.test.tsx +22 -0
  224. package/src/DateInput/MonthScroller.tsx +12 -4
  225. package/src/DateRangeInput/DateRangeInput.test.tsx +49 -0
  226. package/src/DateRangeInput/DateRangeInput.tsx +20 -2
  227. package/src/Dialog/Dialog.test.tsx +27 -1
  228. package/src/Dialog/Dialog.tsx +16 -5
  229. package/src/Dialog/DialogHeader.test.tsx +27 -2
  230. package/src/Dialog/DialogHeader.tsx +7 -8
  231. package/src/Dialog/__tests__/Dialog.a11y.chromium.spec.ts +21 -14
  232. package/src/Divider/Divider.doc.mjs +5 -3
  233. package/src/Divider/Divider.spec.md +140 -54
  234. package/src/Divider/Divider.test.tsx +15 -0
  235. package/src/Divider/Divider.tsx +6 -4
  236. package/src/DropdownMenu/DropdownMenu.doc.mjs +2 -2
  237. package/src/DropdownMenu/DropdownMenu.spec.md +121 -45
  238. package/src/DropdownMenu/DropdownMenu.test.tsx +288 -23
  239. package/src/DropdownMenu/DropdownMenu.tsx +212 -81
  240. package/src/DropdownMenu/DropdownMenuCheckboxItem.doc.mjs +38 -2
  241. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +32 -18
  242. package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +146 -1
  243. package/src/DropdownMenu/__tests__/MenuButton.a11y.chromium.spec.ts +136 -0
  244. package/src/DropdownMenu/__tests__/MenuButton.a11y.known-failures.ts +12 -0
  245. package/src/DropdownMenu/__tests__/MenuButton.a11y.renders.tsx +67 -0
  246. package/src/DropdownMenu/__tests__/MenuButton.a11y.states.ts +141 -0
  247. package/src/DropdownMenu/__tests__/MenuButton.a11y.test.tsx +138 -0
  248. package/src/DropdownMenu/__tests__/MenuHeaderFooter.a11y.chromium.spec.ts +40 -5
  249. package/src/Field/InputClearButton.test.tsx +29 -4
  250. package/src/Field/InputClearButton.tsx +26 -8
  251. package/src/FieldStatus/__tests__/StatusMessage.a11y.chromium.spec.ts +21 -14
  252. package/src/FormLayout/FormLayout.tsx +1 -0
  253. package/src/FormLayout/__snapshots__/FormLayout.test.tsx.snap +1 -1
  254. package/src/Grid/Grid.doc.mjs +14 -11
  255. package/src/Grid/Grid.spec.md +50 -32
  256. package/src/Grid/Grid.tsx +13 -4
  257. package/src/HoverCard/HoverCard.test.tsx +46 -1
  258. package/src/HoverCard/useHoverCard.tsx +68 -48
  259. package/src/InputGroup/InputGroup.doc.mjs +11 -1
  260. package/src/InputGroup/InputGroup.tsx +2 -4
  261. package/src/InputGroup/groupStyles.ts +40 -2
  262. package/src/Layer/useLayerDismissal.ts +9 -9
  263. package/src/Link/__tests__/Link.a11y.chromium.spec.ts +142 -0
  264. package/src/Link/__tests__/Link.a11y.renders.tsx +97 -0
  265. package/src/Link/__tests__/Link.a11y.states.ts +104 -0
  266. package/src/Link/__tests__/Link.a11y.test.tsx +127 -0
  267. package/src/Markdown/Markdown.doc.mjs +1 -1
  268. package/src/Markdown/Markdown.fr23.perf.test.ts +161 -40
  269. package/src/Markdown/Markdown.spec.md +45 -23
  270. package/src/Markdown/Markdown.test.tsx +38 -0
  271. package/src/Markdown/Markdown.tsx +24 -2
  272. package/src/Markdown/plugins/semanticFence.test.tsx +3 -2
  273. package/src/MobileNav/MobileNav.tsx +50 -2
  274. package/src/MobileNav/MobileNavFocus.test.tsx +553 -0
  275. package/src/MoreMenu/MoreMenu.spec.md +18 -7
  276. package/src/MoreMenu/MoreMenu.test.tsx +38 -0
  277. package/src/MultiSelector/MultiSelector.doc.mjs +8 -8
  278. package/src/MultiSelector/MultiSelector.spec.md +1 -1
  279. package/src/MultiSelector/MultiSelector.test.tsx +188 -21
  280. package/src/MultiSelector/MultiSelector.tsx +50 -11
  281. package/src/NumberInput/NumberInput.test.tsx +24 -0
  282. package/src/NumberInput/NumberInput.tsx +1 -1
  283. package/src/NumberInput/__tests__/NumberInput.a11y.chromium.spec.ts +22 -15
  284. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +78 -0
  285. package/src/PowerSearch/PowerSearchEditPopover.tsx +6 -0
  286. package/src/Resizable/Resizable.spec.md +41 -9
  287. package/src/Resizable/ResizeHandle.test.tsx +565 -2
  288. package/src/Resizable/ResizeHandle.tsx +126 -21
  289. package/src/Resizable/__tests__/ResizeHandle.a11y.chromium.spec.ts +119 -0
  290. package/src/Resizable/__tests__/ResizeHandle.a11y.known-failures.ts +39 -0
  291. package/src/Resizable/__tests__/ResizeHandle.a11y.renders.tsx +80 -0
  292. package/src/Resizable/__tests__/ResizeHandle.a11y.states.ts +197 -0
  293. package/src/Resizable/__tests__/ResizeHandle.a11y.test.tsx +123 -0
  294. package/src/Resizable/useResizable.ts +95 -0
  295. package/src/Selector/Selector.doc.mjs +7 -6
  296. package/src/Selector/Selector.spec.md +37 -24
  297. package/src/Selector/Selector.test.tsx +176 -10
  298. package/src/Selector/Selector.tsx +59 -14
  299. package/src/Selector/__tests__/Combobox.a11y.known-failures.ts +27 -0
  300. package/src/Selector/__tests__/Combobox.a11y.states.ts +145 -0
  301. package/src/Selector/__tests__/Selector.combobox.a11y.chromium.spec.ts +108 -0
  302. package/src/Selector/__tests__/Selector.combobox.a11y.test.tsx +126 -0
  303. package/src/SideNav/SideNav.test.tsx +35 -0
  304. package/src/SideNav/SideNav.tsx +16 -2
  305. package/src/Slider/Slider.spec.md +43 -17
  306. package/src/Slider/Slider.test.tsx +134 -0
  307. package/src/Slider/Slider.tsx +29 -6
  308. package/src/Slider/__tests__/Slider.a11y.chromium.spec.ts +112 -0
  309. package/src/Slider/__tests__/Slider.a11y.known-failures.ts +12 -0
  310. package/src/Slider/__tests__/Slider.a11y.renders.tsx +42 -0
  311. package/src/Slider/__tests__/Slider.a11y.states.ts +106 -0
  312. package/src/Slider/__tests__/Slider.a11y.test.tsx +105 -0
  313. package/src/Switch/__tests__/Switch.a11y.chromium.spec.ts +25 -18
  314. package/src/TabList/__tests__/Tabs.a11y.chromium.spec.ts +19 -12
  315. package/src/TextInput/__tests__/TextInput.a11y.chromium.spec.ts +21 -14
  316. package/src/ToggleButton/__tests__/ToggleButton.a11y.chromium.spec.ts +18 -11
  317. package/src/Tokenizer/Tokenizer.test.tsx +87 -0
  318. package/src/Tokenizer/Tokenizer.tsx +31 -3
  319. package/src/Toolbar/Toolbar.test.tsx +131 -4
  320. package/src/Toolbar/Toolbar.tsx +3 -1
  321. package/src/TreeList/TreeList.spec.md +33 -8
  322. package/src/TreeList/TreeList.test.tsx +72 -0
  323. package/src/TreeList/TreeList.tsx +10 -6
  324. package/src/TreeList/TreeListItem.tsx +5 -0
  325. package/src/TreeList/__tests__/TreeList.a11y.chromium.spec.ts +125 -0
  326. package/src/TreeList/__tests__/TreeList.a11y.renders.tsx +44 -0
  327. package/src/TreeList/__tests__/TreeList.a11y.states.ts +164 -0
  328. package/src/TreeList/__tests__/TreeList.a11y.test.tsx +138 -0
  329. package/src/TreeList/__tests__/TreeListRowNames.a11y.chromium.spec.ts +82 -0
  330. package/src/hooks/useScrollOverflow.test.tsx +222 -0
  331. package/src/hooks/useScrollOverflow.ts +55 -13
  332. package/src/hooks/useTreeFocus.test.tsx +37 -0
  333. package/src/hooks/useTreeFocus.ts +55 -2
  334. package/src/i18n/generated-locales/en.generated.ts +3 -0
  335. package/src/i18n/generated-locales/pseudo.generated.ts +3 -0
  336. package/src/reset.a11y.chromium.spec.ts +9 -1
  337. package/src/reset.css +8 -3
  338. package/src/reset.until-found.a11y.browser.spec.ts +75 -0
  339. package/src/reset.until-found.test.ts +32 -0
  340. package/src/stylexValidation.source-build.test.mjs +42 -0
  341. package/src/theme/syntax/SyntaxTheme.tsx +46 -5
  342. package/src/theme/syntax/defineSyntaxTheme.diff.test.ts +91 -0
  343. package/src/theme/syntax/defineSyntaxTheme.ts +75 -15
  344. package/src/theme/syntax/index.ts +5 -1
  345. package/src/theme/syntax/tokens.ts +32 -2
  346. package/src/theme/syntax/useSyntaxTheme.diff.test.tsx +40 -0
  347. package/src/utils/plainDate.test.ts +147 -0
  348. package/src/utils/plainDate.ts +75 -10
@@ -7,47 +7,93 @@ export const docs = {
7
7
  subComponentOf: 'CommandPalette',
8
8
  displayName: 'Command Palette Item',
9
9
  isHiddenFromOverview: true,
10
- description: 'A selectable item. Accepts arbitrary children for full rendering control. Registers with context for keyboard navigation when inside CommandPalette.',
10
+ description:
11
+ 'One option in a command palette result list. CommandPalette context supplies selection, highlight, identity, and close behavior.',
12
+ usage: {
13
+ description:
14
+ 'Use CommandPaletteItem for one non-interactive result row inside CommandPaletteList or CommandPaletteGroup. CommandPalette owns the composite keyboard model; standalone items expose only their explicit visual state and pointer activation.',
15
+ bestPractices: [
16
+ {
17
+ guidance: true,
18
+ description:
19
+ 'Keep each value unique within the result list so highlight, active-descendant identity, and selection resolve to the same item.',
20
+ },
21
+ {
22
+ guidance: true,
23
+ description:
24
+ 'Use non-interactive child content such as icons, descriptions, and shortcut hints; activate the option itself instead of nesting buttons or links.',
25
+ },
26
+ {
27
+ guidance: false,
28
+ description:
29
+ 'Treat isHighlighted as selection. Highlight is the active keyboard result; isSelected represents the chosen value.',
30
+ },
31
+ ],
32
+ anatomy: [
33
+ {
34
+ name: 'Item',
35
+ required: true,
36
+ description:
37
+ 'The option root that carries selection, disabled, item identity, interaction, and theme state.',
38
+ },
39
+ {
40
+ name: 'Content',
41
+ required: true,
42
+ description:
43
+ 'Caller-provided non-interactive label and supporting presentation.',
44
+ },
45
+ ],
46
+ },
47
+ theming: {
48
+ targets: [{className: 'astryx-command-palette-item'}],
49
+ },
11
50
  props: [
12
51
  {
13
52
  name: 'value',
14
53
  type: 'string',
15
- description: 'Unique value for identification and selection.',
54
+ description:
55
+ 'Unique value used for item identity, highlight lookup, and selection.',
16
56
  required: true,
17
57
  },
18
58
  {
19
59
  name: 'children',
20
60
  type: 'ReactNode',
21
- description: 'Item content: render icons, descriptions, keyboard shortcuts, etc.',
61
+ description:
62
+ 'Non-interactive item content such as a label, icon, description, or keyboard shortcut.',
22
63
  required: true,
23
64
  },
24
65
  {
25
66
  name: 'onSelect',
26
67
  type: '(value: string) => void',
27
- description: 'Called when this item is selected via click or Enter.',
68
+ description:
69
+ 'Called after this item is activated by pointer. Keyboard selection in CommandPalette reports through CommandPalette onValueChange.',
28
70
  },
29
71
  {
30
72
  name: 'isHighlighted',
31
73
  type: 'boolean',
32
- description: 'Whether this item has keyboard focus. Derived from context when inside CommandPalette.',
74
+ description:
75
+ 'Whether this item is the active keyboard result. Derived from context when omitted inside CommandPalette.',
33
76
  default: 'false',
34
77
  },
35
78
  {
36
79
  name: 'isSelected',
37
80
  type: 'boolean',
38
- description: 'Whether this item is selected in picker mode.',
81
+ description:
82
+ 'Whether this item represents the selected value in picker mode.',
39
83
  default: 'false',
40
84
  },
41
85
  {
42
86
  name: 'isDisabled',
43
87
  type: 'boolean',
44
- description: 'Whether the item is non-interactive.',
88
+ description:
89
+ 'Whether the item is unavailable and suppresses pointer activation.',
45
90
  default: 'false',
46
91
  },
47
92
  {
48
93
  name: 'xstyle',
49
94
  type: 'StyleXStyles',
50
- description: 'StyleX styles for layout customization. Must be a stylex.create() value.',
95
+ description:
96
+ 'StyleX styles for layout customization. Must be a stylex.create() value.',
51
97
  },
52
98
  ],
53
99
  playground: {
@@ -62,14 +108,17 @@ export const docsZh = {
62
108
  name: 'CommandPaletteItem',
63
109
  isHiddenFromOverview: true,
64
110
  displayName: 'Command Palette Item',
65
- description: '可选择的条目。接受任意子元素以实现完整的渲染控制。',
111
+ description:
112
+ '命令面板结果列表中的一个选项。CommandPalette 上下文提供选择、高亮、标识和关闭行为。',
66
113
  propDescriptions: {
67
- value: '用于标识和选择的唯一值。',
68
- children: '条目内容——渲染图标、描述、键盘快捷键等。',
69
- onSelect: '通过点击或 Enter 选择此条目时调用。',
70
- isHighlighted: '此条目是否具有键盘焦点。在 CommandPalette 内从上下文派生。',
71
- isSelected: '此条目在选择器模式下是否被选中。',
72
- isDisabled: '条目是否为非交互状态。',
114
+ value: '用于条目标识、高亮查找和选择的唯一值。',
115
+ children: '非交互式条目内容,例如标签、图标、描述或键盘快捷键。',
116
+ onSelect:
117
+ '通过指针激活此条目后调用。CommandPalette 中的键盘选择通过根组件的 onValueChange 报告。',
118
+ isHighlighted:
119
+ '此条目是否为当前键盘结果。在 CommandPalette 内省略时从上下文派生。',
120
+ isSelected: '此条目是否代表选择器模式中的已选值。',
121
+ isDisabled: '条目是否不可用并禁止指针激活。',
73
122
  xstyle: 'StyleX 布局自定义样式。必须是 stylex.create() 的值。',
74
123
  },
75
124
  };
@@ -78,14 +127,16 @@ export const docsDense = {
78
127
  name: 'CommandPaletteItem',
79
128
  isHiddenFromOverview: true,
80
129
  displayName: 'Command Palette Item',
81
- description: 'selectable item; arbitrary children; registers w/ context for kbd nav',
130
+ description:
131
+ 'one result option; context owns selection, highlight, identity, and close',
82
132
  propDescriptions: {
83
- value: 'unique id for selection',
84
- children: 'item content: icons, descriptions, shortcuts',
85
- onSelect: 'called on click or Enter',
86
- isHighlighted: 'keyboard focus; derived from context inside palette',
87
- isSelected: 'selected in picker mode',
88
- isDisabled: 'non-interactive',
133
+ value: 'unique value for identity, highlight lookup, and selection',
134
+ children: 'non-interactive label and supporting content',
135
+ onSelect:
136
+ 'called after pointer activation; palette keyboard selection uses root onValueChange',
137
+ isHighlighted: 'active keyboard result; derived from context when omitted',
138
+ isSelected: 'selected value in picker mode',
139
+ isDisabled: 'unavailable; suppresses pointer activation',
89
140
  xstyle: 'StyleX layout styles; must be stylex.create() value',
90
141
  },
91
142
  };
@@ -0,0 +1,223 @@
1
+ ---
2
+ schema_version: 3
3
+ template_version: 7
4
+ kind: component
5
+ id: component:CommandPaletteItem
6
+ authority: draft
7
+ archive_reason: null
8
+ superseded_by: null
9
+ approved_by: null
10
+ approved_at: null
11
+ owners: [cixzhang]
12
+ review_triggers: [behavior, accessibility, public-api, compatibility, theming]
13
+ verified_by:
14
+ [
15
+ packages/core/src/CommandPalette/CommandPaletteItem.test.tsx,
16
+ packages/core/src/CommandPalette/CommandPalette.test.tsx,
17
+ packages/core/src/theme/themingTargets.test.ts,
18
+ apps/storybook/stories/CommandPaletteItem.stories.tsx,
19
+ apps/storybook/rtl-audit/targets.json,
20
+ scripts/check-knowledge.mjs,
21
+ ]
22
+ modules: []
23
+ families: []
24
+ design_specs: []
25
+ architecture:
26
+ [
27
+ architecture:component-test-sufficiency,
28
+ architecture:component-theming-surface,
29
+ architecture:interaction-modality,
30
+ architecture:public-component-api,
31
+ ]
32
+ contributing: []
33
+ system_specs: [spec:AST-017, spec:AST-020]
34
+ ---
35
+
36
+ # CommandPaletteItem component contract
37
+
38
+ ## Contract at a glance
39
+
40
+ | Area | Contract |
41
+ | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
42
+ | Public contract | One result option with context-backed identity, highlight, selection, and close behavior; explicit standalone visual state and pointer activation remain available. |
43
+ | Behavior | Consumer click runs first; cancellation stops selection; successful activation reports locally, updates context, and closes; disabled items run no click callbacks. |
44
+ | End-user impact | Disabled commands cannot activate, and keyboard focus, selected value, and option identity remain distinct and consistently exposed. |
45
+ | Builder impact | Values stay unique; children stay non-interactive; CommandPalette owns composite keyboard navigation and reports keyboard selection through root `onValueChange`. |
46
+ | Compatibility/readiness | Victim-free `[fix]` restores promised disabled and native-passthrough behavior; the standalone keyboard contract remains unsettled. |
47
+ | Review checks | Reject disabled activation, dropped standalone DOM identity, highlight-as-selection ARIA, nested interactive children, or a second context scroll owner. |
48
+ | Governing rules | `architecture:public-component-api/INV5,INV7`; `architecture:interaction-modality`; `spec:AST-017/FR1,FR3,FR5`; `spec:AST-020/FR1,FR2`; WAI-ARIA 1.2 `option`. |
49
+
50
+ This table is a review projection; the body below is authoritative.
51
+
52
+ ## Intent
53
+
54
+ CommandPaletteItem presents one command result as an option. CommandPalette
55
+ context supplies composite state and keyboard ownership; the item owns its option
56
+ semantics, visual states, pointer activation, native passthrough boundary, and
57
+ standalone scroll behavior.
58
+
59
+ ## Compatibility and migration
60
+
61
+ - Released default preserved: `yes`
62
+ - Compatibility class: victim-free contract restoration under
63
+ `spec:AST-017/FR1,FR3,FR5`; `isDisabled` already promises a non-interactive
64
+ item and the native `BaseProps` seam already promises standalone DOM props
65
+ - Controlled/uncontrolled behavior: explicit item state still precedes context
66
+ state, then the existing false default
67
+ - Migration decision: none for these corrections; OQ1 holds any change to the
68
+ standalone keyboard contract
69
+ - Documentation compatibility: item `onSelect` reports pointer activation only.
70
+ No public runtime path delivers Enter to it — CommandPalette mints rows without
71
+ item callbacks and standalone items have no keyboard owner — so describing
72
+ keyboard selection through root `onValueChange` leaves no released consumer
73
+ behind (`spec:AST-017/FR1,FR5`). OQ1 owns any standalone keyboard path.
74
+
75
+ Consumer migration instructions belong in consumer docs and release notes.
76
+
77
+ ## Ownership boundary
78
+
79
+ **Owns**
80
+
81
+ - The option root, item value marker, selected and disabled ARIA state, and
82
+ `command-palette-item` theme target.
83
+ - Explicit → CommandPalette context → false precedence for highlighted and
84
+ selected visual state.
85
+ - Pointer activation order, disabled suppression, and context selection/close.
86
+ - Standalone highlighted-item scroll behavior and the inline-preview initial
87
+ scroll suppression.
88
+
89
+ **Does not own / non-goals**
90
+
91
+ - CommandPalette's listbox, query-field active descendant, arrow-key navigation,
92
+ Enter handling, search results, or root `onValueChange` callback.
93
+ - Grouping, list layout, or caller-provided non-interactive item content.
94
+ - A standalone composite listbox keyboard model; its direction remains OQ1.
95
+ - Interactive descendants. Buttons and links are sibling actions or separate
96
+ commands, not content inside an option.
97
+
98
+ ## Public concepts
99
+
100
+ | Concept | Closed values or states | Meaning | Availability | Default | Owner | Stability | Invalid-value behavior |
101
+ | ------------- | --------------------------------------------------- | ------------------------------------------------- | ------------------------ | ------- | ------------------------------ | --------- | --------------------------------------------------------- |
102
+ | Highlight | explicit; context index; false | Active keyboard result, painted but not selected. | All uses | false | `component:CommandPaletteItem` | Stable | Unknown context value leaves every item unhighlighted. |
103
+ | Selection | explicit; context value; false | Chosen value exposed through `aria-selected`. | All uses | false | `component:CommandPaletteItem` | Stable | Duplicate values resolve ambiguously; values stay unique. |
104
+ | Availability | enabled; disabled | Whether pointer activation is available. | All uses | enabled | `component:CommandPaletteItem` | Stable | Disabled suppresses consumer and component callbacks. |
105
+ | Item identity | context-generated id; standalone caller-provided id | DOM identity used by active-descendant or caller. | Contextual or standalone | absent | component or caller | Stable | Context identity wins only for a registered item. |
106
+
107
+ ## Behavioral and layout contract
108
+
109
+ | ID | Candidate invariant | Basis | Draft review state |
110
+ | --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------------------- |
111
+ | FR1 | Native props and `ref` reach the option root. CommandPalette context owns registered-item id, role, selected state, disabled state, and value marker; standalone caller id persists. | Released source and `architecture:public-component-api/INV5` | Verified by focused DOM tests |
112
+ | FR2 | Pointer activation runs consumer `onClick`, then stops when prevented; otherwise it calls item `onSelect`, then context selection and close. Disabled items run none of those paths. | Released callbacks and disabled promise | Verified; mutation-resistant |
113
+ | FR3 | Explicit `isHighlighted` and `isSelected` precede context-derived values, then false. Highlight paints active state only; selection alone drives `aria-selected`. | Released source, docs, and listbox semantics | State semantics tested; precedence tested; combined paint gap remains OQ2 |
114
+ | FR4 | Context owns highlighted-item scrolling. Outside context, a highlighted item scrolls nearest, except an initially highlighted item inside an inline Dialog does not scroll. | Released source and regression history | Verified by focused Effect tests |
115
+ | FR5 | Children provide the option's label and supporting presentation, without nested interactive descendants. | Option semantics and `spec:AST-020/FR1,FR2` | Documented; exact-head a11y remains a gate |
116
+
117
+ ### Allowed variation
118
+
119
+ - **AV1 — Content.** Labels, icons, descriptions, and shortcut hints may vary
120
+ while remaining non-interactive.
121
+ - **AV2 — Visual state.** Highlight, selection, and disabled state may occur
122
+ independently or together. The current selected paint masks highlighted paint
123
+ when both are true; OQ2 holds the visible-state remedy.
124
+ - **AV3 — Layout.** Consumer `xstyle`, class, and style may adjust the single
125
+ root without replacing its option semantics.
126
+
127
+ ### Representative states
128
+
129
+ | State | Required invariant | Allowed variation |
130
+ | -------------------- | ------------------------------------------------------------------------- | --------------------------------- |
131
+ | Enabled standalone | Caller id and native props persist; pointer activation reports locally. | Content and visual state. |
132
+ | Disabled standalone | `aria-disabled` is true and no click callback fires. | Content. |
133
+ | Context highlighted | Context item id matches active descendant and highlight is not selection. | Item index and content. |
134
+ | Context selected | Matching value exposes `aria-selected=true`. | Highlight may be same or another. |
135
+ | Consumer-cancelled | Consumer click runs; local and context selection/close do not. | Consumer side effect. |
136
+ | Inline initial state | Initial standalone highlight does not scroll the surrounding preview. | Selected value and content. |
137
+
138
+ ### Transformation and precedence order
139
+
140
+ - **ORD1 — Visual state.** Explicit item prop → CommandPalette context → false.
141
+ - **ORD2 — Pointer activation.** Disabled guard → consumer click → prevented
142
+ check → item `onSelect` → context select → context close.
143
+ - **ORD3 — Identity.** Registered context id → standalone caller id → absent.
144
+
145
+ ### Performance and resources
146
+
147
+ - **PR1 — Lookup.** Context matching remains bounded by the current flat result
148
+ list and performs no listener, observer, or per-item registry work.
149
+ - **PR2 — Scroll ownership.** One owner scrolls a highlighted contextual item;
150
+ standalone items schedule no work when not highlighted.
151
+
152
+ ## Accessibility contract
153
+
154
+ - **AR1 — Option semantics.** The root exposes `role=option`; its content or
155
+ caller label provides the accessible name, and `aria-selected` reports chosen
156
+ value rather than visual highlight.
157
+ - **AR2 — Composite ownership.** Inside CommandPalette, the query field retains
158
+ focus and points to the context-generated item id; CommandPalette owns arrow
159
+ navigation and Enter selection under its adopted listbox/combobox model.
160
+ - **AR3 — Disabled state.** Disabled items expose `aria-disabled=true` and
161
+ suppress every pointer activation callback. Source inspection confirms the
162
+ interaction overlay is omitted; exact-head browser evidence remains the paint
163
+ gate.
164
+ - **AR4 — Content.** Item children contain no nested button, link, or other
165
+ interactive descendant whose semantics would be lost when the `option`
166
+ role makes its descendants presentational, following WAI-ARIA 1.2 and
167
+ `spec:AST-020/FR1,FR2`.
168
+ - **AR5 — Standalone gap.** A standalone option has no owning composite keyboard
169
+ model. OQ1 must settle that public contract before runtime semantics change.
170
+
171
+ ## Design relationships
172
+
173
+ | Anatomy | Design requirement | Representation authority | Hierarchy role | Component contract |
174
+ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | -------------- | ------------------ |
175
+ | Item | Paints enabled, highlighted, selected, disabled, and press states on one root. Selected currently masks highlight when both apply (OQ2). | Current source and public docs | Prominent | FR1–FR4, AR1–AR3 |
176
+ | Content | Supplies the option name and non-interactive supporting presentation. | Product callsite | Supporting | FR5, AR1, AR4 |
177
+
178
+ ## Family and system relationships
179
+
180
+ - `component:CommandPalette` owns composite search, listbox, active-descendant,
181
+ keyboard, and close orchestration; this component binds one option to it.
182
+ - `architecture:interaction-modality` owns shared pointer and keyboard behavior.
183
+ - `architecture:public-component-api` owns native passthrough and released API
184
+ compatibility.
185
+ - `architecture:component-theming-surface` owns the aggregate Item anatomy map
186
+ and stable `command-palette-item` target.
187
+ - `spec:AST-017` classifies the victim-free corrections and holds OQ1 against
188
+ silent released-contract changes.
189
+ - `spec:AST-020` supplies accessibility evidence and adopted-pattern boundaries.
190
+ - WAI-ARIA 1.2 option semantics make descendants presentational, so interactive
191
+ controls do not belong inside this option root.
192
+
193
+ ## Verification map
194
+
195
+ | Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
196
+ | ----------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ----------------------------------- |
197
+ | FR1, FR3, AR1–AR2 | `CommandPaletteItem.test.tsx`, `CommandPalette.test.tsx` | standalone; context highlighted/selected | Dropped id/ref/native prop, clobberable role/state, or highlight-as-selection fails focused DOM assertions. | `audit:CommandPaletteItem/a11y` |
198
+ | FR2, AR3 | `CommandPaletteItem.test.tsx` | enabled; disabled; consumer-cancelled; contextual | Disabled consumer activation, ignored cancellation, missing local report, selection, or close fails tests. | `audit:CommandPaletteItem/behavior` |
199
+ | FR4 | `CommandPaletteItem.test.tsx`, `CommandPalette.test.tsx` | standalone; inline initial; changed highlight | Lost nearest scrolling, duplicate contextual scrolling, or initial inline scroll fails Effect assertions. | `audit:CommandPaletteItem/behavior` |
200
+ | FR5, AR4 | public docs, dedicated Storybook states, exact-head a11y/browser evidence | label; shortcut; disabled | Interactive descendant guidance regresses or supported composition fails exact-head accessibility evidence. | `audit:CommandPaletteItem/a11y` |
201
+ | Theme/RTL | focused class assertion, `themingTargets.test.ts`, Storybook fixture, RTL verified N/A | all visual states | Target loss fails inventory/DOM tests; any new directional behavior requires a non-empty RTL dimension. | `audit:CommandPaletteItem/theming` |
202
+
203
+ ## Decision log
204
+
205
+ No component-local API, keyboard, or visual decision is settled in this draft.
206
+ Objective corrections preserve the current public shape.
207
+
208
+ ## Open questions
209
+
210
+ - **OQ1 — What standalone keyboard contract should CommandPaletteItem expose?**
211
+ (`human-api`) Current standalone use exposes an option and pointer activation
212
+ but no owning listbox keyboard model. Decide whether a public composite owner
213
+ must supply that model, the item should gain a different standalone role and
214
+ interaction contract, or standalone activation should enter a migration path.
215
+ - **OQ2 — How should keyboard highlight remain visible when the item is also
216
+ selected?** (`human-design`) Current selected background paint follows and
217
+ masks the highlighted background. Real-browser pixels must confirm the gap;
218
+ any appearance remedy requires owner direction and a separate visual change.
219
+
220
+ ## Content boundary
221
+
222
+ This file does not duplicate consumer examples, audit scores, implementation
223
+ steps, aggregate CommandPalette search/list behavior, or shared system rules.
@@ -6,9 +6,12 @@
6
6
  * @output Unit tests for CommandPaletteItem
7
7
  */
8
8
 
9
+ import {createRef, type ReactElement} from 'react';
9
10
  import {afterEach, describe, it, expect, vi} from 'vitest';
10
11
  import {render, screen, fireEvent, waitFor} from '@testing-library/react';
11
12
  import {Dialog} from '../Dialog/Dialog';
13
+ import {CommandPaletteContext} from './CommandPaletteContext';
14
+ import type {CommandPaletteContextValue} from './CommandPaletteContext';
12
15
  import {CommandPaletteItem} from './CommandPaletteItem';
13
16
 
14
17
  const scrollIntoViewDescriptor = Object.getOwnPropertyDescriptor(
@@ -38,11 +41,45 @@ afterEach(() => {
38
41
  }
39
42
  });
40
43
 
44
+ function makeContext(
45
+ overrides: Partial<CommandPaletteContextValue> = {},
46
+ ): CommandPaletteContextValue {
47
+ return {
48
+ search: '',
49
+ setSearch: vi.fn(),
50
+ value: '',
51
+ setValue: vi.fn(),
52
+ listId: 'command-list',
53
+ highlightedIndex: -1,
54
+ setHighlightedIndex: vi.fn(),
55
+ getItemId: index => `command-item-${index}`,
56
+ selectableItems: [{value: 'test', label: 'Item'}],
57
+ searchResults: [],
58
+ selectItem: vi.fn(),
59
+ onKeyDown: vi.fn(),
60
+ onClose: vi.fn(),
61
+ isOpen: true,
62
+ isBusy: false,
63
+ ...overrides,
64
+ };
65
+ }
66
+
67
+ function renderWithContext(
68
+ item: ReactElement,
69
+ overrides: Partial<CommandPaletteContextValue> = {},
70
+ ) {
71
+ const context = makeContext(overrides);
72
+ return {
73
+ context,
74
+ ...render(
75
+ <CommandPaletteContext value={context}>{item}</CommandPaletteContext>,
76
+ ),
77
+ };
78
+ }
79
+
41
80
  describe('CommandPaletteItem', () => {
42
81
  it('renders children', () => {
43
- render(
44
- <CommandPaletteItem value="test">Test Item</CommandPaletteItem>,
45
- );
82
+ render(<CommandPaletteItem value="test">Test Item</CommandPaletteItem>);
46
83
  expect(screen.getByText('Test Item')).toBeInTheDocument();
47
84
  });
48
85
 
@@ -51,6 +88,13 @@ describe('CommandPaletteItem', () => {
51
88
  expect(screen.getByRole('option')).toBeInTheDocument();
52
89
  });
53
90
 
91
+ it('carries the stable item theme target', () => {
92
+ render(<CommandPaletteItem value="test">Item</CommandPaletteItem>);
93
+ expect(screen.getByRole('option')).toHaveClass(
94
+ 'astryx-command-palette-item',
95
+ );
96
+ });
97
+
54
98
  it('calls onSelect when clicked', () => {
55
99
  const handleSelect = vi.fn();
56
100
  render(
@@ -62,6 +106,36 @@ describe('CommandPaletteItem', () => {
62
106
  expect(handleSelect).toHaveBeenCalledWith('test');
63
107
  });
64
108
 
109
+ it('coordinates selection and close through CommandPalette context', () => {
110
+ const handleSelect = vi.fn();
111
+ const {context} = renderWithContext(
112
+ <CommandPaletteItem value="test" onSelect={handleSelect}>
113
+ Item
114
+ </CommandPaletteItem>,
115
+ );
116
+
117
+ fireEvent.click(screen.getByRole('option'));
118
+
119
+ expect(handleSelect).toHaveBeenCalledWith('test');
120
+ expect(context.selectItem).toHaveBeenCalledWith('test');
121
+ expect(context.onClose).toHaveBeenCalledTimes(1);
122
+ });
123
+
124
+ it('lets consumer click cancellation stop contextual selection and close', () => {
125
+ const {context} = renderWithContext(
126
+ <CommandPaletteItem
127
+ value="test"
128
+ onClick={event => event.preventDefault()}>
129
+ Item
130
+ </CommandPaletteItem>,
131
+ );
132
+
133
+ fireEvent.click(screen.getByRole('option'));
134
+
135
+ expect(context.selectItem).not.toHaveBeenCalled();
136
+ expect(context.onClose).not.toHaveBeenCalled();
137
+ });
138
+
65
139
  it('does not call onSelect when disabled', () => {
66
140
  const handleSelect = vi.fn();
67
141
  render(
@@ -73,6 +147,94 @@ describe('CommandPaletteItem', () => {
73
147
  expect(handleSelect).not.toHaveBeenCalled();
74
148
  });
75
149
 
150
+ it('does not call consumer click or selection handlers when disabled', () => {
151
+ const handleClick = vi.fn();
152
+ const handleSelect = vi.fn();
153
+ render(
154
+ <CommandPaletteItem
155
+ value="test"
156
+ isDisabled
157
+ onClick={handleClick}
158
+ onSelect={handleSelect}>
159
+ Item
160
+ </CommandPaletteItem>,
161
+ );
162
+
163
+ fireEvent.click(screen.getByRole('option'));
164
+
165
+ expect(handleClick).not.toHaveBeenCalled();
166
+ expect(handleSelect).not.toHaveBeenCalled();
167
+ });
168
+
169
+ it('lets a consumer cancel selection from onClick', () => {
170
+ const handleSelect = vi.fn();
171
+ render(
172
+ <CommandPaletteItem
173
+ value="test"
174
+ onClick={event => event.preventDefault()}
175
+ onSelect={handleSelect}>
176
+ Item
177
+ </CommandPaletteItem>,
178
+ );
179
+
180
+ fireEvent.click(screen.getByRole('option'));
181
+
182
+ expect(handleSelect).not.toHaveBeenCalled();
183
+ });
184
+
185
+ it('derives selected state and item identity from context', () => {
186
+ renderWithContext(
187
+ <CommandPaletteItem value="test" id="consumer-id">
188
+ Item
189
+ </CommandPaletteItem>,
190
+ {value: 'test'},
191
+ );
192
+
193
+ const item = screen.getByRole('option');
194
+ expect(item).toHaveAttribute('id', 'command-item-0');
195
+ expect(item).toHaveAttribute('aria-selected', 'true');
196
+ });
197
+
198
+ it('paints context-derived highlight when the item is not selected', () => {
199
+ renderWithContext(
200
+ <CommandPaletteItem value="test">Item</CommandPaletteItem>,
201
+ {highlightedIndex: 0},
202
+ );
203
+
204
+ expect(getComputedStyle(screen.getByRole('option')).backgroundColor).toBe(
205
+ 'var(--color-overlay-hover)',
206
+ );
207
+ });
208
+
209
+ it('lets explicit visual state override context-derived state', () => {
210
+ renderWithContext(
211
+ <CommandPaletteItem value="test" isHighlighted={false} isSelected={false}>
212
+ Item
213
+ </CommandPaletteItem>,
214
+ {value: 'test', highlightedIndex: 0},
215
+ );
216
+
217
+ const item = screen.getByRole('option');
218
+ expect(item).toHaveAttribute('aria-selected', 'false');
219
+ expect(getComputedStyle(item).backgroundColor).toBe('rgba(0, 0, 0, 0)');
220
+ });
221
+
222
+ it('protects owned option semantics from native passthrough props', () => {
223
+ render(
224
+ <CommandPaletteItem
225
+ value="test"
226
+ role="button"
227
+ aria-selected={true}
228
+ aria-disabled={true}>
229
+ Item
230
+ </CommandPaletteItem>,
231
+ );
232
+
233
+ const item = screen.getByRole('option');
234
+ expect(item).toHaveAttribute('aria-selected', 'false');
235
+ expect(item).not.toHaveAttribute('aria-disabled');
236
+ });
237
+
76
238
  it('sets aria-disabled when disabled', () => {
77
239
  render(
78
240
  <CommandPaletteItem value="test" isDisabled>
@@ -157,10 +319,43 @@ describe('CommandPaletteItem', () => {
157
319
  });
158
320
  });
159
321
 
160
- it('sets data-value attribute', () => {
322
+ it('forwards ref and standalone DOM attributes to the option', () => {
323
+ const ref = createRef<HTMLDivElement>();
324
+ render(
325
+ <CommandPaletteItem
326
+ ref={ref}
327
+ value="test"
328
+ id="standalone-item"
329
+ aria-label="Open settings"
330
+ data-kind="command">
331
+ Item
332
+ </CommandPaletteItem>,
333
+ );
334
+
335
+ const item = screen.getByRole('option', {name: 'Open settings'});
336
+ expect(ref.current).toBe(item);
337
+ expect(item).toHaveAttribute('id', 'standalone-item');
338
+ expect(item).toHaveAttribute('data-kind', 'command');
339
+ });
340
+
341
+ it('carries the stable theme target and consumer styling on its root', () => {
161
342
  render(
162
- <CommandPaletteItem value="my-value">Item</CommandPaletteItem>,
343
+ <CommandPaletteItem
344
+ value="test"
345
+ className="consumer-item"
346
+ style={{marginBlockStart: '8px'}}>
347
+ Item
348
+ </CommandPaletteItem>,
163
349
  );
350
+
351
+ const item = screen.getByRole('option');
352
+ expect(item).toHaveClass('astryx-command-palette-item');
353
+ expect(item).toHaveClass('consumer-item');
354
+ expect(item).toHaveStyle({marginBlockStart: '8px'});
355
+ });
356
+
357
+ it('sets data-value attribute', () => {
358
+ render(<CommandPaletteItem value="my-value">Item</CommandPaletteItem>);
164
359
  expect(screen.getByRole('option')).toHaveAttribute(
165
360
  'data-value',
166
361
  'my-value',