@astryxdesign/core 0.6.2 → 0.6.3-canary.0949cb1

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 (384) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/dist/BottomSheet/BottomSheet.d.ts +1 -1
  3. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  4. package/dist/BottomSheet/BottomSheet.js +3 -1
  5. package/dist/BottomSheet/BottomSheetPanel.d.ts +7 -5
  6. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
  7. package/dist/BottomSheet/BottomSheetPanel.js +56 -19
  8. package/dist/Chat/ChatComposer.d.ts.map +1 -1
  9. package/dist/Chat/ChatComposer.js +10 -5
  10. package/dist/Chat/ChatComposerDrawer.d.ts +19 -5
  11. package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
  12. package/dist/Chat/ChatComposerDrawer.js +48 -23
  13. package/dist/Chat/ChatComposerInput.d.ts +11 -3
  14. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  15. package/dist/Chat/ChatComposerInput.js +63 -16
  16. package/dist/Chat/ChatDictationButton.d.ts +3 -2
  17. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  18. package/dist/Chat/ChatDictationButton.js +6 -4
  19. package/dist/Chat/ChatSendButton.js +1 -1
  20. package/dist/Chat/index.d.ts +1 -1
  21. package/dist/Chat/index.d.ts.map +1 -1
  22. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  23. package/dist/CheckboxInput/CheckboxInput.js +12 -2
  24. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  25. package/dist/Collapsible/Collapsible.js +6 -1
  26. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  27. package/dist/CommandPalette/CommandPaletteInput.js +1 -1
  28. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  29. package/dist/ComplexSelector/ComplexSelector.js +1 -1
  30. package/dist/DateInput/DateInput.d.ts.map +1 -1
  31. package/dist/DateInput/DateInput.js +4 -4
  32. package/dist/DateInput/NativeDateField.d.ts.map +1 -1
  33. package/dist/DateInput/NativeDateField.js +16 -16
  34. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  35. package/dist/DateInput/TouchDateField.js +2 -2
  36. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  37. package/dist/DateRangeInput/DateRangeInput.js +4 -4
  38. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  39. package/dist/DateTimeInput/DateTimeInput.js +8 -8
  40. package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
  41. package/dist/DateTimeInput/TouchDateTimeField.js +4 -4
  42. package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts +9 -3
  43. package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts.map +1 -1
  44. package/dist/DateTimeInput/nativePickerSegmentStyles.js +3 -3
  45. package/dist/Dialog/DialogHeader.d.ts +8 -1
  46. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  47. package/dist/Dialog/DialogHeader.js +10 -1
  48. package/dist/Field/InputClearButton.d.ts +4 -2
  49. package/dist/Field/InputClearButton.d.ts.map +1 -1
  50. package/dist/Field/InputClearButton.js +4 -2
  51. package/dist/Field/PanelSearchInput.d.ts.map +1 -1
  52. package/dist/Field/PanelSearchInput.js +1 -1
  53. package/dist/FileInput/FileInput.d.ts.map +1 -1
  54. package/dist/FileInput/FileInput.js +7 -7
  55. package/dist/Kbd/Kbd.d.ts +5 -3
  56. package/dist/Kbd/Kbd.d.ts.map +1 -1
  57. package/dist/Kbd/Kbd.js +36 -42
  58. package/dist/Link/Link.d.ts.map +1 -1
  59. package/dist/Link/Link.js +6 -2
  60. package/dist/Markdown/Markdown.d.ts +8 -2
  61. package/dist/Markdown/Markdown.d.ts.map +1 -1
  62. package/dist/Markdown/Markdown.fr23.bench.d.ts +2 -0
  63. package/dist/Markdown/Markdown.fr23.bench.d.ts.map +1 -0
  64. package/dist/Markdown/Markdown.fr23.bench.js +150 -0
  65. package/dist/Markdown/Markdown.fr23.sampling.d.ts +2 -0
  66. package/dist/Markdown/Markdown.fr23.sampling.d.ts.map +1 -0
  67. package/dist/Markdown/Markdown.fr23.sampling.js +43 -0
  68. package/dist/Markdown/Markdown.js +262 -109
  69. package/dist/Markdown/ast.d.ts +162 -0
  70. package/dist/Markdown/ast.d.ts.map +1 -0
  71. package/dist/Markdown/ast.js +74 -0
  72. package/dist/Markdown/index.d.ts +5 -3
  73. package/dist/Markdown/index.d.ts.map +1 -1
  74. package/dist/Markdown/index.js +3 -2
  75. package/dist/Markdown/parser/index.d.ts +10 -0
  76. package/dist/Markdown/parser/index.d.ts.map +1 -0
  77. package/dist/Markdown/parser/index.js +10 -0
  78. package/dist/Markdown/parser.d.ts +126 -58
  79. package/dist/Markdown/parser.d.ts.map +1 -1
  80. package/dist/Markdown/parser.js +716 -167
  81. package/dist/Markdown/plugins/frontmatter.d.ts +32 -0
  82. package/dist/Markdown/plugins/frontmatter.d.ts.map +1 -0
  83. package/dist/Markdown/plugins/frontmatter.js +132 -0
  84. package/dist/Markdown/plugins/index.d.ts +16 -0
  85. package/dist/Markdown/plugins/index.d.ts.map +1 -0
  86. package/dist/Markdown/plugins/index.js +13 -0
  87. package/dist/Markdown/plugins/protocol.d.ts +191 -0
  88. package/dist/Markdown/plugins/protocol.d.ts.map +1 -0
  89. package/dist/Markdown/plugins/protocol.js +957 -0
  90. package/dist/Markdown/plugins/semanticFence.d.ts +36 -0
  91. package/dist/Markdown/plugins/semanticFence.d.ts.map +1 -0
  92. package/dist/Markdown/plugins/semanticFence.js +213 -0
  93. package/dist/Markdown/plugins/sourceDecoration.d.ts +76 -0
  94. package/dist/Markdown/plugins/sourceDecoration.d.ts.map +1 -0
  95. package/dist/Markdown/plugins/sourceDecoration.js +393 -0
  96. package/dist/Markdown/plugins/textTransform.d.ts +30 -0
  97. package/dist/Markdown/plugins/textTransform.d.ts.map +1 -0
  98. package/dist/Markdown/plugins/textTransform.js +374 -0
  99. package/dist/Markdown/remark.d.ts +196 -0
  100. package/dist/Markdown/remark.d.ts.map +1 -0
  101. package/dist/Markdown/remark.js +1062 -0
  102. package/dist/Markdown/url.d.ts +4 -0
  103. package/dist/Markdown/url.d.ts.map +1 -0
  104. package/dist/Markdown/url.js +25 -0
  105. package/dist/Markdown/utils.d.ts +4 -2
  106. package/dist/Markdown/utils.d.ts.map +1 -1
  107. package/dist/Markdown/utils.js +2 -1
  108. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  109. package/dist/NumberInput/NumberInput.js +4 -4
  110. package/dist/Outline/index.d.ts +1 -0
  111. package/dist/Outline/index.d.ts.map +1 -1
  112. package/dist/Outline/parseOutlineFromMarkdown.d.ts +7 -1
  113. package/dist/Outline/parseOutlineFromMarkdown.d.ts.map +1 -1
  114. package/dist/Outline/parseOutlineFromMarkdown.js +14 -8
  115. package/dist/Outline/useOutlineFromMarkdown.d.ts +3 -1
  116. package/dist/Outline/useOutlineFromMarkdown.d.ts.map +1 -1
  117. package/dist/Outline/useOutlineFromMarkdown.js +8 -3
  118. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  119. package/dist/PowerSearch/PowerSearchEditPopover.js +46 -30
  120. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  121. package/dist/ProgressBar/ProgressBar.js +36 -31
  122. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  123. package/dist/RadioList/RadioListItem.js +13 -1
  124. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  125. package/dist/SegmentedControl/SegmentedControlItem.js +5 -5
  126. package/dist/Selector/Selector.d.ts +9 -7
  127. package/dist/Selector/Selector.d.ts.map +1 -1
  128. package/dist/Selector/Selector.js +7 -5
  129. package/dist/SideNav/SideNav.d.ts +2 -1
  130. package/dist/SideNav/SideNav.d.ts.map +1 -1
  131. package/dist/SideNav/SideNav.js +9 -3
  132. package/dist/Slider/Slider.d.ts.map +1 -1
  133. package/dist/Slider/Slider.js +28 -12
  134. package/dist/Spinner/Spinner.d.ts.map +1 -1
  135. package/dist/Spinner/Spinner.js +23 -7
  136. package/dist/Switch/Switch.d.ts.map +1 -1
  137. package/dist/Switch/Switch.js +11 -0
  138. package/dist/TabList/Tab.d.ts +1 -1
  139. package/dist/TabList/Tab.d.ts.map +1 -1
  140. package/dist/TabList/Tab.js +20 -7
  141. package/dist/Table/Table.d.ts +1 -0
  142. package/dist/Table/Table.d.ts.map +1 -1
  143. package/dist/Table/Table.js +29 -13
  144. package/dist/TextArea/TextArea.d.ts.map +1 -1
  145. package/dist/TextArea/TextArea.js +1 -1
  146. package/dist/TextInput/TextInput.d.ts.map +1 -1
  147. package/dist/TextInput/TextInput.js +2 -2
  148. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  149. package/dist/TimeInput/TimeInput.js +4 -4
  150. package/dist/ToggleButton/ToggleButton.d.ts +9 -6
  151. package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
  152. package/dist/ToggleButton/ToggleButton.js +15 -27
  153. package/dist/TreeList/TreeList.d.ts.map +1 -1
  154. package/dist/TreeList/TreeList.js +3 -0
  155. package/dist/TreeList/TreeListItem.d.ts +6 -1
  156. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  157. package/dist/TreeList/TreeListItem.js +12 -2
  158. package/dist/TreeList/TreeListTypes.d.ts +8 -1
  159. package/dist/TreeList/TreeListTypes.d.ts.map +1 -1
  160. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  161. package/dist/Typeahead/BaseTypeahead.js +16 -7
  162. package/dist/astryx.css +18 -7
  163. package/dist/hooks/scrollKeyboardDelegation.d.ts +3 -0
  164. package/dist/hooks/scrollKeyboardDelegation.d.ts.map +1 -0
  165. package/dist/hooks/scrollKeyboardDelegation.js +146 -0
  166. package/dist/hooks/useScrollableArea.d.ts +6 -2
  167. package/dist/hooks/useScrollableArea.d.ts.map +1 -1
  168. package/dist/hooks/useScrollableArea.js +17 -5
  169. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  170. package/dist/theme/generateThemeRules.js +10 -0
  171. package/dist/utils/interactionOverlay.stylex.d.ts +8 -0
  172. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
  173. package/dist/utils/interactionOverlay.stylex.js +9 -0
  174. package/locales/af-ZA.json +530 -1
  175. package/locales/ar-SA.json +490 -1
  176. package/locales/ca-ES.json +514 -1
  177. package/locales/cs-CZ.json +498 -1
  178. package/locales/da-DK.json +522 -1
  179. package/locales/de-DE.json +522 -1
  180. package/locales/el-GR.json +498 -1
  181. package/locales/es-ES.json +510 -1
  182. package/locales/fi-FI.json +498 -1
  183. package/locales/fr-FR.json +534 -1
  184. package/locales/he-IL.json +498 -1
  185. package/locales/hu-HU.json +498 -1
  186. package/locales/it-IT.json +510 -1
  187. package/locales/ja-JP.json +490 -1
  188. package/locales/ko-KR.json +498 -1
  189. package/locales/nl-NL.json +534 -1
  190. package/locales/no-NO.json +510 -1
  191. package/locales/pl-PL.json +506 -1
  192. package/locales/pt-BR.json +506 -1
  193. package/locales/pt-PT.json +506 -1
  194. package/locales/ro-RO.json +506 -1
  195. package/locales/ru-RU.json +498 -1
  196. package/locales/sr-SP.json +498 -1
  197. package/locales/sv-SE.json +502 -1
  198. package/locales/tr-TR.json +498 -1
  199. package/locales/uk-UA.json +498 -1
  200. package/locales/vi-VN.json +502 -1
  201. package/locales/zh-CN.json +490 -1
  202. package/locales/zh-TW.json +490 -1
  203. package/package.json +19 -4
  204. package/src/BottomSheet/BottomSheet.doc.mjs +8 -1
  205. package/src/BottomSheet/BottomSheet.spec.md +46 -20
  206. package/src/BottomSheet/BottomSheet.test.tsx +6 -3
  207. package/src/BottomSheet/BottomSheet.tsx +3 -1
  208. package/src/BottomSheet/BottomSheetKeyboard.test.tsx +195 -0
  209. package/src/BottomSheet/BottomSheetPanel.test.tsx +11 -1
  210. package/src/BottomSheet/BottomSheetPanel.tsx +49 -16
  211. package/src/BottomSheet/__tests__/BottomSheetKeyboard.a11y.browser.spec.ts +344 -0
  212. package/src/Button/__tests__/Button.a11y.chromium.spec.ts +17 -1
  213. package/src/Button/__tests__/Button.a11y.known-failures.ts +0 -29
  214. package/src/Button/__tests__/Button.a11y.renders.tsx +9 -2
  215. package/src/Button/__tests__/Button.a11y.states.ts +9 -0
  216. package/src/Chat/ChatComposer.doc.mjs +14 -0
  217. package/src/Chat/ChatComposer.spec.md +230 -0
  218. package/src/Chat/ChatComposer.test.tsx +57 -0
  219. package/src/Chat/ChatComposer.tsx +21 -9
  220. package/src/Chat/ChatComposerDrawer.doc.mjs +63 -5
  221. package/src/Chat/ChatComposerDrawer.spec.md +267 -0
  222. package/src/Chat/ChatComposerDrawer.test.tsx +81 -12
  223. package/src/Chat/ChatComposerDrawer.tsx +38 -9
  224. package/src/Chat/ChatComposerInput.doc.mjs +114 -26
  225. package/src/Chat/ChatComposerInput.spec.md +185 -0
  226. package/src/Chat/ChatComposerInput.test.tsx +113 -3
  227. package/src/Chat/ChatComposerInput.tsx +78 -13
  228. package/src/Chat/ChatComposerTokenElement.spec.md +152 -0
  229. package/src/Chat/ChatComposerTokenElement.test.tsx +85 -0
  230. package/src/Chat/ChatDictationButton.doc.mjs +3 -3
  231. package/src/Chat/ChatDictationButton.spec.md +160 -0
  232. package/src/Chat/ChatDictationButton.test.tsx +92 -27
  233. package/src/Chat/ChatDictationButton.tsx +8 -6
  234. package/src/Chat/ChatSendButton.test.tsx +1 -4
  235. package/src/Chat/ChatSendButton.tsx +1 -1
  236. package/src/Chat/index.ts +1 -0
  237. package/src/CheckboxInput/CheckboxInput.doc.mjs +11 -0
  238. package/src/CheckboxInput/CheckboxInput.test.tsx +34 -0
  239. package/src/CheckboxInput/CheckboxInput.tsx +21 -1
  240. package/src/ClickableCard/ClickableCard.test.tsx +102 -5
  241. package/src/Collapsible/Collapsible.doc.mjs +11 -0
  242. package/src/Collapsible/Collapsible.test.tsx +21 -0
  243. package/src/Collapsible/Collapsible.tsx +5 -0
  244. package/src/CommandPalette/CommandPaletteInput.tsx +6 -1
  245. package/src/ComplexSelector/ComplexSelector.tsx +6 -1
  246. package/src/DateInput/DateInput.tsx +6 -1
  247. package/src/DateInput/NativeDateField.tsx +24 -8
  248. package/src/DateInput/TouchDateField.tsx +6 -2
  249. package/src/DateRangeInput/DateRangeInput.tsx +6 -1
  250. package/src/DateTimeInput/DateTimeInput.tsx +6 -1
  251. package/src/DateTimeInput/TouchDateTimeField.tsx +6 -1
  252. package/src/DateTimeInput/nativePickerSegmentStyles.ts +24 -8
  253. package/src/Dialog/DialogHeader.doc.mjs +12 -0
  254. package/src/Dialog/DialogHeader.test.tsx +97 -0
  255. package/src/Dialog/DialogHeader.tsx +25 -3
  256. package/src/Dialog/modules/DialogHeader.spec.md +75 -38
  257. package/src/Field/InputClearButton.test.tsx +17 -3
  258. package/src/Field/InputClearButton.tsx +5 -2
  259. package/src/Field/PanelSearchInput.tsx +5 -2
  260. package/src/FieldStatus/__tests__/StatusMessage.a11y.states.ts +1 -1
  261. package/src/FileInput/FileInput.tsx +11 -2
  262. package/src/Kbd/Kbd.doc.mjs +3 -3
  263. package/src/Kbd/Kbd.test.tsx +57 -1
  264. package/src/Kbd/Kbd.tsx +57 -37
  265. package/src/Layout/LayoutFooter.doc.mjs +17 -0
  266. package/src/Link/Link.doc.mjs +11 -0
  267. package/src/Link/Link.test.tsx +24 -0
  268. package/src/Link/Link.tsx +5 -0
  269. package/src/List/List.spec.md +200 -0
  270. package/src/Markdown/Markdown.doc.mjs +272 -0
  271. package/src/Markdown/Markdown.fr23.bench.ts +174 -0
  272. package/src/Markdown/Markdown.fr23.perf.test.ts +249 -0
  273. package/src/Markdown/Markdown.fr23.sampling.ts +49 -0
  274. package/src/Markdown/Markdown.helpers.perf.test.ts +489 -0
  275. package/src/Markdown/Markdown.public.test.ts +126 -3
  276. package/src/Markdown/Markdown.spec.md +197 -44
  277. package/src/Markdown/Markdown.test.tsx +11 -0
  278. package/src/Markdown/Markdown.tsx +414 -135
  279. package/src/Markdown/ast.test.ts +307 -0
  280. package/src/Markdown/ast.ts +337 -0
  281. package/src/Markdown/incremental.test.ts +12 -0
  282. package/src/Markdown/index.ts +37 -1
  283. package/src/Markdown/modules/remark.spec.md +269 -0
  284. package/src/Markdown/parser/index.ts +64 -0
  285. package/src/Markdown/parser.public.test.ts +103 -0
  286. package/src/Markdown/parser.ts +1180 -235
  287. package/src/Markdown/plugins/frontmatter.test.tsx +125 -0
  288. package/src/Markdown/plugins/frontmatter.ts +198 -0
  289. package/src/Markdown/plugins/index.ts +53 -0
  290. package/src/Markdown/plugins/protocol.test.tsx +1022 -0
  291. package/src/Markdown/plugins/protocol.ts +1618 -0
  292. package/src/Markdown/plugins/semanticFence.test.tsx +546 -0
  293. package/src/Markdown/plugins/semanticFence.ts +424 -0
  294. package/src/Markdown/plugins/sourceDecoration.test.tsx +799 -0
  295. package/src/Markdown/plugins/sourceDecoration.ts +539 -0
  296. package/src/Markdown/plugins/textTransform.test.ts +467 -0
  297. package/src/Markdown/plugins/textTransform.ts +554 -0
  298. package/src/Markdown/remark.test.tsx +1877 -0
  299. package/src/Markdown/remark.ts +1574 -0
  300. package/src/Markdown/url.ts +30 -0
  301. package/src/Markdown/utils.ts +13 -1
  302. package/src/MultiSelector/MultiSelector.test.tsx +1 -35
  303. package/src/MultiSelector/__tests__/MultiSelector.listbox.a11y.test.tsx +128 -0
  304. package/src/NumberInput/NumberInput.tsx +6 -1
  305. package/src/Outline/Outline.doc.mjs +7 -5
  306. package/src/Outline/Outline.spec.md +1 -1
  307. package/src/Outline/index.ts +1 -0
  308. package/src/Outline/modules/parseOutlineFromMarkdown.spec.md +142 -0
  309. package/src/Outline/parseOutlineFromMarkdown.ts +40 -10
  310. package/src/Outline/useOutlineFromMarkdown.ts +15 -3
  311. package/src/PowerSearch/PowerSearch.doc.mjs +2 -2
  312. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +150 -1
  313. package/src/PowerSearch/PowerSearchEditPopover.tsx +51 -28
  314. package/src/ProgressBar/ProgressBar.test.tsx +29 -11
  315. package/src/ProgressBar/ProgressBar.tsx +59 -72
  316. package/src/RadioList/RadioList.doc.mjs +11 -0
  317. package/src/RadioList/RadioList.test.tsx +32 -0
  318. package/src/RadioList/RadioListItem.tsx +25 -1
  319. package/src/ScrollableArea/modules/useScrollableArea.spec.md +50 -22
  320. package/src/SegmentedControl/SegmentedControl.doc.mjs +2 -2
  321. package/src/SegmentedControl/SegmentedControl.test.tsx +31 -0
  322. package/src/SegmentedControl/SegmentedControlItem.tsx +6 -9
  323. package/src/Selector/Selector.doc.mjs +2 -2
  324. package/src/Selector/Selector.spec.md +51 -49
  325. package/src/Selector/Selector.test.tsx +61 -55
  326. package/src/Selector/Selector.tsx +23 -14
  327. package/src/Selector/__tests__/Listbox.a11y.chromium.spec.ts +130 -0
  328. package/src/Selector/__tests__/Listbox.a11y.dom.ts +38 -0
  329. package/src/Selector/__tests__/Listbox.a11y.inventory.test.ts +63 -0
  330. package/src/Selector/__tests__/Listbox.a11y.known-failures.ts +37 -0
  331. package/src/Selector/__tests__/Listbox.a11y.states.ts +232 -0
  332. package/src/Selector/__tests__/Selector.listbox.a11y.test.tsx +121 -0
  333. package/src/SideNav/SideNav.doc.mjs +1 -1
  334. package/src/SideNav/SideNav.test.tsx +10 -0
  335. package/src/SideNav/SideNav.tsx +14 -2
  336. package/src/Slider/Slider.doc.mjs +17 -3
  337. package/src/Slider/Slider.test.tsx +221 -0
  338. package/src/Slider/Slider.tsx +40 -9
  339. package/src/Spinner/Spinner.test.tsx +4 -0
  340. package/src/Spinner/Spinner.tsx +31 -18
  341. package/src/Switch/Switch.doc.mjs +11 -0
  342. package/src/Switch/Switch.test.tsx +16 -0
  343. package/src/Switch/Switch.tsx +28 -0
  344. package/src/TabList/Tab.tsx +35 -7
  345. package/src/TabList/TabList.doc.mjs +11 -0
  346. package/src/TabList/TabList.spec.md +204 -0
  347. package/src/TabList/TabList.test.tsx +66 -0
  348. package/src/TabList/__tests__/Tabs.a11y.known-failures.ts +1 -34
  349. package/src/Table/Table.doc.mjs +1 -1
  350. package/src/Table/Table.spec.md +54 -40
  351. package/src/Table/Table.test.tsx +83 -10
  352. package/src/Table/Table.tsx +30 -22
  353. package/src/Table/__tests__/TableScroll.a11y.chromium.spec.ts +137 -0
  354. package/src/TextArea/TextArea.tsx +6 -1
  355. package/src/TextInput/TextInput.test.tsx +20 -1
  356. package/src/TextInput/TextInput.tsx +6 -1
  357. package/src/TimeInput/TimeInput.tsx +6 -1
  358. package/src/ToggleButton/ToggleButton.doc.mjs +3 -3
  359. package/src/ToggleButton/ToggleButton.test.tsx +299 -4
  360. package/src/ToggleButton/ToggleButton.tsx +26 -33
  361. package/src/ToggleButton/ToggleButtonGroup.doc.mjs +3 -3
  362. package/src/ToggleButton/__tests__/ToggleButton.a11y.chromium.spec.ts +209 -0
  363. package/src/Tokenizer/Tokenizer.spec.md +142 -75
  364. package/src/TreeList/TreeList.doc.mjs +3 -3
  365. package/src/TreeList/TreeList.spec.md +123 -75
  366. package/src/TreeList/TreeList.test.tsx +29 -0
  367. package/src/TreeList/TreeList.tsx +3 -0
  368. package/src/TreeList/TreeListItem.tsx +15 -1
  369. package/src/TreeList/TreeListTypes.ts +11 -1
  370. package/src/Typeahead/BaseTypeahead.spec.md +4 -3
  371. package/src/Typeahead/BaseTypeahead.tsx +21 -7
  372. package/src/Typeahead/Typeahead.test.tsx +53 -0
  373. package/src/__tests__/PressedState.a11y.chromium.spec.ts +813 -0
  374. package/src/__tests__/pressState.ts +93 -0
  375. package/src/hooks/scrollKeyboardDelegation.test.ts +155 -0
  376. package/src/hooks/scrollKeyboardDelegation.ts +233 -0
  377. package/src/hooks/useScrollableArea.doc.mjs +15 -3
  378. package/src/hooks/useScrollableArea.test.tsx +59 -1
  379. package/src/hooks/useScrollableArea.ts +34 -10
  380. package/src/inputFontFloor.test.ts +106 -0
  381. package/src/tailwind-theme.css +0 -6
  382. package/src/theme/generateThemeRules.test.ts +30 -0
  383. package/src/theme/generateThemeRules.ts +10 -0
  384. package/src/utils/interactionOverlay.stylex.ts +20 -0
@@ -4,15 +4,17 @@
4
4
 
5
5
  /**
6
6
  * @file Selector.tsx
7
- * @input Uses React, StyleX, usePopover, useTooltip, Icon, InputGroupContext,
8
- * and Selector positioning hooks
9
- * @output Exports Selector component
7
+ * @input Uses React, StyleX, adaptive selection surfaces, theme-resolved
8
+ * indicators, Field, and InputGroup context
9
+ * @output Exports Selector with content-derived option-mark layout
10
10
  * @position Core implementation; consumed by index.ts
11
11
  *
12
12
  * SYNC: When modified, update:
13
+ * - /packages/core/src/Selector/Selector.spec.md
13
14
  * - /packages/core/src/Selector/Selector.doc.mjs
14
15
  * - /packages/core/src/Selector/Selector.test.tsx
15
16
  * - /packages/core/src/Selector/index.ts
17
+ * - /apps/storybook/stories/Selector.stories.tsx
16
18
  * - /apps/storybook/stories/InputGroup.stories.tsx
17
19
  * - /packages/cli/assets/templates/blocks/components/Selector/ (showcase blocks)
18
20
  */
@@ -102,9 +104,14 @@ const styles = stylex.create({
102
104
  paddingBlock: spacingVars['--spacing-2'],
103
105
  paddingInline: spacingVars['--spacing-3'],
104
106
  fontFamily: typographyVars['--font-family-body'],
107
+ // The 16px floor is iOS-only: iOS Safari zooms the page when a focused
108
+ // control sits under 16px, and only iOS WebKit implements
109
+ // -webkit-touch-callout to key the coarse-pointer floor to it.
105
110
  fontSize: {
106
111
  default: typeScaleVars['--text-label-size'],
107
- '@media (pointer: coarse)': `max(1rem, ${typeScaleVars['--text-label-size']})`,
112
+ '@media (pointer: coarse)': {
113
+ '@supports (-webkit-touch-callout: none)': `max(1rem, ${typeScaleVars['--text-label-size']})`,
114
+ },
108
115
  },
109
116
  // A FIXED line box, not the ratio: the trigger's padding is derived from
110
117
  // one line being `--spacing-5` tall, and a ratio makes the line box track
@@ -362,18 +369,20 @@ const styles = stylex.create({
362
369
  flex: 1,
363
370
  minWidth: 0,
364
371
  },
365
- // The mark's column, reserved on every row and at either position, so a row
366
- // occupies the same geometry whether or not it is the chosen one — the
367
- // default check draws nothing when unchecked, and without the column a list
368
- // would indent (or truncate) its chosen row differently from the rest.
369
- // `minWidth` rather than `width`: a theme can replace `check` with a larger
370
- // indicator (a radio is 20px at `sm`), and the column has to grow with it.
372
+ // The wrapper keeps a visible mark at either logical position and lets a
373
+ // replacement indicator grow beyond the default 1rem minimum. When the
374
+ // resolved indicator draws nothing, `:empty` removes the wrapper from layout
375
+ // instead of reserving blank space. Selected and unselected labels may
376
+ // therefore shift or have different available width by design (AST-004).
371
377
  itemMarkColumn: {
372
378
  display: 'inline-flex',
373
379
  alignItems: 'center',
374
380
  justifyContent: 'center',
375
381
  flexShrink: 0,
376
382
  minWidth: '1rem',
383
+ ':empty': {
384
+ display: 'none',
385
+ },
377
386
  },
378
387
  itemCheckmark: {
379
388
  flexShrink: 0,
@@ -649,10 +658,10 @@ interface SelectorPropsBase<
649
658
  renderValue?: (option: SelectorOptionData) => ReactNode;
650
659
 
651
660
  /**
652
- * Which edge of the option row carries the selected mark. `start` reserves a
653
- * mark column ahead of every label so they stay aligned, the way a native
654
- * menu does; `end` is the house convention shared with Typeahead and
655
- * CommandPalette.
661
+ * Which logical edge of the option row carries a rendered selection mark. An
662
+ * empty mark consumes no space, so selected and unselected labels may shift or
663
+ * have different available width. `end` is the house convention shared with
664
+ * Typeahead and CommandPalette.
656
665
  *
657
666
  * @default 'end'
658
667
  */
@@ -0,0 +1,130 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Listbox.a11y.chromium.spec.ts
5
+ * @input Uses the Listbox contract, browser harness, state inventory, and checked-in stories
6
+ * @output DOM/accessibility-tree evidence for each real Listbox binding part
7
+ * @position Browser binding; keyboard policy, pixels, and real AT remain separate owners.
8
+ */
9
+
10
+ import {expect, test} from '@playwright/test';
11
+ import {
12
+ LISTBOX_PATTERN,
13
+ checkAccessibilitySpec,
14
+ blockingResults,
15
+ formatFailures,
16
+ formatReport,
17
+ summarize,
18
+ neverExercised,
19
+ unmatchedKnownFailures,
20
+ type BindingResult,
21
+ } from '@astryxdesign/a11y-spec';
22
+ import {
23
+ createChromiumHarness,
24
+ holdMotionStill,
25
+ } from '@astryxdesign/a11y-spec/chromium';
26
+ import {
27
+ serveStorybook,
28
+ DEFAULT_STORYBOOK_DIR,
29
+ type StaticServer,
30
+ } from '@astryxdesign/a11y-spec/storybook';
31
+ import {LISTBOX_KNOWN_FAILURES} from './Listbox.a11y.known-failures';
32
+ import {LISTBOX_SCENARIOS, listboxParts} from './Listbox.a11y.states';
33
+
34
+ let storybook: StaticServer;
35
+ const observedResults: BindingResult[] = [];
36
+ test.beforeAll(async () => {
37
+ storybook = await serveStorybook(
38
+ process.env.ASTRYX_STORYBOOK_DIR ?? DEFAULT_STORYBOOK_DIR,
39
+ );
40
+ });
41
+ test.afterAll(async () => {
42
+ await storybook?.close();
43
+ expect(
44
+ unmatchedKnownFailures(LISTBOX_KNOWN_FAILURES, observedResults),
45
+ ).toEqual([]);
46
+ });
47
+
48
+ for (const scenario of LISTBOX_SCENARIOS) {
49
+ test(`${scenario.component} — ${scenario.id}`, async ({page}) => {
50
+ test.setTimeout(2 * 60 * 1000);
51
+ const cdp = await page.context().newCDPSession(page);
52
+ const results: BindingResult[] = [];
53
+ const mount = async () => {
54
+ await page.goto(
55
+ `${storybook.origin}/iframe.html?id=a11y-listbox-pattern--${scenario.id}&viewMode=story&globals=direction:${scenario.direction ?? 'ltr'}`,
56
+ {waitUntil: 'load'},
57
+ );
58
+ await holdMotionStill(page);
59
+ await expect(
60
+ page.locator(`[data-listbox-scenario="${scenario.id}"]`),
61
+ ).toBeAttached();
62
+ await page.getByRole('listbox').waitFor({state: 'visible'});
63
+ if (scenario.query != null) {
64
+ await page.getByRole('combobox').fill(scenario.query);
65
+ }
66
+ await expect(page.getByRole('listbox').getByRole('option')).toHaveCount(
67
+ scenario.expectedOptions.length,
68
+ );
69
+ };
70
+
71
+ for (const part of listboxParts(scenario)) {
72
+ results.push(
73
+ await checkAccessibilitySpec({
74
+ spec: LISTBOX_PATTERN,
75
+ binding: `${scenario.component}.${part.role}`,
76
+ state: part.state,
77
+ facts: part.facts,
78
+ knownFailures: LISTBOX_KNOWN_FAILURES,
79
+ mount: async () => {
80
+ await mount();
81
+ const listbox = page.getByRole('listbox');
82
+ const subject =
83
+ part.role === 'listbox'
84
+ ? listbox
85
+ : part.role === 'group'
86
+ ? listbox
87
+ .getByRole('group')
88
+ .nth(scenario.groups.indexOf(part.name ?? ''))
89
+ : listbox.getByRole('option', {
90
+ name: part.name,
91
+ exact: true,
92
+ });
93
+ return createChromiumHarness({
94
+ page,
95
+ cdp,
96
+ subject,
97
+ related: {
98
+ listbox,
99
+ ...Object.fromEntries(
100
+ scenario.expectedOptions.map(option => [
101
+ `option:${option.value}`,
102
+ listbox.getByRole('option', {
103
+ name: option.name,
104
+ exact: true,
105
+ }),
106
+ ]),
107
+ ),
108
+ ...Object.fromEntries(
109
+ scenario.groups.map((name, index) => [
110
+ `group:${name}`,
111
+ listbox.getByRole('group').nth(index),
112
+ ]),
113
+ ),
114
+ },
115
+ });
116
+ },
117
+ }),
118
+ );
119
+ }
120
+
121
+ observedResults.push(...results);
122
+ const report = summarize(LISTBOX_PATTERN, results);
123
+ console.log(formatReport(report));
124
+ expect(formatFailures(blockingResults(results))).toBe('');
125
+ expect(report.counts.unrun).toBe(0);
126
+ if (scenario.component === 'Selector' && scenario.groups.length > 0) {
127
+ expect(neverExercised(results)).toEqual([]);
128
+ }
129
+ });
130
+ }
@@ -0,0 +1,38 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Listbox.a11y.dom.ts
5
+ * @input Uses Vitest lifecycle hooks and the DOM Dialog prototype
6
+ * @output Scoped stubs for Dialog methods missing from jsdom
7
+ * @position DOM-only binding setup; these stubs prove no native modal behavior.
8
+ */
9
+
10
+ import {afterAll, beforeAll} from 'vitest';
11
+
12
+ export function installListboxDialogStubs(): void {
13
+ const originals = new Map<string, PropertyDescriptor | undefined>();
14
+ beforeAll(() => {
15
+ for (const name of ['show', 'showModal', 'close']) {
16
+ originals.set(
17
+ name,
18
+ Object.getOwnPropertyDescriptor(HTMLDialogElement.prototype, name),
19
+ );
20
+ Object.defineProperty(HTMLDialogElement.prototype, name, {
21
+ configurable: true,
22
+ writable: true,
23
+ value: function (this: HTMLDialogElement) {
24
+ this.open = name !== 'close';
25
+ },
26
+ });
27
+ }
28
+ });
29
+ afterAll(() => {
30
+ for (const [name, descriptor] of originals) {
31
+ if (descriptor == null) {
32
+ Reflect.deleteProperty(HTMLDialogElement.prototype, name);
33
+ } else {
34
+ Object.defineProperty(HTMLDialogElement.prototype, name, descriptor);
35
+ }
36
+ }
37
+ });
38
+ }
@@ -0,0 +1,63 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Listbox.a11y.inventory.test.ts
5
+ * @input Uses the locked Listbox migration matrix and checklist
6
+ * @output Coverage-boundary and part-inventory regression checks
7
+ * @position Binding metadata proof, separate from runtime conformance results.
8
+ */
9
+
10
+ import {describe, expect, it} from 'vitest';
11
+ import {LISTBOX_PATTERN, unansweredDimensions} from '@astryxdesign/a11y-spec';
12
+ import {LISTBOX_KNOWN_FAILURES} from './Listbox.a11y.known-failures';
13
+ import {
14
+ LISTBOX_SCENARIOS,
15
+ LISTBOX_EXCLUSIONS,
16
+ listboxParts,
17
+ } from './Listbox.a11y.states';
18
+
19
+ describe('Listbox migration inventory', () => {
20
+ it('accounts for every checklist dimension without claiming other evidence layers', () => {
21
+ expect(unansweredDimensions(LISTBOX_PATTERN)).toEqual([]);
22
+ expect(LISTBOX_EXCLUSIONS).toHaveLength(5);
23
+ });
24
+
25
+ it('binds 21 scenarios and all six real semantic parts', () => {
26
+ expect(LISTBOX_SCENARIOS).toHaveLength(21);
27
+ const parts = LISTBOX_SCENARIOS.flatMap(scenario =>
28
+ listboxParts(scenario).map(part => ({
29
+ binding: `${scenario.component}.${part.role}`,
30
+ state: part.state,
31
+ })),
32
+ );
33
+ expect(parts).toHaveLength(89);
34
+ expect(new Set(parts.map(part => part.state)).size).toBe(89);
35
+ expect([...new Set(parts.map(part => part.binding))].sort()).toEqual([
36
+ 'MultiSelector.group',
37
+ 'MultiSelector.listbox',
38
+ 'MultiSelector.option',
39
+ 'Selector.group',
40
+ 'Selector.listbox',
41
+ 'Selector.option',
42
+ ]);
43
+ });
44
+
45
+ it('pins each known failure to one exact inventory part', () => {
46
+ const parts = LISTBOX_SCENARIOS.flatMap(scenario =>
47
+ listboxParts(scenario).map(part => ({
48
+ binding: `${scenario.component}.${part.role}`,
49
+ state: part.state,
50
+ })),
51
+ );
52
+
53
+ expect(LISTBOX_KNOWN_FAILURES).toHaveLength(2);
54
+ for (const record of LISTBOX_KNOWN_FAILURES) {
55
+ expect(
56
+ parts.filter(
57
+ part =>
58
+ part.binding === record.binding && part.state === record.state,
59
+ ),
60
+ ).toHaveLength(1);
61
+ }
62
+ });
63
+ });
@@ -0,0 +1,37 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Listbox.a11y.known-failures.ts
5
+ * @input Uses KnownFailure from @astryxdesign/a11y-spec
6
+ * @output Exact public-safe Selector and MultiSelector listbox migration failures
7
+ * @position AST-021 debt records; operational ownership remains outside public source.
8
+ */
9
+
10
+ import type {KnownFailure} from '@astryxdesign/a11y-spec';
11
+
12
+ export const LISTBOX_KNOWN_FAILURES: ReadonlyArray<KnownFailure> = [
13
+ {
14
+ expectation: 'listbox.exposure.identity',
15
+ binding: 'Selector.listbox',
16
+ state: 'single-sheet:listbox',
17
+ evidenceLayer: 'accessibility-tree',
18
+ failureEquals: 'the browser exposes the listbox without an accessible name',
19
+ standardsReference: 'WCAG 2.2 4.1.2 Name, Role, Value (Level A)',
20
+ userImpact:
21
+ 'An accessibility consumer encounters an unnamed listbox in the bottom-sheet presentation and cannot identify what set of choices it contains.',
22
+ reason:
23
+ 'The no-search bottom-sheet presentation renders a visible sheet heading without assigning that heading, or another label, as the listbox accessible name. This migration records the existing behavior without changing the component.',
24
+ },
25
+ {
26
+ expectation: 'listbox.exposure.identity',
27
+ binding: 'MultiSelector.listbox',
28
+ state: 'multiple-sheet:listbox',
29
+ evidenceLayer: 'accessibility-tree',
30
+ failureEquals: 'the browser exposes the listbox without an accessible name',
31
+ standardsReference: 'WCAG 2.2 4.1.2 Name, Role, Value (Level A)',
32
+ userImpact:
33
+ 'An accessibility consumer encounters an unnamed multi-select listbox in the bottom-sheet presentation and cannot identify what set of choices it contains.',
34
+ reason:
35
+ 'The no-search bottom-sheet presentation renders a visible sheet heading without assigning that heading, or another label, as the listbox accessible name. This migration records the existing behavior without changing the component.',
36
+ },
37
+ ];
@@ -0,0 +1,232 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Listbox.a11y.states.ts
5
+ * @input Uses public Selector option types and the shared Listbox facts
6
+ * @output A bounded, explicit inventory of existing listbox/group/option states
7
+ * @position Test-only migration ledger shared by component tests and browser stories.
8
+ */
9
+
10
+ import type {ListboxStateFacts} from '@astryxdesign/a11y-spec';
11
+ import type {SelectorOptionType} from '../types';
12
+
13
+ export interface ListboxScenario {
14
+ readonly id: string;
15
+ readonly component: 'Selector' | 'MultiSelector';
16
+ readonly options: SelectorOptionType[];
17
+ readonly values: string[];
18
+ readonly expectedOptions: ReadonlyArray<{
19
+ value: string;
20
+ name: string;
21
+ disabled: boolean;
22
+ selected?: boolean;
23
+ group?: string;
24
+ }>;
25
+ readonly groups: ReadonlyArray<string>;
26
+ readonly hasSearch?: boolean;
27
+ readonly query?: string;
28
+ readonly presentation?: 'popover' | 'bottom-sheet';
29
+ readonly customContent?: boolean;
30
+ readonly hiddenLabel?: boolean;
31
+ readonly direction?: 'ltr' | 'rtl';
32
+ readonly isLoading?: boolean;
33
+ readonly hasSelectAll?: boolean;
34
+ }
35
+
36
+ const flatOptions: SelectorOptionType[] = [
37
+ {value: 'apple', label: 'Apple'},
38
+ {value: 'banana', label: 'Banana'},
39
+ {value: 'cherry', label: 'Cherry', disabled: true},
40
+ ];
41
+ const flatExpected = [
42
+ {value: 'apple', name: 'Apple', disabled: false},
43
+ {value: 'banana', name: 'Banana', disabled: false},
44
+ {value: 'cherry', name: 'Cherry', disabled: true},
45
+ ];
46
+ const groupedOptions: SelectorOptionType[] = [
47
+ {
48
+ type: 'section',
49
+ title: 'Citrus',
50
+ options: [
51
+ {value: 'orange', label: 'Orange'},
52
+ {value: 'lemon', label: 'Lemon'},
53
+ ],
54
+ },
55
+ {type: 'divider'},
56
+ {
57
+ type: 'section',
58
+ title: 'Berries',
59
+ options: [{value: 'blueberry', label: 'Blueberry', disabled: true}],
60
+ },
61
+ ];
62
+ const groupedExpected = [
63
+ {value: 'orange', name: 'Orange', disabled: false, group: 'Citrus'},
64
+ {value: 'lemon', name: 'Lemon', disabled: false, group: 'Citrus'},
65
+ {value: 'blueberry', name: 'Blueberry', disabled: true, group: 'Berries'},
66
+ ];
67
+
68
+ function scenarios(component: ListboxScenario['component']): ListboxScenario[] {
69
+ const prefix = component === 'Selector' ? 'single' : 'multiple';
70
+ const base = {
71
+ component,
72
+ options: flatOptions,
73
+ expectedOptions: flatExpected,
74
+ groups: [],
75
+ };
76
+ return [
77
+ {...base, id: `${prefix}-unset`, values: []},
78
+ {
79
+ ...base,
80
+ id: `${prefix}-selected`,
81
+ values: component === 'Selector' ? ['apple'] : ['apple', 'banana'],
82
+ },
83
+ {...base, id: `${prefix}-disabled-selected`, values: ['cherry']},
84
+ {
85
+ ...base,
86
+ id: `${prefix}-grouped`,
87
+ options: groupedOptions,
88
+ values: ['orange'],
89
+ expectedOptions: groupedExpected,
90
+ groups: ['Citrus', 'Berries'],
91
+ },
92
+ {
93
+ ...base,
94
+ id: `${prefix}-filtered`,
95
+ options: groupedOptions,
96
+ values: ['orange'],
97
+ expectedOptions: [
98
+ {value: 'lemon', name: 'Lemon', disabled: false, group: 'Citrus'},
99
+ ],
100
+ groups: ['Citrus'],
101
+ hasSearch: true,
102
+ query: 'lem',
103
+ },
104
+ {
105
+ ...base,
106
+ id: `${prefix}-custom-rtl`,
107
+ values: ['banana'],
108
+ customContent: true,
109
+ hiddenLabel: true,
110
+ direction: 'rtl',
111
+ expectedOptions: [
112
+ {value: 'apple', name: 'Apple details', disabled: false},
113
+ {value: 'banana', name: 'Banana details', disabled: false},
114
+ {value: 'cherry', name: 'Cherry details', disabled: true},
115
+ ],
116
+ },
117
+ {
118
+ ...base,
119
+ id: `${prefix}-sheet`,
120
+ values: ['apple'],
121
+ presentation: 'bottom-sheet',
122
+ },
123
+ {
124
+ ...base,
125
+ id: `${prefix}-sheet-search`,
126
+ values: ['banana'],
127
+ presentation: 'bottom-sheet',
128
+ hasSearch: true,
129
+ },
130
+ {...base, id: `${prefix}-loading`, values: ['apple'], isLoading: true},
131
+ ];
132
+ }
133
+
134
+ export const LISTBOX_SCENARIOS: ReadonlyArray<ListboxScenario> = [
135
+ ...scenarios('Selector'),
136
+ ...scenarios('MultiSelector'),
137
+ ...(['none', 'partial', 'all'] as const).map(state => ({
138
+ id: `multiple-select-all-${state}`,
139
+ component: 'MultiSelector' as const,
140
+ options: flatOptions,
141
+ values:
142
+ state === 'none'
143
+ ? []
144
+ : state === 'partial'
145
+ ? ['apple']
146
+ : ['apple', 'banana'],
147
+ groups: [],
148
+ hasSelectAll: true,
149
+ expectedOptions: [
150
+ {
151
+ value: 'select-all',
152
+ name:
153
+ state === 'partial' ? 'Select all, partially selected' : 'Select all',
154
+ disabled: false,
155
+ selected: state === 'all',
156
+ },
157
+ ...flatExpected,
158
+ ],
159
+ })),
160
+ ];
161
+
162
+ export interface ListboxBindingPart {
163
+ readonly role: 'listbox' | 'group' | 'option';
164
+ readonly name?: string;
165
+ readonly state: string;
166
+ readonly facts: ListboxStateFacts;
167
+ }
168
+
169
+ export function listboxParts(
170
+ scenario: ListboxScenario,
171
+ ): ReadonlyArray<ListboxBindingPart> {
172
+ const multiple = scenario.component === 'MultiSelector';
173
+ return [
174
+ {
175
+ role: 'listbox',
176
+ state: `${scenario.id}:listbox`,
177
+ facts: {
178
+ part: 'listbox',
179
+ multiple,
180
+ optionRelations: scenario.expectedOptions.map(
181
+ option => `option:${option.value}`,
182
+ ),
183
+ },
184
+ },
185
+ ...scenario.groups.map(name => ({
186
+ role: 'group' as const,
187
+ name,
188
+ state: `${scenario.id}:group:${name}`,
189
+ facts: {part: 'group' as const, multiple},
190
+ })),
191
+ ...scenario.expectedOptions.map(option => ({
192
+ role: 'option' as const,
193
+ name: option.name,
194
+ state: `${scenario.id}:option:${option.value}`,
195
+ facts: {
196
+ part: 'option' as const,
197
+ multiple,
198
+ selected: option.selected ?? scenario.values.includes(option.value),
199
+ disabled: option.disabled,
200
+ ownerGroup: option.group == null ? undefined : `group:${option.group}`,
201
+ },
202
+ })),
203
+ ];
204
+ }
205
+
206
+ export const LISTBOX_EXCLUSIONS = [
207
+ {
208
+ owner: 'Selector/MultiSelector trigger and search input',
209
+ reason:
210
+ 'Combobox, field validation, required/read-only/disabled trigger state, and opening/closing are separate contracts. This slice observes active popup parts.',
211
+ },
212
+ {
213
+ owner: 'Selector/MultiSelector existing interaction suites',
214
+ reason:
215
+ 'Keyboard selection, selection-follows-focus, disabled-option discovery, Home/End, typeahead, and callback policy are not newly adopted here.',
216
+ },
217
+ {
218
+ owner: 'Selector/MultiSelector empty-state and live-region owners',
219
+ reason:
220
+ 'Zero-result representation and announcement timing require their own authority/evidence. No required option is invented for an empty listbox.',
221
+ },
222
+ {
223
+ owner: 'Typeahead, Tokenizer, PowerSearch, ComplexSelector, CommandPalette',
224
+ reason:
225
+ 'Later bounded adopters; this first migration is limited to Selector and MultiSelector.',
226
+ },
227
+ {
228
+ owner: 'Component-specific suites',
229
+ reason:
230
+ 'Public ID forwarding, callback payloads, forms, value formatting, sorting, required/error status, and styling stay local. Selector has no independent uncontrolled selected-value owner; an omitted value is the unset state.',
231
+ },
232
+ ] as const;