@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
@@ -0,0 +1,123 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ /** @vitest-environment jsdom */
3
+
4
+ /**
5
+ * @file ResizeHandle.a11y.test.tsx
6
+ * @input WINDOW_SPLITTER_PATTERN bound to ResizeHandle's representative states
7
+ * @output jsdom-lane proof of the DOM expectations and an honest "unrun" report for the browser layers
8
+ * @position Binding test for component:Resizable AR1 (the Chromium spec covers the rest)
9
+ */
10
+
11
+ import {cleanup, render, screen} from '@testing-library/react';
12
+ import {describe, expect, it} from 'vitest';
13
+ import {
14
+ WINDOW_SPLITTER_PATTERN,
15
+ checkAccessibilitySpec,
16
+ createJsdomHarness,
17
+ expectAccessibilitySpec,
18
+ summarize,
19
+ type BindingResult,
20
+ } from '@astryxdesign/a11y-spec';
21
+ import {RESIZE_HANDLE_KNOWN_FAILURES} from './ResizeHandle.a11y.known-failures';
22
+ import {
23
+ BARE_PANE_ID,
24
+ renderResizeHandleState,
25
+ } from './ResizeHandle.a11y.renders';
26
+ import {
27
+ RESIZE_HANDLE_BINDING_STATES,
28
+ RESIZE_HANDLE_EXCLUSIONS,
29
+ type ResizeHandleBindingState,
30
+ } from './ResizeHandle.a11y.states';
31
+
32
+ function separator(state: ResizeHandleBindingState): HTMLElement {
33
+ return screen.getByRole('separator', {name: state.label});
34
+ }
35
+
36
+ function pane(): HTMLElement {
37
+ const element = document.getElementById(BARE_PANE_ID);
38
+ if (element == null) {
39
+ throw new Error('the bare pane is not rendered');
40
+ }
41
+ return element;
42
+ }
43
+
44
+ async function checkState(
45
+ state: ResizeHandleBindingState,
46
+ ): Promise<BindingResult> {
47
+ return checkAccessibilitySpec({
48
+ spec: WINDOW_SPLITTER_PATTERN,
49
+ binding: 'ResizeHandle',
50
+ state: state.id,
51
+ facts: state.facts,
52
+ knownFailures: RESIZE_HANDLE_KNOWN_FAILURES,
53
+ mount: async () => {
54
+ render(renderResizeHandleState(state));
55
+ return createJsdomHarness({
56
+ subject: separator(state),
57
+ related: {pane: pane()},
58
+ });
59
+ },
60
+ unmount: cleanup,
61
+ });
62
+ }
63
+
64
+ describe('ResizeHandle — window splitter pattern, jsdom lane', () => {
65
+ it.each(
66
+ RESIZE_HANDLE_BINDING_STATES.map(
67
+ state => [state.id, state.summary, state] as const,
68
+ ),
69
+ )('%s — %s', async (_id, _summary, state) => {
70
+ await expectAccessibilitySpec({
71
+ spec: WINDOW_SPLITTER_PATTERN,
72
+ binding: 'ResizeHandle',
73
+ state: state.id,
74
+ facts: state.facts,
75
+ knownFailures: RESIZE_HANDLE_KNOWN_FAILURES,
76
+ render: () => {
77
+ render(renderResizeHandleState(state));
78
+ },
79
+ subject: () => separator(state),
80
+ related: () => ({pane: pane()}),
81
+ cleanup,
82
+ });
83
+ });
84
+
85
+ it('runs the DOM layer and reports the browser-owned outcomes as unrun', async () => {
86
+ const results: BindingResult[] = [];
87
+ for (const state of RESIZE_HANDLE_BINDING_STATES) {
88
+ results.push(await checkState(state));
89
+ }
90
+ const report = summarize(WINDOW_SPLITTER_PATTERN, results);
91
+ expect(report.counts.pass).toBeGreaterThan(0);
92
+ expect(report.unrunLayers).toEqual(['accessibility-tree', 'real-browser']);
93
+ expect(report.counts.unexpectedPass).toBe(0);
94
+ });
95
+ });
96
+
97
+ describe('ResizeHandle binding inventory', () => {
98
+ it('gives every representative state a distinct checked-in story', () => {
99
+ const stories = RESIZE_HANDLE_BINDING_STATES.map(state => state.storyId);
100
+ expect(new Set(stories).size).toBe(stories.length);
101
+ });
102
+
103
+ it('keeps pointer and pane-cycling ownership explicit', () => {
104
+ expect(RESIZE_HANDLE_EXCLUSIONS.map(exclusion => exclusion.id)).toEqual([
105
+ 'sidenav-binding',
106
+ 'pointer-drag-model',
107
+ 'pane-cycling',
108
+ ]);
109
+ for (const exclusion of RESIZE_HANDLE_EXCLUSIONS) {
110
+ expect(exclusion.owner.length, exclusion.id).toBeGreaterThan(20);
111
+ expect(exclusion.reason.length, exclusion.id).toBeGreaterThan(80);
112
+ }
113
+ });
114
+
115
+ it('renders exactly one named separator and its pane for every state', () => {
116
+ for (const state of RESIZE_HANDLE_BINDING_STATES) {
117
+ render(renderResizeHandleState(state));
118
+ expect(separator(state), state.id).toBeTruthy();
119
+ expect(pane(), state.id).toBeTruthy();
120
+ cleanup();
121
+ }
122
+ });
123
+ });
@@ -303,6 +303,9 @@ function persistState(key: string, state: PersistedResizableState): void {
303
303
 
304
304
  /** The released compatibility basis when there is no window to measure. */
305
305
  const SERVER_BASIS = 1200;
306
+
307
+ /** A store that never changes on its own; the snapshot is re-read on render. */
308
+ const noopSubscribe = () => () => {};
306
309
  const DEFAULT_SIZE_FALLBACK = 250;
307
310
  const RESIZABLE_SIZE_GUIDANCE =
308
311
  'Use a non-negative number of pixels, an exact "Npx" string, an exact ' +
@@ -699,6 +702,23 @@ function useSingleResizable(config: UseResizableSingleConfig): ResizableRegion {
699
702
  () => SERVER_BASIS,
700
703
  );
701
704
 
705
+ // The window's extent along the hook's axis, for the REPORTED maximum of an
706
+ // unbounded region (never for clamping). Read through the same store shape
707
+ // so a server-rendered handle hydrates with no maximum and gains the real
708
+ // one on the first client render, instead of a hydration mismatch. It takes
709
+ // no resize subscription: an unbounded pixel region observes nothing
710
+ // (component:Resizable Performance and resources).
711
+ const windowExtent = useSyncExternalStore(
712
+ noopSubscribe,
713
+ () =>
714
+ typeof window === 'undefined'
715
+ ? null
716
+ : direction === 'vertical'
717
+ ? window.innerHeight
718
+ : window.innerWidth,
719
+ () => null,
720
+ );
721
+
702
722
  // With a container, its content box is the basis; without one, the released
703
723
  // viewport basis. Before a supplied container has been measured — the first
704
724
  // render, the server, and any moment it is display:none or detached — the
@@ -1026,6 +1046,29 @@ function useSingleResizable(config: UseResizableSingleConfig): ResizableRegion {
1026
1046
  // percentage bound stays pinned to the container size at grab time.
1027
1047
  const onResizeCancel = releaseGestureBasis;
1028
1048
 
1049
+ // The maximum a handle REPORTS (End uses only a configured maximum). A
1050
+ // configured maximum wins. Otherwise a measured extent stands in — the
1051
+ // container's content box while a percentage bound already observes it, or
1052
+ // the window's extent along the axis — and never drops below the current size, so
1053
+ // `aria-valuenow` can never exceed `aria-valuemax` (a saved, default, or
1054
+ // pre-resize size may already be larger than the window). An unobserved
1055
+ // container reports nothing: measuring it would add an observer to an
1056
+ // atomic pixel path.
1057
+ const measuredBasisForMax = hasContainer
1058
+ ? hasPositiveMeasurement && observeContainerBasis
1059
+ ? containerBasis
1060
+ : null
1061
+ : windowExtent;
1062
+ // Never below the announced value either: a collapsed pane announces the
1063
+ // resolved minimum as its value, so the stand-in floors there as well, and
1064
+ // `aria-valuemax` can never fall under `aria-valuemin`.
1065
+ const effectiveMaxPx =
1066
+ resolvedMax !== Infinity
1067
+ ? resolvedMax
1068
+ : measuredBasisForMax == null
1069
+ ? undefined
1070
+ : Math.max(measuredBasisForMax, isCollapsed ? resolvedMin : size);
1071
+
1029
1072
  const props: ResizableProps = {
1030
1073
  _size: isCollapsed ? 0 : size,
1031
1074
  _isCollapsed: isCollapsed,
@@ -1041,6 +1084,16 @@ function useSingleResizable(config: UseResizableSingleConfig): ResizableRegion {
1041
1084
  _direction: direction,
1042
1085
  _isResizableProps: true,
1043
1086
  };
1087
+ collapseControls.set(props, {collapse, expand});
1088
+ // Without a configured maximum the basis stands in — only when it is a
1089
+ // real measurement (an observed container, or the window), never the
1090
+ // temporary 1200px placeholder (component:Resizable Performance: atomic
1091
+ // pixel paths add no observer, so an unobserved container stays unknown).
1092
+ // The released no-container basis is the window WIDTH on both axes; a
1093
+ // vertical region's reported maximum reads the window height instead.
1094
+ if (effectiveMaxPx != null) {
1095
+ effectiveMaxima.set(props, effectiveMaxPx);
1096
+ }
1044
1097
 
1045
1098
  return {
1046
1099
  size: isCollapsed ? 0 : size,
@@ -1097,6 +1150,48 @@ function useMultiResizable(
1097
1150
  // Public API
1098
1151
  // =============================================================================
1099
1152
 
1153
+ /**
1154
+ * Collapse/expand for a region, keyed by the `ResizableProps` object the hook
1155
+ * returns. A handle's Enter and double-click use them so the pane restores
1156
+ * its previous position (APG window splitter) rather than emulating the
1157
+ * toggle with a resize to the minimum.
1158
+ *
1159
+ * Kept off `ResizableProps` on purpose: that type is exported, so a new field
1160
+ * on it — optional or underscored — is a public delta. This module-private
1161
+ * map and {@link getCollapseControls} are the package's own channel between
1162
+ * the hook and the handle; neither is re-exported.
1163
+ */
1164
+ type CollapseControls = {collapse: () => void; expand: () => void};
1165
+ const collapseControls = new WeakMap<ResizableProps, CollapseControls>();
1166
+
1167
+ /**
1168
+ * The maximum an unbounded region reports as `aria-valuemax`: a measured
1169
+ * extent that stands in for the missing configured maximum — the container's
1170
+ * content box on the active axis while a percentage bound already observes
1171
+ * it, or the window's extent along the axis — floored at the current size
1172
+ * and, while collapsed, at the resolved minimum. The region is never clamped
1173
+ * to it; it is what the separator announces. Kept off the exported
1174
+ * `ResizableProps` for the same reason as the collapse controls;
1175
+ * `getEffectiveMaxPx` is internal.
1176
+ */
1177
+ const effectiveMaxima = new WeakMap<ResizableProps, number>();
1178
+
1179
+ /** The reported maximum for `props`, or `undefined` for a hand-built object. */
1180
+ export function getEffectiveMaxPx(props: ResizableProps): number | undefined {
1181
+ return effectiveMaxima.get(props);
1182
+ }
1183
+
1184
+ /**
1185
+ * The collapse/expand pair the hook registered for `props`, or `undefined`
1186
+ * for a hand-built `ResizableProps` object (which the handle then toggles
1187
+ * with a resize gesture). Internal to the package.
1188
+ */
1189
+ export function getCollapseControls(
1190
+ props: ResizableProps,
1191
+ ): CollapseControls | undefined {
1192
+ return collapseControls.get(props);
1193
+ }
1194
+
1100
1195
  /** Removed keys must fail even when a variable bypasses excess-property checks. */
1101
1196
  type RejectRemovedPixelBounds<Config> = Config extends unknown
1102
1197
  ? Config & {minSizePx?: never; maxSizePx?: never}
@@ -245,9 +245,9 @@ export const docs = {
245
245
  },
246
246
  {
247
247
  name: 'variant',
248
- type: "'input' | 'ghost'",
248
+ type: "'input' | 'secondary' | 'ghost'",
249
249
  description:
250
- 'Visual trigger style. input is the bordered input treatment for forms; ghost is borderless and matches ghost buttons for toolbar usage.',
250
+ 'Visual trigger style. input is the bordered input treatment for forms; secondary matches the secondary buttons of the active theme (borderless and neutral-filled by default) for navs and toolbars; ghost is borderless and transparent, matching ghost buttons for toolbar usage.',
251
251
  default: "'input'",
252
252
  },
253
253
  {
@@ -307,8 +307,9 @@ export const docs = {
307
307
  name: 'statusVariant',
308
308
  type: "'attached' | 'detached' | 'tooltip'",
309
309
  description:
310
- 'How the status message is placed relative to the input. attached overlaps directly below the bordered input and is only valid for the input variant; ghost selectors detach attached status messages by default. Use tooltip for compact toolbar controls.',
311
- default: "'attached' for input selectors; 'detached' for ghost selectors",
310
+ 'How the status message is placed relative to the input. attached overlaps directly below the bordered input and is only valid for the input variant; secondary and ghost selectors detach attached status messages by default. Use tooltip for compact toolbar controls.',
311
+ default:
312
+ "'attached' for input selectors; 'detached' for secondary and ghost selectors",
312
313
  },
313
314
  {
314
315
  name: 'renderOption',
@@ -439,7 +440,7 @@ export const docs = {
439
440
  {
440
441
  guidance: true,
441
442
  description:
442
- 'Use variant="ghost" when a selector sits in a toolbar with ghost buttons. If validation status is needed there, prefer statusVariant="tooltip" so the toolbar height stays compact.',
443
+ 'Use variant="secondary" when a selector sits in a nav or toolbar beside secondary buttons or a segmented control, so it shares their treatment instead of reading as a form field. Use variant="ghost" when a selector sits in a toolbar with ghost buttons. If validation status is needed there, prefer statusVariant="tooltip" so the toolbar height stays compact.',
443
444
  },
444
445
  {
445
446
  guidance: true,
@@ -576,7 +577,7 @@ export const docsDense = {
576
577
  {
577
578
  guidance: true,
578
579
  description:
579
- 'Use variant="ghost" in toolbars with ghost buttons; prefer statusVariant="tooltip" for compact validation status.',
580
+ 'Use variant="secondary" in navs/toolbars beside secondary buttons; use variant="ghost" in toolbars with ghost buttons; prefer statusVariant="tooltip" for compact validation status.',
580
581
  },
581
582
  {
582
583
  guidance: false,
@@ -16,6 +16,8 @@ verified_by:
16
16
  packages/core/src/Selector/Selector.source-build.test.mjs,
17
17
  packages/core/src/Selector/__tests__/Selector.listbox.a11y.test.tsx,
18
18
  packages/core/src/Selector/__tests__/Listbox.a11y.chromium.spec.ts,
19
+ packages/core/src/Selector/__tests__/Selector.combobox.a11y.test.tsx,
20
+ packages/core/src/Selector/__tests__/Selector.combobox.a11y.chromium.spec.ts,
19
21
  apps/storybook/stories/Selector.stories.tsx,
20
22
  .github/scripts/story-play-guard.js,
21
23
  ]
@@ -60,6 +62,8 @@ connection between the closed trigger and its selection surface.
60
62
  - `isReadOnly` is additive and defaults to `false`. It preserves the selected
61
63
  value, focus, and form participation while removing selection-surface and
62
64
  editing affordances. `isDisabled` takes precedence when both are set.
65
+ - `secondary` is an additive trigger variant. `input` remains the default;
66
+ existing `input` and `ghost` callers keep their released behavior.
63
67
  - `spec:AST-004/DEC-1` governs the state-derived indicator-space behavior in FR3.
64
68
  - 0.7.0 removes the `selector-clear-icon` alias; the shared clear glyph remains
65
69
  available through `input-clear-icon`.
@@ -122,15 +126,15 @@ connection between the closed trigger and its selection surface.
122
126
  This table names semantic concepts reviewers need. Prop syntax, complete defaults,
123
127
  and examples remain in `Selector.doc.mjs`.
124
128
 
125
- | Concept | Closed values or states | Meaning | Availability by variant/orientation/state | Default | Owner | Stability | Invalid-value behavior |
126
- | ---------------------- | -------------------------------------- | -------------------------------------------------------- | ----------------------------------------- | ---------- | -------- | --------- | ------------------------------- |
127
- | trigger variant | `input`, `ghost` | Form-field or toolbar presentation | All trigger states | `input` | Selector | released | TypeScript rejects other values |
128
- | size | `sm`, `md`, `lg` | Trigger and option-row density | All presentations | `md` | Selector | released | TypeScript rejects other values |
129
- | selected-mark position | `start`, `end` | Logical edge containing a rendered selection mark | Every option row | `end` | Selector | released | TypeScript rejects other values |
130
- | presentation | `popover`, `bottom-sheet`, `adaptive` | Anchored pointer surface or modal compact-touch surface | All trigger variants | `adaptive` | Selector | released | TypeScript rejects other values |
131
- | popup semantics | `listbox`; modal dialog containing one | Semantics follow the active presentation | Popover; bottom sheet | `listbox` | Selector | released | No separate role prop is public |
132
- | option-row state | `selected`, `disabled` | Stable theming state on each option row | Every rendered option | neither | Selector | released | Unknown states are not emitted |
133
- | read-only state | `false`, `true` | Preserves and submits value without selection affordance | Closed trigger | `false` | Caller | additive | Boolean normalization |
129
+ | Concept | Closed values or states | Meaning | Availability by variant/orientation/state | Default | Owner | Stability | Invalid-value behavior |
130
+ | ---------------------- | -------------------------------------- | -------------------------------------------------------- | ----------------------------------------- | ---------- | -------- | ------------------------------ | ------------------------------- |
131
+ | trigger variant | `input`, `secondary`, `ghost` | Form-field or button-aligned toolbar presentation | All trigger states | `input` | Selector | released; `secondary` additive | TypeScript rejects other values |
132
+ | size | `sm`, `md`, `lg` | Trigger and option-row density | All presentations | `md` | Selector | released | TypeScript rejects other values |
133
+ | selected-mark position | `start`, `end` | Logical edge containing a rendered selection mark | Every option row | `end` | Selector | released | TypeScript rejects other values |
134
+ | presentation | `popover`, `bottom-sheet`, `adaptive` | Anchored pointer surface or modal compact-touch surface | All trigger variants | `adaptive` | Selector | released | TypeScript rejects other values |
135
+ | popup semantics | `listbox`; modal dialog containing one | Semantics follow the active presentation | Popover; bottom sheet | `listbox` | Selector | released | No separate role prop is public |
136
+ | option-row state | `selected`, `disabled` | Stable theming state on each option row | Every rendered option | neither | Selector | released | Unknown states are not emitted |
137
+ | read-only state | `false`, `true` | Preserves and submits value without selection affordance | Closed trigger | `false` | Caller | additive | Boolean normalization |
134
138
 
135
139
  ## Behavioral and layout contract
136
140
 
@@ -217,14 +221,22 @@ These requirements describe shipped behavior on current `main`.
217
221
 
218
222
  No current design spec is linked.
219
223
 
220
- | Anatomy or state | Current representation requirement | Representation authority | Hierarchy role | Component contract |
221
- | -------------------------------- | -------------------------------------------------------------------------------------------------- | -------------------------- | ----------------------- | ------------------ |
222
- | selected mark and option spacing | Empty resolved marks collapse; visible marks retain space, so row label geometry may vary by state | `spec:AST-004/DEC-1` | supporting | FR3 |
223
- | input versus ghost trigger | none recorded | existing released behavior | form or toolbar control | Public concepts |
224
+ | Anatomy or state | Current representation requirement | Representation authority | Hierarchy role | Component contract |
225
+ | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | ------------------------ | --------------------------- | ------------------ |
226
+ | selected mark and option spacing | Empty resolved marks collapse; visible marks retain space, so row label geometry may vary by state | `spec:AST-004/DEC-1` | supporting | FR3 |
227
+ | trigger variants | `input` reads as a form field; `secondary` matches adjacent secondary `Button`s; `ghost` matches adjacent ghost `Button`s | `component:Selector/DD1` | form or peer action control | Public concepts |
224
228
 
225
229
  The first row implements the state-derived spacing decision in
226
230
  `spec:AST-004/DEC-1`.
227
231
 
232
+ ### Design decisions
233
+
234
+ <!-- design-decisions:v1 -->
235
+
236
+ | ID | Decision | Intent or reason | Applies to | Allowed variation |
237
+ | --- | ------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
238
+ | DD1 | A `secondary` Selector matches the visual role of adjacent secondary `Button`s. | A mixed toolbar or navigation area reads as one action hierarchy instead of making the Selector look like a form field or a ghost action. | The secondary trigger at rest and through its states | Themes may choose exact tokens while preserving parity with their secondary `Button` treatment. |
239
+
228
240
  ### Theming anatomy
229
241
 
230
242
  <!-- anatomy-theming:v1 -->
@@ -319,17 +331,18 @@ new theming target.
319
331
 
320
332
  ## Verification map
321
333
 
322
- | Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
323
- | --------------------- | -------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
324
- | FR1, AR2, AR3 | `Selector.test.tsx` selection, focus, and keyboard suites | closed/open, search/non-search, disabled option | Removing selection wiring, focus movement, or keyboard behavior fails the named interaction tests | `audit:Selector/behavior` |
325
- | FR2 | placement and selected-item geometry tests | default, explicit, RTL, transformed entry | Using the wrong positioning model fails the expected position-area or margin | `audit:Selector/behavior` |
326
- | FR3, AV1 | Focused `Selector.test.tsx` computed-display checks plus guarded Chromium Storybook matrix and stable visual stories | popover/bottom sheet, narrow/wide, start/end, LTR/RTL, selected/unselected, check/radio | Empty output reserves width, visible output collapses, logical placement flips incorrectly, or row content overflows | `audit:Selector/design-rendered` |
327
- | FR4, AR1, AR2 | presentation tests plus `aria-haspopup` source review | pointer, compact coarse pointer, search/non-search | Wrong Popover/dialog roles or focus destinations fail tests; `aria-haspopup` values require source/a11y review | `audit:Selector/accessibility` |
328
- | AR1, AV2 | `Selector.listbox.a11y.test.tsx` and `Listbox.a11y.chromium.spec.ts` against the shared Listbox contract | popover/sheet, flat/grouped, selected/unselected, disabled, search, loading, custom RTL | A new or wider loss of role, listbox/option name, state, or ownership gates; the exact unnamed no-search sheet state remains known debt | `audit:Selector/accessibility` |
329
- | FR5 | loading, empty-state, and live-region tests | empty options, unmatched search, loading | Empty/no-results output appears or is announced while loading | `audit:Selector/behavior` |
330
- | FR6, AR4 | read-only interaction, form, ARIA, and theme-state tests | search/non-search, clearable, open→read-only, disabled precedence | A value changes, popup or edit affordance remains, form value disappears, or read-only semantics are absent | `audit:Selector/accessibility` |
331
- | FR7 | `Selector.test.tsx` press model suite | finger release over another option, finger/mouse release outside, listbox marker | The press option is selected, the listbox takes focus, a finger release outside closes the list, or the stray click selects | `audit:Selector/behavior` |
332
- | source-build contract | `Selector.source-build.test.mjs` | package source compiled by consumer Babel | Moving evaluated StyleX values outside the supported source form fails compilation | `audit:Selector/code-health` |
334
+ | Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
335
+ | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
336
+ | FR1, AR2, AR3 | `Selector.test.tsx` selection, focus, and keyboard suites | closed/open, search/non-search, disabled option | Removing selection wiring, focus movement, or keyboard behavior fails the named interaction tests | `audit:Selector/behavior` |
337
+ | FR2 | placement and selected-item geometry tests | default, explicit, RTL, transformed entry | Using the wrong positioning model fails the expected position-area or margin | `audit:Selector/behavior` |
338
+ | FR3, AV1 | Focused `Selector.test.tsx` computed-display checks plus guarded Chromium Storybook matrix and stable visual stories | popover/bottom sheet, narrow/wide, start/end, LTR/RTL, selected/unselected, check/radio | Empty output reserves width, visible output collapses, logical placement flips incorrectly, or row content overflows | `audit:Selector/design-rendered` |
339
+ | FR4, AR1, AR2 | presentation tests plus `aria-haspopup` source review | pointer, compact coarse pointer, search/non-search | Wrong Popover/dialog roles or focus destinations fail tests; `aria-haspopup` values require source/a11y review | `audit:Selector/accessibility` |
340
+ | AR1, AV2 | `Selector.listbox.a11y.test.tsx` and `Listbox.a11y.chromium.spec.ts` against the shared Listbox contract | popover/sheet, flat/grouped, selected/unselected, disabled, search, loading, custom RTL | A new or wider loss of role, listbox/option name, state, or ownership gates; the exact unnamed no-search sheet state remains known debt | `audit:Selector/accessibility` |
341
+ | FR5, FR6, AR1, AR2 (anchored), AR4 | `Selector.combobox.a11y.test.tsx` and `Selector.combobox.a11y.chromium.spec.ts` against the shared Combobox contract | closed, open with active option, read-only, busy, bottom-sheet open, search input with active option | The trigger or search input loses its role/name/state or popup kind, its open popup or active option relationship breaks, or read-only exposes a selection surface; the bottom-sheet trigger's `aria-controls` naming the inner listbox remains exact known debt | `audit:Selector/accessibility` |
342
+ | FR5 | loading, empty-state, and live-region tests | empty options, unmatched search, loading | Empty/no-results output appears or is announced while loading | `audit:Selector/behavior` |
343
+ | FR6, AR4 | read-only interaction, form, ARIA, and theme-state tests | search/non-search, clearable, open→read-only, disabled precedence | A value changes, popup or edit affordance remains, form value disappears, or read-only semantics are absent | `audit:Selector/accessibility` |
344
+ | FR7 | `Selector.test.tsx` press model suite | finger release over another option, finger/mouse release outside, listbox marker | The press option is selected, the listbox takes focus, a finger release outside closes the list, or the stray click selects | `audit:Selector/behavior` |
345
+ | source-build contract | `Selector.source-build.test.mjs` | package source compiled by consumer Babel | Moving evaluated StyleX values outside the supported source form fails compilation | `audit:Selector/code-health` |
333
346
 
334
347
  ## Decision log
335
348