@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
@@ -46,7 +46,11 @@ import {
46
46
  } from '../theme/tokens.stylex';
47
47
  import {focusOutlineProps} from '../utils/focusOutline.stylex';
48
48
  import {mergeProps, rtlStyles} from '../utils';
49
- import type {ResizableProps} from './useResizable';
49
+ import {
50
+ getCollapseControls,
51
+ getEffectiveMaxPx,
52
+ type ResizableProps,
53
+ } from './useResizable';
50
54
  import {themeProps} from '../utils/themeProps';
51
55
  import {useTranslator} from '../i18n';
52
56
 
@@ -360,6 +364,60 @@ export interface ResizeHandleProps extends Omit<
360
364
  children?: ReactNode;
361
365
  }
362
366
 
367
+ /**
368
+ * The snap point `count` points away from the region's current size in
369
+ * `direction` (+1 grows, -1 shrinks). A point beyond `minSize` or `maxSize`
370
+ * counts as that bound; the nearest end point serves when fewer remain, and
371
+ * the current size when it is already there.
372
+ */
373
+ function adjacentSnapPoint(
374
+ resizable: ResizableProps,
375
+ direction: 1 | -1,
376
+ count: number,
377
+ ): number {
378
+ const points = [
379
+ ...new Set(
380
+ resizable._snaps.map(p =>
381
+ Math.min(resizable._maxSizePx, Math.max(resizable._minSizePx, p)),
382
+ ),
383
+ ),
384
+ ].sort((a, b) => a - b);
385
+ const size = resizable._size;
386
+ const ahead =
387
+ direction > 0
388
+ ? points.filter(p => p > size)
389
+ : points.filter(p => p < size).reverse();
390
+ if (ahead.length === 0) {
391
+ return size;
392
+ }
393
+ return ahead[Math.min(count, ahead.length) - 1];
394
+ }
395
+
396
+ /**
397
+ * Collapse an open pane, or restore a collapsed one to the size it had before
398
+ * it collapsed (APG window splitter: Enter "restores the splitter to its
399
+ * previous position"). The hook's own collapse/expand do exactly that; a
400
+ * hand-built `ResizableProps` (no registered controls) falls back to a resize
401
+ * gesture to the minimum, which also cannot reopen a pane whose minimum sits below its
402
+ * collapse threshold.
403
+ */
404
+ function toggleCollapse(resizable: ResizableProps): void {
405
+ const controls = getCollapseControls(resizable);
406
+ if (controls) {
407
+ if (resizable._isCollapsed) {
408
+ controls.expand();
409
+ } else {
410
+ controls.collapse();
411
+ }
412
+ return;
413
+ }
414
+ resizable._onResizeStart();
415
+ resizable._onResizeMove(
416
+ resizable._isCollapsed ? resizable._minSizePx : -resizable._size,
417
+ );
418
+ resizable._onResizeEnd();
419
+ }
420
+
363
421
  /**
364
422
  * Draggable resize handle placed between resizable panels. Renders as a thin
365
423
  * divider line with a wider invisible hit area and optional pill grip indicator.
@@ -375,6 +433,7 @@ export interface ResizeHandleProps extends Omit<
375
433
  * hasDivider />
376
434
  * ```
377
435
  */
436
+
378
437
  export function ResizeHandle({
379
438
  direction = 'horizontal',
380
439
  position: positionMode = 'inline',
@@ -528,20 +587,64 @@ export function ResizeHandle({
528
587
  const step = e.shiftKey ? KEYBOARD_LARGE_STEP : KEYBOARD_STEP;
529
588
  const rtl = isHorizontal ? getRTLMultiplier() : 1;
530
589
 
590
+ // The pane's grow direction on this key: ArrowRight/Down grow unless the
591
+ // layout is reversed or, on the inline axis, right-to-left.
592
+ const grows = (key: string) =>
593
+ (key === 'ArrowRight' || key === 'ArrowDown'
594
+ ? 1
595
+ : key === 'ArrowLeft' || key === 'ArrowUp'
596
+ ? -1
597
+ : 0) *
598
+ (isHorizontal ? rtl : 1) *
599
+ sign >
600
+ 0;
601
+
531
602
  switch (e.key) {
532
603
  case 'ArrowRight':
533
- case 'ArrowDown': {
534
- e.preventDefault();
535
- resizable._onResizeStart();
536
- resizable._onResizeMove(step * (isHorizontal ? rtl : 1) * sign);
537
- resizable._onResizeEnd();
538
- break;
539
- }
604
+ case 'ArrowDown':
540
605
  case 'ArrowLeft':
541
606
  case 'ArrowUp': {
542
607
  e.preventDefault();
608
+ if (resizable._isCollapsed) {
609
+ // A collapsed pane answers only the grow arrow: it opens one step
610
+ // above its minimum, the value the separator announces while
611
+ // collapsed, or at the collapse threshold when that is larger (APG
612
+ // window splitter: the arrow moves the separator from where it is;
613
+ // a bare step would stay below the threshold and leave it in
614
+ // place). The shrink arrow is a no-op.
615
+ if (grows(e.key)) {
616
+ resizable._onResizeStart();
617
+ // At least the collapse threshold, or the move would stay
618
+ // collapsed when the minimum sits below it.
619
+ resizable._onResizeMove(
620
+ Math.max(resizable._minSizePx + step, resizable._collapsedSize),
621
+ );
622
+ resizable._onResizeEnd();
623
+ }
624
+ break;
625
+ }
626
+ if (resizable._snaps.length > 0) {
627
+ // With snap points the region can rest only on a point, so a
628
+ // pixel step would snap straight back; the arrow moves to the
629
+ // adjacent point in its direction instead (Shift, two points),
630
+ // staying within the bounds.
631
+ resizable._onResizeStart();
632
+ resizable._onResizeMove(
633
+ adjacentSnapPoint(
634
+ resizable,
635
+ grows(e.key) ? 1 : -1,
636
+ e.shiftKey ? 2 : 1,
637
+ ) - resizable._size,
638
+ );
639
+ resizable._onResizeEnd();
640
+ break;
641
+ }
642
+ const direction =
643
+ e.key === 'ArrowRight' || e.key === 'ArrowDown' ? 1 : -1;
543
644
  resizable._onResizeStart();
544
- resizable._onResizeMove(-step * (isHorizontal ? rtl : 1) * sign);
645
+ resizable._onResizeMove(
646
+ direction * step * (isHorizontal ? rtl : 1) * sign,
647
+ );
545
648
  resizable._onResizeEnd();
546
649
  break;
547
650
  }
@@ -554,6 +657,9 @@ export function ResizeHandle({
554
657
  }
555
658
  case 'End': {
556
659
  e.preventDefault();
660
+ // Only a configured maximum is the region's own limit; the reported
661
+ // stand-in for an unbounded region is where the pane *could* reach,
662
+ // not where End may safely move it (a recorded gap).
557
663
  if (resizable._maxSizePx !== Infinity) {
558
664
  resizable._onResizeStart();
559
665
  resizable._onResizeMove(resizable._maxSizePx - resizable._size);
@@ -564,11 +670,7 @@ export function ResizeHandle({
564
670
  case 'Enter': {
565
671
  e.preventDefault();
566
672
  if (resizable._collapsible) {
567
- resizable._onResizeStart();
568
- resizable._onResizeMove(
569
- resizable._isCollapsed ? resizable._minSizePx : -resizable._size,
570
- );
571
- resizable._onResizeEnd();
673
+ toggleCollapse(resizable);
572
674
  }
573
675
  break;
574
676
  }
@@ -582,11 +684,7 @@ export function ResizeHandle({
582
684
  if (isDisabled || !resizable || !resizable._collapsible) {
583
685
  return;
584
686
  }
585
- resizable._onResizeStart();
586
- resizable._onResizeMove(
587
- resizable._isCollapsed ? resizable._minSizePx : -resizable._size,
588
- );
589
- resizable._onResizeEnd();
687
+ toggleCollapse(resizable);
590
688
  }, [isDisabled, resizable]);
591
689
 
592
690
  // --- Cleanup on unmount ---
@@ -620,9 +718,16 @@ export function ResizeHandle({
620
718
  : resizable._size
621
719
  : undefined;
622
720
  const ariaValueMin = resizable ? resizable._minSizePx : undefined;
721
+ // A separator with a value needs a maximum (WAI-ARIA, APG window splitter).
722
+ // Unbounded regions report the basis they can fill; a hand-built props
723
+ // object without it reports only a configured maximum.
724
+ const effectiveMax = resizable
725
+ ? (getEffectiveMaxPx(resizable) ??
726
+ (resizable._maxSizePx !== Infinity ? resizable._maxSizePx : undefined))
727
+ : undefined;
623
728
  const ariaValueMax =
624
- resizable && resizable._maxSizePx !== Infinity
625
- ? resizable._maxSizePx
729
+ effectiveMax != null && Number.isFinite(effectiveMax)
730
+ ? effectiveMax
626
731
  : undefined;
627
732
  const ariaValueText =
628
733
  resizable && isCollapsed ? t('@astryx.resizable.collapsed') : undefined;
@@ -0,0 +1,119 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file ResizeHandle.a11y.chromium.spec.ts
5
+ * @input Built ResizeHandle stories and WINDOW_SPLITTER_PATTERN in real Chromium
6
+ * @output Browser evidence for every window-splitter expectation across the binding's states, reconciled against the exact known failures
7
+ * @position Chromium lane of the ResizeHandle binding (component:Resizable AR1)
8
+ */
9
+
10
+ import {
11
+ expect,
12
+ test,
13
+ type CDPSession,
14
+ type Locator,
15
+ type Page,
16
+ } from '@playwright/test';
17
+ import {
18
+ WINDOW_SPLITTER_PATTERN,
19
+ blockingResults,
20
+ checkAccessibilitySpec,
21
+ formatFailures,
22
+ neverExercised,
23
+ summarize,
24
+ unmatchedKnownFailures,
25
+ type BindingResult,
26
+ } from '@astryxdesign/a11y-spec';
27
+ import {
28
+ createChromiumHarness,
29
+ holdMotionStill,
30
+ } from '@astryxdesign/a11y-spec/chromium';
31
+ import {
32
+ DEFAULT_STORYBOOK_DIR,
33
+ serveStorybook,
34
+ type StaticServer,
35
+ } from '@astryxdesign/a11y-spec/storybook';
36
+ import {RESIZE_HANDLE_KNOWN_FAILURES} from './ResizeHandle.a11y.known-failures';
37
+ import {
38
+ RESIZE_HANDLE_BINDING_STATES,
39
+ type ResizeHandleBindingState,
40
+ } from './ResizeHandle.a11y.states';
41
+
42
+ let storybook: StaticServer;
43
+
44
+ test.beforeAll(async () => {
45
+ storybook = await serveStorybook(
46
+ process.env.ASTRYX_STORYBOOK_DIR ?? DEFAULT_STORYBOOK_DIR,
47
+ );
48
+ });
49
+
50
+ test.afterAll(async () => {
51
+ await storybook?.close();
52
+ });
53
+
54
+ function storyUrl(storyId: string): string {
55
+ return `${storybook.origin}/iframe.html?id=${storyId}&viewMode=story`;
56
+ }
57
+
58
+ async function mountState(
59
+ page: Page,
60
+ state: ResizeHandleBindingState,
61
+ ): Promise<{subject: Locator; related: Record<string, Locator>}> {
62
+ await page.goto(storyUrl(state.storyId), {waitUntil: 'load'});
63
+ await holdMotionStill(page);
64
+ const root = page.locator('#storybook-root');
65
+ const subject = root.getByRole('separator', {name: state.label});
66
+ await subject.waitFor({state: 'attached'});
67
+ const pane = root.locator('#a11y-splitter-pane');
68
+ return {subject, related: {pane}};
69
+ }
70
+
71
+ async function runState(
72
+ page: Page,
73
+ cdp: CDPSession,
74
+ state: ResizeHandleBindingState,
75
+ ): Promise<BindingResult> {
76
+ return checkAccessibilitySpec({
77
+ spec: WINDOW_SPLITTER_PATTERN,
78
+ binding: 'ResizeHandle',
79
+ state: state.id,
80
+ facts: state.facts,
81
+ knownFailures: RESIZE_HANDLE_KNOWN_FAILURES,
82
+ mount: async () => {
83
+ const {subject, related} = await mountState(page, state);
84
+ return createChromiumHarness({page, cdp, subject, related});
85
+ },
86
+ });
87
+ }
88
+
89
+ test('every window-splitter expectation is exercised by a ResizeHandle state', async ({
90
+ page,
91
+ }) => {
92
+ // One test mounts and checks every binding state in turn: about 20s on an
93
+ // idle machine, three times that when the contract run shares a runner's
94
+ // cores, so the default 60s ran out mid-loop on whichever state it reached.
95
+ // Budget it like the other whole-inventory sweeps (Button, Checkbox).
96
+ test.setTimeout(3 * 60 * 1000);
97
+ const cdp = await page.context().newCDPSession(page);
98
+ const results: BindingResult[] = [];
99
+ for (const state of RESIZE_HANDLE_BINDING_STATES) {
100
+ results.push(await runState(page, cdp, state));
101
+ }
102
+ expect(neverExercised(results)).toEqual([]);
103
+ expect(unmatchedKnownFailures(RESIZE_HANDLE_KNOWN_FAILURES, results)).toEqual(
104
+ [],
105
+ );
106
+ });
107
+
108
+ for (const state of RESIZE_HANDLE_BINDING_STATES) {
109
+ test(`ResizeHandle [${state.id}] — ${state.summary}`, async ({page}) => {
110
+ const cdp = await page.context().newCDPSession(page);
111
+ const result = await runState(page, cdp, state);
112
+ const report = summarize(WINDOW_SPLITTER_PATTERN, [result]);
113
+ // Required rows block (AST-020 FR9); advisory rows and exact known
114
+ // failures report.
115
+ expect(formatFailures(blockingResults([result]))).toBe('');
116
+ expect(report.unrunLayers).toEqual([]);
117
+ expect(report.counts.unexpectedPass).toBe(0);
118
+ });
119
+ }
@@ -0,0 +1,39 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file ResizeHandle.a11y.known-failures.ts
5
+ * @input The exact window-splitter failures the shipped ResizeHandle produces today
6
+ * @output RESIZE_HANDLE_KNOWN_FAILURES — records both lanes reconcile against, so a fix shows up as an unexpected pass and any other failure stays a failure
7
+ * @position Known-failure ledger for the ResizeHandle binding
8
+ */
9
+
10
+ import type {KnownFailure} from '@astryxdesign/a11y-spec';
11
+
12
+ export const RESIZE_HANDLE_KNOWN_FAILURES: ReadonlyArray<KnownFailure> = [
13
+ {
14
+ expectation: 'windowsplitter.separator.maximum',
15
+ binding: 'ResizeHandle',
16
+ state: 'bare-unbounded-in-container',
17
+ evidenceLayer: 'dom',
18
+ failureEquals: 'the splitter exposes no aria-valuemax',
19
+ standardsReference:
20
+ 'WAI-ARIA separator (focusable): aria-valuemax; APG Window Splitter states and properties; Astryx component:Resizable AR1 (an unbounded Handle in a container that no percentage bound observes carries no aria-valuemax, because measuring that container would add an observer to a region whose bounds are all in pixels).',
21
+ userImpact:
22
+ 'A screen-reader user on a handle whose pixel-only region sits in a container and sets no maximum hears a value and a minimum but no maximum.',
23
+ reason:
24
+ 'A recorded gap with a reason the record owns (Performance and resources: atomic pixel paths add no observer); it closes only with a record decision, not a fix.',
25
+ },
26
+ {
27
+ expectation: 'windowsplitter.separator.controls-pane',
28
+ binding: 'ResizeHandle',
29
+ state: 'bare-documented-usage',
30
+ evidenceLayer: 'dom',
31
+ failureEquals: 'the splitter carries no aria-controls',
32
+ standardsReference:
33
+ 'APG Window Splitter states and properties: the separator has aria-controls set to the id of the primary pane; Astryx component:Resizable AR1 (the Handle names the pane it resizes with aria-controls only when its caller passes one).',
34
+ userImpact:
35
+ 'A screen-reader user on a handle rendered the documented minimal way hears a separator with no named pane; the relationship exists only when the caller wires it (SideNav does).',
36
+ reason:
37
+ 'A recorded gap the record owns: whether the Handle should derive the pane relationship itself is a component decision for its own spec-backed patch.',
38
+ },
39
+ ];
@@ -0,0 +1,80 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file ResizeHandle.a11y.renders.tsx
7
+ * @input One ResizeHandle binding state
8
+ * @output The React tree every lane renders for that state (the jsdom test directly, the story through Storybook)
9
+ * @position Shared fixture for the ResizeHandle binding
10
+ */
11
+
12
+ import {useRef, type ReactElement} from 'react';
13
+ import {ResizeHandle} from '../ResizeHandle';
14
+ import {useResizable} from '../useResizable';
15
+ import type {ResizeHandleBindingState} from './ResizeHandle.a11y.states';
16
+
17
+ /** The id the binding gives the pane the bare handle controls. */
18
+ export const BARE_PANE_ID = 'a11y-splitter-pane';
19
+
20
+ function BareSplitter({state}: {state: ResizeHandleBindingState}) {
21
+ const direction = state.direction ?? 'horizontal';
22
+ const containerRef = useRef<HTMLDivElement>(null);
23
+ const region = useResizable({
24
+ containerRef: state.inContainer ? containerRef : undefined,
25
+ defaultSize: state.facts.valueNow,
26
+ minSize: state.facts.valueMin,
27
+ maxSize: state.maxSize === null ? undefined : (state.facts.valueMax ?? 400),
28
+ direction,
29
+ collapsible: state.facts.collapsible,
30
+ collapsedSize: state.collapsedSize,
31
+ defaultIsCollapsed: state.startsCollapsed,
32
+ snaps: state.snaps ? [...state.snaps] : undefined,
33
+ });
34
+ const isHorizontal = direction === 'horizontal';
35
+ const pane = (
36
+ <div
37
+ id={BARE_PANE_ID}
38
+ style={{
39
+ ...(isHorizontal ? {width: region.size} : {height: region.size}),
40
+ background: 'var(--astryx-bg-surface, #f2f2f2)',
41
+ padding: 12,
42
+ }}>
43
+ Details
44
+ </div>
45
+ );
46
+ const handle = (
47
+ <ResizeHandle
48
+ resizable={region.props}
49
+ label={state.label}
50
+ direction={direction}
51
+ isReversed={state.isReversed}
52
+ isDisabled={state.disabled}
53
+ aria-controls={state.withoutControls ? undefined : BARE_PANE_ID}
54
+ />
55
+ );
56
+ return (
57
+ <div
58
+ ref={containerRef}
59
+ style={{
60
+ display: 'flex',
61
+ flexDirection: isHorizontal ? 'row' : 'column',
62
+ width: 600,
63
+ height: 320,
64
+ }}>
65
+ {state.isReversed ? handle : pane}
66
+ {state.isReversed ? pane : handle}
67
+ <div style={{flex: 1, padding: 12}}>Main content</div>
68
+ </div>
69
+ );
70
+ }
71
+
72
+ export function renderResizeHandleState(
73
+ state: ResizeHandleBindingState,
74
+ ): ReactElement {
75
+ return (
76
+ <div dir={state.rtl ? 'rtl' : 'ltr'} style={{padding: 16}}>
77
+ <BareSplitter state={state} />
78
+ </div>
79
+ );
80
+ }
@@ -0,0 +1,197 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file ResizeHandle.a11y.states.ts
5
+ * @input ResizeHandle's representative splitter states and the facts WINDOW_SPLITTER_PATTERN reads
6
+ * @output RESIZE_HANDLE_BINDING_STATES and the explicit ownership exclusions for this binding
7
+ * @position Binding inventory shared by the jsdom test, the Chromium spec, and the story (component:Resizable AR1)
8
+ */
9
+
10
+ import type {WindowSplitterStateFacts} from '@astryxdesign/a11y-spec';
11
+
12
+ export interface ResizeHandleBindingState {
13
+ readonly id: string;
14
+ readonly summary: string;
15
+ readonly storyId: string;
16
+ /** Which composition renders the handle; SideNav's binding follows separately. */
17
+ readonly component: 'ResizeHandle';
18
+ /** The separator's accessible name. */
19
+ readonly label: string;
20
+ readonly facts: WindowSplitterStateFacts;
21
+ /** Bare-handle configuration. */
22
+ readonly direction?: 'horizontal' | 'vertical';
23
+ readonly isReversed?: boolean;
24
+ readonly rtl?: boolean;
25
+ readonly maxSize?: number | null;
26
+ /** The hook's collapse threshold, when the state sets one. */
27
+ readonly collapsedSize?: number;
28
+ /** Start the pane collapsed (`defaultIsCollapsed`). */
29
+ readonly startsCollapsed?: boolean;
30
+ /** Pass a `containerRef` (a pixel-only region inside a container). */
31
+ readonly inContainer?: boolean;
32
+ /** Snap points for the region (`snaps`). */
33
+ readonly snaps?: ReadonlyArray<number>;
34
+ /** Render the documented minimal usage: no `aria-controls` passed. */
35
+ readonly withoutControls?: boolean;
36
+ readonly disabled?: boolean;
37
+ }
38
+
39
+ function facts(
40
+ overrides: Partial<WindowSplitterStateFacts> = {},
41
+ ): WindowSplitterStateFacts {
42
+ return {
43
+ valueNow: 200,
44
+ valueMin: 100,
45
+ valueMax: 400,
46
+ orientation: 'vertical',
47
+ increaseKey: 'ArrowRight',
48
+ step: 10,
49
+ operable: true,
50
+ collapsible: false,
51
+ ...overrides,
52
+ };
53
+ }
54
+
55
+ const story = (id: string) => `a11y-windowsplitter--${id}`;
56
+
57
+ export const RESIZE_HANDLE_BINDING_STATES = [
58
+ {
59
+ id: 'bare-horizontal',
60
+ summary: 'a bare ResizeHandle on the end side of a 200px pane (100–400)',
61
+ storyId: story('bare-horizontal'),
62
+ component: 'ResizeHandle',
63
+ label: 'Resize details pane',
64
+ facts: facts(),
65
+ },
66
+ {
67
+ id: 'bare-vertical',
68
+ summary: 'a bare ResizeHandle below a 200px pane: ArrowDown grows it',
69
+ storyId: story('bare-vertical'),
70
+ component: 'ResizeHandle',
71
+ label: 'Resize log pane',
72
+ facts: facts({orientation: 'horizontal', increaseKey: 'ArrowDown'}),
73
+ direction: 'vertical',
74
+ },
75
+ {
76
+ id: 'bare-reversed',
77
+ summary:
78
+ 'a bare ResizeHandle on the start side of its pane: ArrowLeft grows it',
79
+ storyId: story('bare-reversed'),
80
+ component: 'ResizeHandle',
81
+ label: 'Resize details pane',
82
+ facts: facts({increaseKey: 'ArrowLeft'}),
83
+ isReversed: true,
84
+ },
85
+ {
86
+ id: 'bare-rtl',
87
+ summary:
88
+ 'a bare ResizeHandle on a right-to-left page: the inline arrows follow the reading direction',
89
+ storyId: story('bare-rtl'),
90
+ component: 'ResizeHandle',
91
+ label: 'Resize details pane',
92
+ facts: facts({increaseKey: 'ArrowLeft'}),
93
+ rtl: true,
94
+ },
95
+ {
96
+ id: 'bare-collapsible',
97
+ summary:
98
+ 'a bare ResizeHandle on a collapsible pane: Enter collapses and restores',
99
+ storyId: story('bare-collapsible'),
100
+ component: 'ResizeHandle',
101
+ label: 'Resize details pane',
102
+ facts: facts({collapsible: true}),
103
+ },
104
+ {
105
+ id: 'bare-small-min',
106
+ summary:
107
+ 'a bare ResizeHandle on a collapsible pane whose minimum sits below the collapse threshold',
108
+ storyId: story('bare-small-min'),
109
+ component: 'ResizeHandle',
110
+ label: 'Resize details pane',
111
+ facts: facts({collapsible: true, valueMin: 20}),
112
+ collapsedSize: 50,
113
+ },
114
+ {
115
+ id: 'bare-start-collapsed',
116
+ summary:
117
+ 'a bare ResizeHandle on a pane that starts collapsed: it announces the minimum as its value',
118
+ storyId: story('bare-start-collapsed'),
119
+ component: 'ResizeHandle',
120
+ label: 'Resize details pane',
121
+ // Collapsed, the handle announces the minimum (100) as its value.
122
+ facts: facts({collapsible: true, startsCollapsed: true, valueNow: 100}),
123
+ startsCollapsed: true,
124
+ },
125
+ {
126
+ id: 'bare-unbounded',
127
+ summary: 'a bare ResizeHandle whose region sets no maximum',
128
+ storyId: story('bare-unbounded'),
129
+ component: 'ResizeHandle',
130
+ label: 'Resize details pane',
131
+ facts: facts({valueMax: null}),
132
+ maxSize: null,
133
+ },
134
+ {
135
+ id: 'bare-unbounded-in-container',
136
+ summary:
137
+ 'a bare ResizeHandle whose pixel-only region sets no maximum and passes a containerRef: the first useResizable example',
138
+ storyId: story('bare-unbounded-in-container'),
139
+ component: 'ResizeHandle',
140
+ label: 'Resize details pane',
141
+ facts: facts({valueMax: null}),
142
+ maxSize: null,
143
+ inContainer: true,
144
+ },
145
+ {
146
+ id: 'bare-snapped',
147
+ summary:
148
+ 'a bare ResizeHandle whose region sets snap points [100, 200, 300, 400]: an arrow moves to the adjacent point',
149
+ storyId: story('bare-snapped'),
150
+ component: 'ResizeHandle',
151
+ label: 'Resize details pane',
152
+ // One arrow moves to the adjacent point: 100px apart here.
153
+ facts: facts({step: 100}),
154
+ snaps: [100, 200, 300, 400],
155
+ },
156
+ {
157
+ id: 'bare-documented-usage',
158
+ summary:
159
+ 'the documented minimal usage — <ResizeHandle direction resizable={region.props} /> with no aria-controls passed',
160
+ storyId: story('bare-documented-usage'),
161
+ component: 'ResizeHandle',
162
+ label: 'Resize details pane',
163
+ facts: facts(),
164
+ withoutControls: true,
165
+ },
166
+ {
167
+ id: 'bare-disabled',
168
+ summary: 'a disabled ResizeHandle: out of the Tab order and unmoving',
169
+ storyId: story('bare-disabled'),
170
+ component: 'ResizeHandle',
171
+ label: 'Resize details pane',
172
+ facts: facts({operable: false}),
173
+ disabled: true,
174
+ },
175
+ ] as const satisfies ReadonlyArray<ResizeHandleBindingState>;
176
+
177
+ export const RESIZE_HANDLE_EXCLUSIONS = [
178
+ {
179
+ id: 'sidenav-binding',
180
+ owner:
181
+ 'SideNav.test.tsx until SideNav binds this contract in its own change',
182
+ reason:
183
+ 'SideNav renders ResizeHandle in overlay position with its own collapse coupling and translated label, and hides the handle entirely while the nav is collapsed, so the collapse-and-restore row cannot run against it as written; SideNav binds separately with states shaped for that.',
184
+ },
185
+ {
186
+ id: 'pointer-drag-model',
187
+ owner: 'ResizeHandle.test.tsx pointer suites',
188
+ reason:
189
+ "Dragging (pointer capture on the grab zone, ignoring a pointer that does not own the drag, ending on pointercancel or lost capture), double-click collapse and restore, and the grab-zone geometry are pointer behavior outside the keyboard-and-semantics pattern; the component's own jsdom pointer suites prove them. ResizeHandle has no Escape cancel and no Chromium pointer suite.",
190
+ },
191
+ {
192
+ id: 'pane-cycling',
193
+ owner: 'component:Resizable AR1 (not adopted) and the composing page',
194
+ reason:
195
+ "F6 pane cycling is an optional part of the APG pattern that the record does not adopt; which panes exist and how focus cycles among them is the composing page's decision.",
196
+ },
197
+ ] as const;