@astryxdesign/core 0.1.2 → 0.1.3-canary.6d57c8d

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 (567) hide show
  1. package/CHANGELOG.md +165 -0
  2. package/README.md +12 -12
  3. package/dist/Avatar/Avatar.d.ts.map +1 -1
  4. package/dist/Avatar/Avatar.js +11 -5
  5. package/dist/Breadcrumbs/BreadcrumbItem.d.ts +1 -1
  6. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  7. package/dist/Breadcrumbs/BreadcrumbItem.js +24 -5
  8. package/dist/Button/Button.d.ts.map +1 -1
  9. package/dist/Button/Button.js +2 -4
  10. package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
  11. package/dist/ButtonGroup/ButtonGroup.js +0 -1
  12. package/dist/Calendar/Calendar.d.ts +5 -4
  13. package/dist/Calendar/Calendar.d.ts.map +1 -1
  14. package/dist/Calendar/Calendar.js +82 -43
  15. package/dist/Calendar/hooks/index.d.ts +0 -2
  16. package/dist/Calendar/hooks/index.d.ts.map +1 -1
  17. package/dist/Calendar/hooks/index.js +1 -2
  18. package/dist/Calendar/index.d.ts +3 -3
  19. package/dist/Calendar/index.d.ts.map +1 -1
  20. package/dist/Calendar/index.js +1 -1
  21. package/dist/Calendar/styles.d.ts +3 -9
  22. package/dist/Calendar/styles.d.ts.map +1 -1
  23. package/dist/Calendar/styles.js +3 -11
  24. package/dist/Carousel/Carousel.d.ts.map +1 -1
  25. package/dist/Carousel/Carousel.js +17 -3
  26. package/dist/Center/Center.d.ts +11 -1
  27. package/dist/Center/Center.d.ts.map +1 -1
  28. package/dist/Center/Center.js +9 -3
  29. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  30. package/dist/Chat/ChatComposerInput.js +0 -1
  31. package/dist/Chat/ChatMessageList.d.ts +14 -1
  32. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  33. package/dist/Chat/ChatMessageList.js +2 -0
  34. package/dist/Chat/useTriggerMenu.d.ts +8 -1
  35. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  36. package/dist/Chat/useTriggerMenu.js +15 -3
  37. package/dist/CheckboxInput/CheckboxInput.d.ts +23 -2
  38. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  39. package/dist/CheckboxInput/CheckboxInput.js +51 -9
  40. package/dist/CheckboxList/CheckboxList.d.ts +13 -1
  41. package/dist/CheckboxList/CheckboxList.d.ts.map +1 -1
  42. package/dist/CheckboxList/CheckboxList.js +39 -9
  43. package/dist/CheckboxList/CheckboxListContext.d.ts +7 -0
  44. package/dist/CheckboxList/CheckboxListContext.d.ts.map +1 -1
  45. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  46. package/dist/CheckboxList/CheckboxListItem.js +0 -1
  47. package/dist/Citation/Citation.d.ts.map +1 -1
  48. package/dist/Citation/Citation.js +9 -5
  49. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  50. package/dist/CodeBlock/CodeBlock.js +51 -37
  51. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  52. package/dist/CommandPalette/CommandPalette.js +5 -5
  53. package/dist/ContextMenu/ContextMenu.d.ts +4 -5
  54. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  55. package/dist/ContextMenu/ContextMenu.js +93 -11
  56. package/dist/DateInput/DateInput.d.ts +23 -1
  57. package/dist/DateInput/DateInput.d.ts.map +1 -1
  58. package/dist/DateInput/DateInput.js +167 -99
  59. package/dist/DateRangeInput/DateRangeInput.d.ts +23 -1
  60. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  61. package/dist/DateRangeInput/DateRangeInput.js +42 -9
  62. package/dist/DateTimeInput/DateTimeInput.d.ts +35 -2
  63. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  64. package/dist/DateTimeInput/DateTimeInput.js +78 -15
  65. package/dist/Dialog/Dialog.d.ts.map +1 -1
  66. package/dist/Dialog/Dialog.js +12 -0
  67. package/dist/DropdownMenu/DropdownMenu.d.ts +1 -8
  68. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  69. package/dist/DropdownMenu/DropdownMenu.js +42 -14
  70. package/dist/Field/Field.d.ts +19 -2
  71. package/dist/Field/Field.d.ts.map +1 -1
  72. package/dist/Field/Field.js +4 -0
  73. package/dist/Field/FieldLabel.d.ts +21 -2
  74. package/dist/Field/FieldLabel.d.ts.map +1 -1
  75. package/dist/Field/FieldLabel.js +41 -26
  76. package/dist/FileInput/FileInput.d.ts +22 -1
  77. package/dist/FileInput/FileInput.d.ts.map +1 -1
  78. package/dist/FileInput/FileInput.js +56 -10
  79. package/dist/Grid/Grid.d.ts +11 -1
  80. package/dist/Grid/Grid.d.ts.map +1 -1
  81. package/dist/Grid/Grid.js +32 -6
  82. package/dist/InputGroup/InputGroup.d.ts +4 -3
  83. package/dist/InputGroup/InputGroup.d.ts.map +1 -1
  84. package/dist/InputGroup/InputGroup.js +16 -6
  85. package/dist/InputGroup/InputGroupContext.d.ts +4 -0
  86. package/dist/InputGroup/InputGroupContext.d.ts.map +1 -1
  87. package/dist/InputGroup/InputGroupContext.js +2 -2
  88. package/dist/InputGroup/groupStyles.d.ts +1 -1
  89. package/dist/InputGroup/groupStyles.d.ts.map +1 -1
  90. package/dist/InputGroup/groupStyles.js +3 -3
  91. package/dist/InputGroup/index.d.ts +1 -0
  92. package/dist/InputGroup/index.d.ts.map +1 -1
  93. package/dist/Kbd/Kbd.d.ts.map +1 -1
  94. package/dist/Kbd/Kbd.js +33 -1
  95. package/dist/Layer/layerAnimations.stylex.d.ts +4 -0
  96. package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
  97. package/dist/Layer/layerAnimations.stylex.js +8 -4
  98. package/dist/Layer/useLayer.d.ts +10 -0
  99. package/dist/Layer/useLayer.d.ts.map +1 -1
  100. package/dist/Layer/useLayer.js +64 -9
  101. package/dist/Layout/Layout.d.ts +4 -11
  102. package/dist/Layout/Layout.d.ts.map +1 -1
  103. package/dist/Layout/Layout.js +10 -11
  104. package/dist/Layout/LayoutFooter.d.ts +2 -2
  105. package/dist/Layout/LayoutFooter.d.ts.map +1 -1
  106. package/dist/Layout/LayoutHeader.d.ts +2 -2
  107. package/dist/Layout/LayoutHeader.d.ts.map +1 -1
  108. package/dist/Layout/LayoutPanel.d.ts +2 -2
  109. package/dist/Layout/LayoutPanel.d.ts.map +1 -1
  110. package/dist/Layout/padding.stylex.d.ts +51 -0
  111. package/dist/Layout/padding.stylex.d.ts.map +1 -1
  112. package/dist/Layout/padding.stylex.js +63 -0
  113. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  114. package/dist/Lightbox/Lightbox.js +4 -2
  115. package/dist/Link/Link.d.ts +16 -1
  116. package/dist/Link/Link.d.ts.map +1 -1
  117. package/dist/Link/Link.js +18 -7
  118. package/dist/Markdown/Markdown.d.ts.map +1 -1
  119. package/dist/Markdown/Markdown.js +7 -0
  120. package/dist/MoreMenu/MoreMenu.d.ts +1 -7
  121. package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
  122. package/dist/MoreMenu/MoreMenu.js +0 -2
  123. package/dist/MultiSelector/MultiSelector.d.ts +27 -2
  124. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  125. package/dist/MultiSelector/MultiSelector.js +141 -42
  126. package/dist/MultiSelector/hooks.d.ts +12 -1
  127. package/dist/MultiSelector/hooks.d.ts.map +1 -1
  128. package/dist/MultiSelector/hooks.js +14 -1
  129. package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
  130. package/dist/NavMenu/NavHeadingMenu.js +34 -3
  131. package/dist/NumberInput/NumberInput.d.ts +23 -2
  132. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  133. package/dist/NumberInput/NumberInput.js +62 -12
  134. package/dist/Pagination/Pagination.d.ts +1 -1
  135. package/dist/Pagination/Pagination.d.ts.map +1 -1
  136. package/dist/Pagination/Pagination.js +15 -1
  137. package/dist/Popover/Popover.d.ts +18 -2
  138. package/dist/Popover/Popover.d.ts.map +1 -1
  139. package/dist/Popover/Popover.js +5 -2
  140. package/dist/Popover/usePopover.d.ts +38 -3
  141. package/dist/Popover/usePopover.d.ts.map +1 -1
  142. package/dist/Popover/usePopover.js +24 -9
  143. package/dist/PowerSearch/PowerSearch.d.ts +11 -1
  144. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  145. package/dist/PowerSearch/PowerSearch.js +6 -1
  146. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  147. package/dist/ProgressBar/ProgressBar.js +3 -5
  148. package/dist/RadioList/RadioList.d.ts +20 -2
  149. package/dist/RadioList/RadioList.d.ts.map +1 -1
  150. package/dist/RadioList/RadioList.js +105 -9
  151. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  152. package/dist/RadioList/RadioListItem.js +13 -2
  153. package/dist/SegmentedControl/SegmentedControl.d.ts +13 -2
  154. package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  155. package/dist/SegmentedControl/SegmentedControl.js +78 -44
  156. package/dist/SegmentedControl/SegmentedControlContext.d.ts +7 -0
  157. package/dist/SegmentedControl/SegmentedControlContext.d.ts.map +1 -1
  158. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  159. package/dist/SegmentedControl/SegmentedControlItem.js +13 -2
  160. package/dist/Selector/Selector.d.ts +24 -1
  161. package/dist/Selector/Selector.d.ts.map +1 -1
  162. package/dist/Selector/Selector.js +122 -43
  163. package/dist/Selector/hooks.d.ts +8 -1
  164. package/dist/Selector/hooks.d.ts.map +1 -1
  165. package/dist/Selector/hooks.js +14 -1
  166. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  167. package/dist/SideNav/SideNavHeading.js +2 -0
  168. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  169. package/dist/SideNav/SideNavItem.js +1 -1
  170. package/dist/Skeleton/Skeleton.d.ts.map +1 -1
  171. package/dist/Skeleton/Skeleton.js +8 -2
  172. package/dist/Slider/Slider.d.ts +21 -0
  173. package/dist/Slider/Slider.d.ts.map +1 -1
  174. package/dist/Slider/Slider.js +36 -9
  175. package/dist/Spinner/Spinner.d.ts.map +1 -1
  176. package/dist/Spinner/Spinner.js +1 -1
  177. package/dist/Stack/Stack.d.ts +38 -23
  178. package/dist/Stack/Stack.d.ts.map +1 -1
  179. package/dist/Stack/Stack.js +25 -1
  180. package/dist/Stack/StackItem.d.ts +12 -23
  181. package/dist/Stack/StackItem.d.ts.map +1 -1
  182. package/dist/Stack/StackItem.js +8 -1
  183. package/dist/Switch/Switch.d.ts +23 -2
  184. package/dist/Switch/Switch.d.ts.map +1 -1
  185. package/dist/Switch/Switch.js +41 -11
  186. package/dist/TabList/Tab.d.ts.map +1 -1
  187. package/dist/TabList/Tab.js +6 -0
  188. package/dist/TabList/TabList.d.ts +16 -4
  189. package/dist/TabList/TabList.d.ts.map +1 -1
  190. package/dist/TabList/TabList.js +87 -10
  191. package/dist/TabList/TabListContext.d.ts +5 -0
  192. package/dist/TabList/TabListContext.d.ts.map +1 -1
  193. package/dist/TabList/TabListContext.js +5 -0
  194. package/dist/TabList/TabMenu.d.ts.map +1 -1
  195. package/dist/TabList/TabMenu.js +6 -1
  196. package/dist/Table/BaseTable.d.ts.map +1 -1
  197. package/dist/Table/BaseTable.js +11 -8
  198. package/dist/Table/Table.d.ts.map +1 -1
  199. package/dist/Table/Table.js +10 -1
  200. package/dist/Table/TableCell.d.ts +8 -1
  201. package/dist/Table/TableCell.d.ts.map +1 -1
  202. package/dist/Table/TableCell.js +10 -10
  203. package/dist/Table/TableHeaderCell.d.ts +8 -1
  204. package/dist/Table/TableHeaderCell.d.ts.map +1 -1
  205. package/dist/Table/TableHeaderCell.js +16 -16
  206. package/dist/Table/index.d.ts +2 -1
  207. package/dist/Table/index.d.ts.map +1 -1
  208. package/dist/Table/index.js +2 -2
  209. package/dist/Table/plugins/pagination/paginateData.d.ts +2 -1
  210. package/dist/Table/plugins/pagination/paginateData.d.ts.map +1 -1
  211. package/dist/Table/plugins/pagination/paginateData.js +8 -3
  212. package/dist/Table/plugins/pagination/useTablePagination.d.ts.map +1 -1
  213. package/dist/Table/plugins/pagination/useTablePagination.js +6 -1
  214. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  215. package/dist/Table/plugins/sortable/useTableSortable.js +59 -3
  216. package/dist/Table/tableContextMenu.d.ts +33 -0
  217. package/dist/Table/tableContextMenu.d.ts.map +1 -0
  218. package/dist/Table/tableContextMenu.js +133 -0
  219. package/dist/Table/types.d.ts +66 -0
  220. package/dist/Table/types.d.ts.map +1 -1
  221. package/dist/TextArea/TextArea.d.ts +22 -1
  222. package/dist/TextArea/TextArea.d.ts.map +1 -1
  223. package/dist/TextArea/TextArea.js +41 -9
  224. package/dist/TextInput/TextInput.d.ts +23 -2
  225. package/dist/TextInput/TextInput.d.ts.map +1 -1
  226. package/dist/TextInput/TextInput.js +55 -10
  227. package/dist/TimeInput/TimeInput.d.ts +23 -1
  228. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  229. package/dist/TimeInput/TimeInput.js +147 -76
  230. package/dist/Toast/Toast.d.ts.map +1 -1
  231. package/dist/Toast/Toast.js +14 -0
  232. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  233. package/dist/Toast/ToastViewport.js +131 -3
  234. package/dist/Tokenizer/Tokenizer.d.ts +12 -1
  235. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  236. package/dist/Tokenizer/Tokenizer.js +26 -4
  237. package/dist/Toolbar/Toolbar.d.ts +3 -3
  238. package/dist/Toolbar/Toolbar.d.ts.map +1 -1
  239. package/dist/Toolbar/Toolbar.js +51 -7
  240. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  241. package/dist/Tooltip/useTooltip.js +56 -9
  242. package/dist/TopNav/TopNavHeading.d.ts +7 -1
  243. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  244. package/dist/TopNav/TopNavHeading.js +8 -0
  245. package/dist/TreeList/TreeList.d.ts +1 -1
  246. package/dist/TreeList/TreeList.d.ts.map +1 -1
  247. package/dist/TreeList/TreeList.js +72 -2
  248. package/dist/TreeList/TreeListItem.d.ts +11 -1
  249. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  250. package/dist/TreeList/TreeListItem.js +51 -12
  251. package/dist/TreeList/treeListItem.markers.stylex.d.ts +16 -0
  252. package/dist/TreeList/treeListItem.markers.stylex.d.ts.map +1 -0
  253. package/dist/TreeList/treeListItem.markers.stylex.js +22 -0
  254. package/dist/Typeahead/BaseTypeahead.d.ts +13 -0
  255. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  256. package/dist/Typeahead/BaseTypeahead.js +69 -6
  257. package/dist/Typeahead/Typeahead.d.ts +26 -3
  258. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  259. package/dist/Typeahead/Typeahead.js +65 -29
  260. package/dist/VisuallyHidden/VisuallyHidden.d.ts +61 -0
  261. package/dist/VisuallyHidden/VisuallyHidden.d.ts.map +1 -0
  262. package/dist/VisuallyHidden/VisuallyHidden.js +65 -0
  263. package/dist/VisuallyHidden/index.d.ts +11 -0
  264. package/dist/VisuallyHidden/index.d.ts.map +1 -0
  265. package/dist/VisuallyHidden/index.js +13 -0
  266. package/dist/astryx.css +18 -0
  267. package/dist/astryx.umd.js +55 -55
  268. package/dist/astryx.umd.js.map +4 -4
  269. package/dist/hooks/focusableSelector.d.ts +22 -0
  270. package/dist/hooks/focusableSelector.d.ts.map +1 -0
  271. package/dist/hooks/focusableSelector.js +24 -0
  272. package/dist/hooks/index.d.ts +12 -2
  273. package/dist/hooks/index.d.ts.map +1 -1
  274. package/dist/hooks/index.js +7 -2
  275. package/dist/hooks/useAnnounce.d.ts +40 -0
  276. package/dist/hooks/useAnnounce.d.ts.map +1 -0
  277. package/dist/hooks/useAnnounce.js +142 -0
  278. package/dist/hooks/useClickableContainer.d.ts +16 -1
  279. package/dist/hooks/useClickableContainer.d.ts.map +1 -1
  280. package/dist/hooks/useClickableContainer.js +16 -4
  281. package/dist/hooks/useEntryAnimation.d.ts.map +1 -1
  282. package/dist/hooks/useEntryAnimation.js +4 -4
  283. package/dist/hooks/useFocusTrap.d.ts +18 -0
  284. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  285. package/dist/hooks/useFocusTrap.js +87 -3
  286. package/dist/hooks/useGridFocus.d.ts +88 -1
  287. package/dist/hooks/useGridFocus.d.ts.map +1 -1
  288. package/dist/hooks/useGridFocus.js +261 -62
  289. package/dist/hooks/useKeyboardHint.d.ts +82 -0
  290. package/dist/hooks/useKeyboardHint.d.ts.map +1 -0
  291. package/dist/hooks/useKeyboardHint.js +220 -0
  292. package/dist/hooks/useListFocus.d.ts +78 -7
  293. package/dist/hooks/useListFocus.d.ts.map +1 -1
  294. package/dist/hooks/useListFocus.js +305 -52
  295. package/dist/hooks/useLongPress.d.ts +21 -0
  296. package/dist/hooks/useLongPress.d.ts.map +1 -0
  297. package/dist/hooks/useLongPress.js +89 -0
  298. package/dist/hooks/useTreeFocus.d.ts +157 -0
  299. package/dist/hooks/useTreeFocus.d.ts.map +1 -0
  300. package/dist/hooks/useTreeFocus.js +337 -0
  301. package/dist/hooks/useTypeahead.d.ts +63 -0
  302. package/dist/hooks/useTypeahead.d.ts.map +1 -0
  303. package/dist/hooks/useTypeahead.js +117 -0
  304. package/dist/index.d.ts +1 -0
  305. package/dist/index.d.ts.map +1 -1
  306. package/dist/index.js +1 -0
  307. package/dist/utils/dateTypes.d.ts +12 -0
  308. package/dist/utils/dateTypes.d.ts.map +1 -1
  309. package/dist/utils/dateTypes.js +41 -1
  310. package/dist/utils/index.d.ts +4 -0
  311. package/dist/utils/index.d.ts.map +1 -1
  312. package/dist/utils/index.js +3 -1
  313. package/dist/utils/inputAria.d.ts +29 -0
  314. package/dist/utils/inputAria.d.ts.map +1 -0
  315. package/dist/utils/inputAria.js +30 -0
  316. package/dist/utils/timeParser.d.ts.map +1 -1
  317. package/dist/utils/timeParser.js +5 -2
  318. package/docs.mjs +2 -2
  319. package/package.json +12 -8
  320. package/src/Avatar/Avatar.test.tsx +37 -0
  321. package/src/Avatar/Avatar.tsx +10 -5
  322. package/src/Breadcrumbs/BreadcrumbItem.tsx +25 -7
  323. package/src/Breadcrumbs/Breadcrumbs.test.tsx +31 -10
  324. package/src/Button/Button.tsx +3 -16
  325. package/src/ButtonGroup/ButtonGroup.test.tsx +9 -9
  326. package/src/ButtonGroup/ButtonGroup.tsx +0 -1
  327. package/src/Calendar/Calendar.doc.mjs +4 -4
  328. package/src/Calendar/Calendar.test.tsx +168 -30
  329. package/src/Calendar/Calendar.tsx +121 -66
  330. package/src/Calendar/hooks/index.ts +0 -6
  331. package/src/Calendar/index.ts +1 -3
  332. package/src/Calendar/styles.ts +4 -9
  333. package/src/Carousel/Carousel.doc.mjs +7 -1
  334. package/src/Carousel/Carousel.test.tsx +20 -0
  335. package/src/Carousel/Carousel.tsx +16 -1
  336. package/src/Center/Center.doc.mjs +12 -2
  337. package/src/Center/Center.tsx +28 -3
  338. package/src/Chat/ChatComposerInput.test.tsx +26 -7
  339. package/src/Chat/ChatComposerInput.tsx +0 -1
  340. package/src/Chat/ChatDictationButton.doc.mjs +1 -1
  341. package/src/Chat/ChatMessageList.doc.mjs +8 -0
  342. package/src/Chat/ChatMessageList.test.tsx +18 -0
  343. package/src/Chat/ChatMessageList.tsx +16 -0
  344. package/src/Chat/useTriggerMenu.tsx +22 -4
  345. package/src/CheckboxInput/CheckboxInput.doc.mjs +10 -0
  346. package/src/CheckboxInput/CheckboxInput.test.tsx +172 -27
  347. package/src/CheckboxInput/CheckboxInput.tsx +78 -6
  348. package/src/CheckboxList/CheckboxList.doc.mjs +9 -0
  349. package/src/CheckboxList/CheckboxList.test.tsx +192 -26
  350. package/src/CheckboxList/CheckboxList.tsx +56 -3
  351. package/src/CheckboxList/CheckboxListContext.tsx +7 -0
  352. package/src/CheckboxList/CheckboxListItem.tsx +0 -3
  353. package/src/Citation/Citation.doc.mjs +10 -0
  354. package/src/Citation/Citation.test.tsx +121 -0
  355. package/src/Citation/Citation.tsx +15 -3
  356. package/src/CodeBlock/CodeBlock.test.tsx +115 -0
  357. package/src/CodeBlock/CodeBlock.tsx +63 -33
  358. package/src/CommandPalette/CommandPalette.test.tsx +47 -1
  359. package/src/CommandPalette/CommandPalette.tsx +9 -21
  360. package/src/ContextMenu/ContextMenu.doc.mjs +4 -4
  361. package/src/ContextMenu/ContextMenu.test.tsx +155 -1
  362. package/src/ContextMenu/ContextMenu.tsx +113 -16
  363. package/src/DateInput/DateInput.doc.mjs +286 -56
  364. package/src/DateInput/DateInput.test.tsx +248 -2
  365. package/src/DateInput/DateInput.tsx +196 -100
  366. package/src/DateRangeInput/DateRangeInput.doc.mjs +251 -46
  367. package/src/DateRangeInput/DateRangeInput.test.tsx +182 -20
  368. package/src/DateRangeInput/DateRangeInput.tsx +63 -5
  369. package/src/DateTimeInput/DateTimeInput.doc.mjs +368 -67
  370. package/src/DateTimeInput/DateTimeInput.test.tsx +279 -11
  371. package/src/DateTimeInput/DateTimeInput.tsx +125 -17
  372. package/src/Dialog/Dialog.doc.mjs +2 -2
  373. package/src/Dialog/Dialog.tsx +12 -0
  374. package/src/DropdownMenu/DropdownMenu.doc.mjs +1 -8
  375. package/src/DropdownMenu/DropdownMenu.test.tsx +56 -42
  376. package/src/DropdownMenu/DropdownMenu.tsx +52 -18
  377. package/src/Field/Field.doc.mjs +59 -18
  378. package/src/Field/Field.test.tsx +32 -0
  379. package/src/Field/Field.tsx +23 -5
  380. package/src/Field/FieldLabel.tsx +55 -17
  381. package/src/FileInput/FileInput.doc.mjs +17 -0
  382. package/src/FileInput/FileInput.test.tsx +283 -49
  383. package/src/FileInput/FileInput.tsx +76 -4
  384. package/src/Grid/Grid.doc.mjs +17 -4
  385. package/src/Grid/Grid.test.tsx +43 -30
  386. package/src/Grid/Grid.tsx +38 -3
  387. package/src/Icon/Icon.doc.mjs +3 -3
  388. package/src/InputGroup/InputGroup.doc.mjs +111 -23
  389. package/src/InputGroup/InputGroup.test.tsx +257 -60
  390. package/src/InputGroup/InputGroup.tsx +23 -5
  391. package/src/InputGroup/InputGroupContext.ts +9 -4
  392. package/src/InputGroup/groupStyles.ts +7 -1
  393. package/src/InputGroup/index.ts +1 -0
  394. package/src/Kbd/Kbd.test.tsx +22 -4
  395. package/src/Kbd/Kbd.tsx +35 -3
  396. package/src/Layer/layerAnimations.stylex.ts +20 -4
  397. package/src/Layer/useLayer.doc.mjs +5 -0
  398. package/src/Layer/useLayer.test.tsx +111 -0
  399. package/src/Layer/useLayer.tsx +90 -9
  400. package/src/Layout/Layout.tsx +8 -16
  401. package/src/Layout/LayoutFooter.doc.mjs +4 -4
  402. package/src/Layout/LayoutFooter.tsx +3 -3
  403. package/src/Layout/LayoutHeader.doc.mjs +4 -4
  404. package/src/Layout/LayoutHeader.tsx +3 -3
  405. package/src/Layout/LayoutPanel.tsx +3 -3
  406. package/src/Layout/padding.stylex.ts +52 -0
  407. package/src/Lightbox/Lightbox.doc.mjs +9 -0
  408. package/src/Lightbox/Lightbox.test.tsx +53 -5
  409. package/src/Lightbox/Lightbox.tsx +9 -4
  410. package/src/Link/Link.doc.mjs +14 -0
  411. package/src/Link/Link.test.tsx +50 -0
  412. package/src/Link/Link.tsx +39 -4
  413. package/src/Markdown/Markdown.test.tsx +11 -0
  414. package/src/Markdown/Markdown.tsx +7 -0
  415. package/src/MetadataList/MetadataListItem.doc.mjs +4 -0
  416. package/src/MoreMenu/MoreMenu.doc.mjs +2 -17
  417. package/src/MoreMenu/MoreMenu.tsx +0 -9
  418. package/src/MultiSelector/MultiSelector.doc.mjs +30 -0
  419. package/src/MultiSelector/MultiSelector.test.tsx +375 -8
  420. package/src/MultiSelector/MultiSelector.tsx +194 -48
  421. package/src/MultiSelector/hooks.ts +27 -0
  422. package/src/NavMenu/NavHeadingMenu.test.tsx +77 -1
  423. package/src/NavMenu/NavHeadingMenu.tsx +50 -3
  424. package/src/NumberInput/NumberInput.doc.mjs +17 -0
  425. package/src/NumberInput/NumberInput.test.tsx +242 -40
  426. package/src/NumberInput/NumberInput.tsx +89 -11
  427. package/src/Pagination/Pagination.doc.mjs +3 -3
  428. package/src/Pagination/Pagination.test.tsx +117 -5
  429. package/src/Pagination/Pagination.tsx +21 -1
  430. package/src/Popover/Popover.doc.mjs +26 -0
  431. package/src/Popover/Popover.test.tsx +121 -0
  432. package/src/Popover/Popover.tsx +23 -2
  433. package/src/Popover/usePopover.doc.mjs +9 -3
  434. package/src/Popover/usePopover.tsx +70 -12
  435. package/src/PowerSearch/PowerSearch.doc.mjs +15 -0
  436. package/src/PowerSearch/PowerSearch.test.tsx +97 -1
  437. package/src/PowerSearch/PowerSearch.tsx +16 -3
  438. package/src/ProgressBar/ProgressBar.test.tsx +34 -26
  439. package/src/ProgressBar/ProgressBar.tsx +3 -4
  440. package/src/RadioList/RadioList.doc.mjs +9 -0
  441. package/src/RadioList/RadioList.test.tsx +252 -16
  442. package/src/RadioList/RadioList.tsx +166 -10
  443. package/src/RadioList/RadioListItem.tsx +14 -2
  444. package/src/SegmentedControl/SegmentedControl.doc.mjs +9 -0
  445. package/src/SegmentedControl/SegmentedControl.test.tsx +214 -42
  446. package/src/SegmentedControl/SegmentedControl.tsx +102 -54
  447. package/src/SegmentedControl/SegmentedControlContext.ts +7 -0
  448. package/src/SegmentedControl/SegmentedControlItem.tsx +14 -1
  449. package/src/SelectableCard/SelectableCard.doc.mjs +1 -1
  450. package/src/Selector/Selector.doc.mjs +26 -0
  451. package/src/Selector/Selector.test.tsx +387 -15
  452. package/src/Selector/Selector.tsx +175 -67
  453. package/src/Selector/hooks.ts +23 -0
  454. package/src/SideNav/SideNav.test.tsx +48 -0
  455. package/src/SideNav/SideNavHeading.tsx +8 -2
  456. package/src/SideNav/SideNavItem.tsx +2 -4
  457. package/src/Skeleton/Skeleton.test.tsx +25 -0
  458. package/src/Skeleton/Skeleton.tsx +11 -1
  459. package/src/Slider/Slider.doc.mjs +15 -0
  460. package/src/Slider/Slider.test.tsx +155 -2
  461. package/src/Slider/Slider.tsx +53 -5
  462. package/src/Spinner/Spinner.tsx +7 -1
  463. package/src/Stack/Stack.doc.mjs +77 -0
  464. package/src/Stack/Stack.test.tsx +55 -5
  465. package/src/Stack/Stack.tsx +73 -24
  466. package/src/Stack/StackItem.test.tsx +23 -0
  467. package/src/Stack/StackItem.tsx +20 -23
  468. package/src/Switch/Switch.doc.mjs +15 -0
  469. package/src/Switch/Switch.test.tsx +162 -27
  470. package/src/Switch/Switch.tsx +61 -21
  471. package/src/TabList/Tab.tsx +6 -0
  472. package/src/TabList/TabList.doc.mjs +6 -0
  473. package/src/TabList/TabList.test.tsx +251 -0
  474. package/src/TabList/TabList.tsx +103 -12
  475. package/src/TabList/TabListContext.ts +7 -3
  476. package/src/TabList/TabMenu.tsx +6 -3
  477. package/src/Table/BaseTable.tsx +21 -17
  478. package/src/Table/Table.doc.mjs +2 -0
  479. package/src/Table/Table.test.tsx +10 -0
  480. package/src/Table/Table.tsx +8 -0
  481. package/src/Table/TableCell.tsx +25 -23
  482. package/src/Table/TableHeaderCell.tsx +28 -29
  483. package/src/Table/index.ts +3 -2
  484. package/src/Table/plugins/pagination/paginateData.ts +10 -3
  485. package/src/Table/plugins/pagination/useTablePagination.test.tsx +16 -0
  486. package/src/Table/plugins/pagination/useTablePagination.tsx +8 -1
  487. package/src/Table/plugins/sortable/useTableSortable.test.tsx +91 -2
  488. package/src/Table/plugins/sortable/useTableSortable.tsx +53 -1
  489. package/src/Table/tableContextMenu.test.tsx +157 -0
  490. package/src/Table/tableContextMenu.tsx +142 -0
  491. package/src/Table/types.ts +74 -0
  492. package/src/Table/useTableColumnResize.doc.mjs +3 -3
  493. package/src/Table/useTableStickyColumns.doc.mjs +2 -2
  494. package/src/Text/Text.doc.mjs +18 -18
  495. package/src/TextArea/TextArea.doc.mjs +17 -0
  496. package/src/TextArea/TextArea.test.tsx +167 -35
  497. package/src/TextArea/TextArea.tsx +62 -15
  498. package/src/TextInput/TextInput.doc.mjs +17 -0
  499. package/src/TextInput/TextInput.test.tsx +168 -34
  500. package/src/TextInput/TextInput.tsx +77 -9
  501. package/src/Thumbnail/Thumbnail.doc.mjs +4 -4
  502. package/src/TimeInput/TimeInput.doc.mjs +340 -60
  503. package/src/TimeInput/TimeInput.test.tsx +255 -7
  504. package/src/TimeInput/TimeInput.tsx +176 -70
  505. package/src/Timestamp/Timestamp.doc.mjs +19 -19
  506. package/src/Toast/Toast.tsx +14 -0
  507. package/src/Toast/ToastViewport.test.tsx +214 -0
  508. package/src/Toast/ToastViewport.tsx +167 -21
  509. package/src/Tokenizer/Tokenizer.doc.mjs +29 -14
  510. package/src/Tokenizer/Tokenizer.test.tsx +105 -1
  511. package/src/Tokenizer/Tokenizer.tsx +37 -1
  512. package/src/Toolbar/Toolbar.test.tsx +109 -6
  513. package/src/Toolbar/Toolbar.tsx +59 -5
  514. package/src/Tooltip/Tooltip.test.tsx +68 -0
  515. package/src/Tooltip/useTooltip.tsx +55 -8
  516. package/src/TopNav/TopNav.test.tsx +50 -0
  517. package/src/TopNav/TopNavHeading.tsx +17 -1
  518. package/src/TreeList/TreeList.test.tsx +295 -6
  519. package/src/TreeList/TreeList.tsx +73 -1
  520. package/src/TreeList/TreeListItem.tsx +51 -5
  521. package/src/TreeList/treeListItem.markers.stylex.ts +20 -0
  522. package/src/Typeahead/BaseTypeahead.tsx +93 -9
  523. package/src/Typeahead/Typeahead.doc.mjs +141 -30
  524. package/src/Typeahead/Typeahead.test.tsx +331 -1
  525. package/src/Typeahead/Typeahead.tsx +105 -33
  526. package/src/VisuallyHidden/VisuallyHidden.doc.mjs +80 -0
  527. package/src/VisuallyHidden/VisuallyHidden.test.tsx +76 -0
  528. package/src/VisuallyHidden/VisuallyHidden.tsx +113 -0
  529. package/src/VisuallyHidden/index.ts +15 -0
  530. package/src/docs-script.test.mjs +50 -0
  531. package/src/hooks/focusableSelector.ts +25 -0
  532. package/src/hooks/index.ts +28 -2
  533. package/src/hooks/useAnnounce.test.tsx +101 -0
  534. package/src/hooks/useAnnounce.ts +168 -0
  535. package/src/hooks/useClickableContainer.ts +16 -4
  536. package/src/hooks/useEntryAnimation.ts +16 -4
  537. package/src/hooks/useFocusTrap.test.tsx +132 -0
  538. package/src/hooks/useFocusTrap.ts +98 -4
  539. package/src/hooks/useGridFocus.doc.mjs +40 -2
  540. package/src/hooks/useGridFocus.test.tsx +132 -0
  541. package/src/hooks/useGridFocus.ts +343 -67
  542. package/src/hooks/useKeyboardHint.doc.mjs +101 -0
  543. package/src/hooks/useKeyboardHint.test.tsx +70 -0
  544. package/src/hooks/useKeyboardHint.tsx +332 -0
  545. package/src/hooks/useListFocus.doc.mjs +50 -10
  546. package/src/hooks/useListFocus.test.tsx +375 -0
  547. package/src/hooks/useListFocus.ts +395 -57
  548. package/src/hooks/useLongPress.test.tsx +134 -0
  549. package/src/hooks/useLongPress.ts +119 -0
  550. package/src/hooks/useTreeFocus.doc.mjs +140 -0
  551. package/src/hooks/useTreeFocus.test.tsx +214 -0
  552. package/src/hooks/useTreeFocus.ts +559 -0
  553. package/src/hooks/useTypeahead.test.tsx +109 -0
  554. package/src/hooks/useTypeahead.ts +183 -0
  555. package/src/index.ts +1 -0
  556. package/src/theme/derivedVarRegistry.test.ts +10 -5
  557. package/src/utils/dateTypes.test.ts +40 -0
  558. package/src/utils/dateTypes.ts +40 -0
  559. package/src/utils/index.ts +9 -0
  560. package/src/utils/inputAria.test.ts +39 -0
  561. package/src/utils/inputAria.ts +58 -0
  562. package/src/utils/timeParser.test.ts +10 -0
  563. package/src/utils/timeParser.ts +5 -2
  564. package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts +0 -57
  565. package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts.map +0 -1
  566. package/dist/Calendar/hooks/useCalendarRovingTabindex.js +0 -96
  567. package/src/Calendar/hooks/useCalendarRovingTabindex.ts +0 -118
@@ -0,0 +1,76 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file VisuallyHidden.test.tsx
5
+ * @input Uses vitest, @testing-library/react, VisuallyHidden component
6
+ * @output Unit tests for VisuallyHidden rendering + a11y behavior
7
+ * @position Testing; validates VisuallyHidden.tsx implementation
8
+ *
9
+ * SYNC: When VisuallyHidden.tsx changes, update tests to match new behavior
10
+ */
11
+
12
+ import {describe, it, expect} from 'vitest';
13
+ import {render, screen} from '@testing-library/react';
14
+ import {createRef} from 'react';
15
+ import {VisuallyHidden} from './VisuallyHidden';
16
+
17
+ describe('VisuallyHidden', () => {
18
+ it('renders its children in the accessibility tree', () => {
19
+ render(<VisuallyHidden>Delete incident</VisuallyHidden>);
20
+ // Present in the a11y tree (getByText finds it — it is not display:none).
21
+ expect(screen.getByText('Delete incident')).toBeInTheDocument();
22
+ });
23
+
24
+ it('renders a <span> by default', () => {
25
+ render(<VisuallyHidden>Label</VisuallyHidden>);
26
+ expect(screen.getByText('Label').tagName).toBe('SPAN');
27
+ });
28
+
29
+ it('renders a custom element via the `as` prop', () => {
30
+ render(
31
+ <VisuallyHidden as="div" aria-live="polite">
32
+ Moved task to Done
33
+ </VisuallyHidden>,
34
+ );
35
+ const el = screen.getByText('Moved task to Done');
36
+ expect(el.tagName).toBe('DIV');
37
+ expect(el).toHaveAttribute('aria-live', 'polite');
38
+ });
39
+
40
+ it('applies the clip styles that hide it visually', () => {
41
+ render(<VisuallyHidden>Hidden</VisuallyHidden>);
42
+ const el = screen.getByText('Hidden');
43
+ // jsdom does not apply the stylesheet, but the StyleX class is attached.
44
+ expect(el.getAttribute('class')).toBeTruthy();
45
+ // It must NOT be display:none / hidden — it stays in the a11y tree.
46
+ expect(el).not.toHaveAttribute('hidden');
47
+ });
48
+
49
+ it('forwards a ref to the rendered element', () => {
50
+ const ref = createRef<HTMLElement>();
51
+ render(<VisuallyHidden ref={ref}>Ref target</VisuallyHidden>);
52
+ expect(ref.current).toBeInstanceOf(HTMLElement);
53
+ expect(ref.current?.textContent).toBe('Ref target');
54
+ });
55
+
56
+ it('passes through arbitrary BaseProps (id, role, data-*)', () => {
57
+ render(
58
+ <VisuallyHidden id="announcer" role="status" data-testid="vh">
59
+ Status
60
+ </VisuallyHidden>,
61
+ );
62
+ const el = screen.getByTestId('vh');
63
+ expect(el).toHaveAttribute('id', 'announcer');
64
+ expect(el).toHaveAttribute('role', 'status');
65
+ });
66
+
67
+ it('gives an icon-only control an accessible name', () => {
68
+ render(
69
+ <button type="button">
70
+ <span aria-hidden="true">🗑️</span>
71
+ <VisuallyHidden>Delete</VisuallyHidden>
72
+ </button>,
73
+ );
74
+ expect(screen.getByRole('button', {name: 'Delete'})).toBeInTheDocument();
75
+ });
76
+ });
@@ -0,0 +1,113 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file VisuallyHidden.tsx
7
+ * @input Uses React createElement/ElementType, stylex
8
+ * @output Exports VisuallyHidden component and VisuallyHiddenProps
9
+ * @position Accessibility primitive; renders content in the a11y tree while
10
+ * hiding it visually (icon-only labels, aria-live regions, SR-only context)
11
+ *
12
+ * SYNC: When modified, update these files to stay in sync:
13
+ * - /packages/core/src/VisuallyHidden/VisuallyHidden.doc.mjs
14
+ * - /packages/core/src/VisuallyHidden/VisuallyHidden.test.tsx
15
+ * - /apps/storybook/stories/VisuallyHidden.stories.tsx
16
+ */
17
+
18
+ import {createElement, type ElementType, type ReactNode, type Ref} from 'react';
19
+ import type {BaseProps} from '../BaseProps';
20
+ import * as stylex from '@stylexjs/stylex';
21
+
22
+ /**
23
+ * VisuallyHidden is deliberately styling-free: it exists to *not* be seen, so it
24
+ * intentionally omits `xstyle`/`className`/`style`. The clip block is fixed and
25
+ * non-overridable — styling a visually-hidden node is always a mistake. The
26
+ * accessibility pass-throughs from `BaseProps` (`aria-*`, `role`, `id`,
27
+ * `data-*`, event handlers) remain, since the live-region use case needs them.
28
+ */
29
+ export interface VisuallyHiddenProps extends Omit<
30
+ BaseProps<HTMLElement>,
31
+ 'className' | 'style'
32
+ > {
33
+ /** Ref forwarded to the rendered element. */
34
+ ref?: React.Ref<HTMLElement>;
35
+
36
+ /** Content to expose to assistive technology while hidden from sight. */
37
+ children: ReactNode;
38
+
39
+ /**
40
+ * HTML tag to render as. Defaults to `'span'` (inline) for the common
41
+ * icon-label case; pass a block element such as `'div'` when wrapping block
42
+ * content or hosting an `aria-live` region. This is a structural choice, not
43
+ * a visual one.
44
+ *
45
+ * @default 'span'
46
+ */
47
+ as?: ElementType;
48
+ }
49
+
50
+ const styles = stylex.create({
51
+ // Canonical "visually hidden" clip block. Uses `clip: rect(...)` (not
52
+ // clip-path) for the widest assistive-tech/browser support. `inset` pins the
53
+ // 1px box to the top-left so a positioned ancestor cannot reveal it, and
54
+ // pointer/selection are disabled so the hidden node can't catch clicks or be
55
+ // text-selected.
56
+ visuallyHidden: {
57
+ position: 'absolute',
58
+ width: 1,
59
+ height: 1,
60
+ margin: -1,
61
+ padding: 0,
62
+ overflow: 'hidden',
63
+ clip: 'rect(0, 0, 0, 0)',
64
+ whiteSpace: 'nowrap',
65
+ borderStyle: 'none',
66
+ insetBlockStart: 0,
67
+ insetInlineStart: 0,
68
+ pointerEvents: 'none',
69
+ userSelect: 'none',
70
+ },
71
+ });
72
+
73
+ /**
74
+ * Renders its children in the accessibility tree while hiding them visually.
75
+ *
76
+ * Use for content that assistive technology must perceive but sighted users
77
+ * should not see: accessible names for icon-only controls, `aria-live`
78
+ * announcement regions, and supplementary screen-reader context.
79
+ *
80
+ * @example
81
+ * ```
82
+ * // Accessible name for an icon-only button
83
+ * <IconButton icon="trash" label="">
84
+ * <VisuallyHidden>Delete incident</VisuallyHidden>
85
+ * </IconButton>
86
+ *
87
+ * // Live region for announcements
88
+ * <VisuallyHidden as="div" aria-live="polite">
89
+ * {`Moved ${task} to ${column}`}
90
+ * </VisuallyHidden>
91
+ * ```
92
+ */
93
+ export function VisuallyHidden({
94
+ children,
95
+ as: element = 'span',
96
+ ref,
97
+ ...props
98
+ }: VisuallyHiddenProps) {
99
+ return createElement(
100
+ element,
101
+ {
102
+ ref: ref as Ref<Element>,
103
+ // Spread consumer props (aria-*, role, id, data-*, handlers) first, then
104
+ // the fixed clip styles, so the visually-hidden class can never be
105
+ // displaced. There is no consumer className/style to merge — by design.
106
+ ...props,
107
+ ...stylex.props(styles.visuallyHidden),
108
+ },
109
+ children,
110
+ );
111
+ }
112
+
113
+ VisuallyHidden.displayName = 'VisuallyHidden';
@@ -0,0 +1,15 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file index.ts
7
+ * @input Imports from VisuallyHidden.tsx
8
+ * @output Exports VisuallyHidden component and props type
9
+ * @position Package entry point for VisuallyHidden
10
+ *
11
+ * SYNC: When modified, update /packages/core/src/VisuallyHidden/VisuallyHidden.doc.mjs
12
+ */
13
+
14
+ export {VisuallyHidden} from './VisuallyHidden';
15
+ export type {VisuallyHiddenProps} from './VisuallyHidden';
@@ -0,0 +1,50 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Subprocess smoke tests for the zero-dependency docs script.
5
+ *
6
+ * `docs.mjs` resolves the package directory from `import.meta.url`. Using
7
+ * `new URL(...).pathname` there breaks on Windows (drive-letter paths come
8
+ * back as `/D:/...`), which made `--list` print nothing and component
9
+ * lookups crash with ENOENT. These tests spawn the script as a real
10
+ * subprocess from a neutral cwd, so resolution can only come from the
11
+ * module URL, and assert it finds the component catalog on every platform.
12
+ */
13
+
14
+ import {describe, it, expect} from 'vitest';
15
+ import {spawnSync} from 'node:child_process';
16
+ import * as os from 'node:os';
17
+ import * as path from 'node:path';
18
+ import {fileURLToPath} from 'node:url';
19
+
20
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
21
+ const DOCS_SCRIPT = path.resolve(__dirname, '..', 'docs.mjs');
22
+
23
+ function runDocs(args) {
24
+ return spawnSync(process.execPath, [DOCS_SCRIPT, ...args], {
25
+ cwd: os.tmpdir(),
26
+ encoding: 'utf8',
27
+ timeout: 20_000,
28
+ env: {...process.env, FORCE_COLOR: '0'},
29
+ });
30
+ }
31
+
32
+ describe('docs.mjs component discovery', () => {
33
+ it('--list discovers the component catalog', () => {
34
+ const r = runDocs(['--list']);
35
+ expect(r.error).toBeUndefined();
36
+ expect(r.signal).toBeNull();
37
+ expect(r.status).toBe(0);
38
+ expect(r.stdout).toMatch(/\bButton\b/);
39
+ expect(r.stdout).toMatch(/\bDialog\b/);
40
+ });
41
+
42
+ it('renders docs for a single component', () => {
43
+ const r = runDocs(['Button']);
44
+ expect(r.error).toBeUndefined();
45
+ expect(r.signal).toBeNull();
46
+ expect(r.status).toBe(0);
47
+ expect(r.stdout).toMatch(/^# Button$/m);
48
+ expect(r.stdout).toMatch(/## Props/);
49
+ });
50
+ });
@@ -0,0 +1,25 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file focusableSelector.ts
5
+ * @input None (a plain CSS selector string constant)
6
+ * @output Exports FOCUSABLE_SELECTOR
7
+ * @position Internal utility; the canonical CSS selector for focusable
8
+ * elements, shared by focus-management hooks (e.g. useFocusTrap) so the
9
+ * selector isn't duplicated across components/hooks. Not exported from the
10
+ * public barrel — internal implementation detail.
11
+ */
12
+
13
+ /**
14
+ * Canonical CSS selector for commonly focusable elements. Includes the
15
+ * tabbable natives (button/link/input/select/textarea/[tabindex]) plus
16
+ * editable and media elements the browser also puts in the tab order —
17
+ * contenteditable, media with controls, iframe, and an open <details>'s
18
+ * <summary> — which a naive selector misses, letting Tab escape a trap whose
19
+ * only interactive content is (e.g.) a contenteditable composer (infra-8).
20
+ *
21
+ * This is the canonical focusable selector; prefer importing it here over
22
+ * re-declaring the string so behavior stays consistent across hooks.
23
+ */
24
+ export const FOCUSABLE_SELECTOR =
25
+ 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"]):not([disabled]), [contenteditable]:not([contenteditable="false"]), audio[controls], video[controls], iframe, details > summary:first-child';
@@ -14,11 +14,31 @@
14
14
  export {useFocusTrap} from './useFocusTrap';
15
15
  export type {UseFocusTrapOptions, UseFocusTrapReturn} from './useFocusTrap';
16
16
 
17
+ export {useAnnounce} from './useAnnounce';
18
+ export type {AnnounceFn, AnnouncePoliteness} from './useAnnounce';
19
+
17
20
  export {useGridFocus} from './useGridFocus';
18
21
  export type {UseGridFocusOptions, UseGridFocusReturn} from './useGridFocus';
19
22
 
20
23
  export {useListFocus} from './useListFocus';
21
- export type {UseListFocusOptions, UseListFocusReturn} from './useListFocus';
24
+ export type {
25
+ UseListFocusOptions,
26
+ UseListFocusReturn,
27
+ ListFocusOrientation,
28
+ } from './useListFocus';
29
+
30
+ export {useTreeFocus} from './useTreeFocus';
31
+ export type {UseTreeFocusOptions, UseTreeFocusReturn} from './useTreeFocus';
32
+
33
+ export {useTypeahead} from './useTypeahead';
34
+
35
+ export {useKeyboardHint} from './useKeyboardHint';
36
+ export type {
37
+ UseKeyboardHintOptions,
38
+ UseKeyboardHintReturn,
39
+ KeyboardHintOrientation,
40
+ } from './useKeyboardHint';
41
+ export type {UseTypeaheadOptions, UseTypeaheadReturn} from './useTypeahead';
22
42
 
23
43
  export {useMediaQuery} from './useMediaQuery';
24
44
 
@@ -41,7 +61,10 @@ export type {
41
61
  export {useImageMode} from './useImageMode';
42
62
  export type {ImageSampleRegion, UseImageModeOptions} from './useImageMode';
43
63
 
44
- export {useClickableContainer} from './useClickableContainer';
64
+ export {
65
+ useClickableContainer,
66
+ INTERACTIVE_SELECTORS,
67
+ } from './useClickableContainer';
45
68
  export type {
46
69
  UseClickableContainerOptions,
47
70
  ClickableContainerResult,
@@ -55,3 +78,6 @@ export type {
55
78
  InteractiveRole,
56
79
  UseInteractiveRoleOptions,
57
80
  } from './useInteractiveRole';
81
+
82
+ export {useLongPress} from './useLongPress';
83
+ export type {UseLongPressOptions, UseLongPressHandlers} from './useLongPress';
@@ -0,0 +1,101 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file useAnnounce.test.tsx
5
+ * @input Uses vitest, @testing-library/react, useAnnounce hook
6
+ * @output Unit tests for useAnnounce live-region announcements
7
+ * @position Testing; validates useAnnounce.ts
8
+ *
9
+ * SYNC: When useAnnounce.ts changes, update tests to match new behavior
10
+ */
11
+
12
+ import {describe, it, expect, afterEach} from 'vitest';
13
+ import {renderHook, waitFor} from '@testing-library/react';
14
+ import {useAnnounce, __resetLiveRegionsForTest} from './useAnnounce';
15
+
16
+ afterEach(() => {
17
+ __resetLiveRegionsForTest();
18
+ });
19
+
20
+ function politeRegion(): HTMLElement | null {
21
+ return document.querySelector('[data-astryx-live-region="polite"]');
22
+ }
23
+ function assertiveRegion(): HTMLElement | null {
24
+ return document.querySelector('[data-astryx-live-region="assertive"]');
25
+ }
26
+
27
+ describe('useAnnounce', () => {
28
+ it('mounts empty polite and assertive live regions on first announce', async () => {
29
+ const {result} = renderHook(() => useAnnounce());
30
+ // Regions do not exist until first use.
31
+ expect(politeRegion()).toBeNull();
32
+
33
+ result.current('Saved');
34
+
35
+ // Both regions exist after the first announce, before content settles.
36
+ expect(politeRegion()).not.toBeNull();
37
+ expect(assertiveRegion()).not.toBeNull();
38
+ expect(politeRegion()).toHaveAttribute('aria-live', 'polite');
39
+ expect(politeRegion()).toHaveAttribute('aria-atomic', 'true');
40
+ expect(politeRegion()).toHaveAttribute('role', 'status');
41
+ expect(assertiveRegion()).toHaveAttribute('aria-live', 'assertive');
42
+ expect(assertiveRegion()).toHaveAttribute('role', 'alert');
43
+ });
44
+
45
+ it('announces a polite message into the polite region', async () => {
46
+ const {result} = renderHook(() => useAnnounce());
47
+ result.current('12 results');
48
+ await waitFor(() => {
49
+ expect(politeRegion()).toHaveTextContent('12 results');
50
+ });
51
+ // Assertive region stays empty.
52
+ expect(assertiveRegion()).toHaveTextContent('');
53
+ });
54
+
55
+ it('routes assertive messages to the assertive region', async () => {
56
+ const {result} = renderHook(() => useAnnounce());
57
+ result.current('Upload failed', 'assertive');
58
+ await waitFor(() => {
59
+ expect(assertiveRegion()).toHaveTextContent('Upload failed');
60
+ });
61
+ expect(politeRegion()).toHaveTextContent('');
62
+ });
63
+
64
+ it('re-announces an identical message (clears then re-sets)', async () => {
65
+ const {result} = renderHook(() => useAnnounce());
66
+ result.current('No results found');
67
+ await waitFor(() => {
68
+ expect(politeRegion()).toHaveTextContent('No results found');
69
+ });
70
+ // Second identical announce should still land (region is cleared first).
71
+ result.current('No results found');
72
+ expect(politeRegion()).toHaveTextContent('');
73
+ await waitFor(() => {
74
+ expect(politeRegion()).toHaveTextContent('No results found');
75
+ });
76
+ });
77
+
78
+ it('ignores empty messages', () => {
79
+ const {result} = renderHook(() => useAnnounce());
80
+ result.current('');
81
+ // No regions created for an empty announce.
82
+ expect(politeRegion()).toBeNull();
83
+ });
84
+
85
+ it('reuses the same singleton regions across hook instances', async () => {
86
+ const {result: a} = renderHook(() => useAnnounce());
87
+ a.current('first');
88
+ const region = politeRegion();
89
+
90
+ const {result: b} = renderHook(() => useAnnounce());
91
+ b.current('second');
92
+ await waitFor(() => {
93
+ expect(politeRegion()).toHaveTextContent('second');
94
+ });
95
+ // Same DOM node, not a duplicate.
96
+ expect(politeRegion()).toBe(region);
97
+ expect(
98
+ document.querySelectorAll('[data-astryx-live-region="polite"]').length,
99
+ ).toBe(1);
100
+ });
101
+ });
@@ -0,0 +1,168 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file useAnnounce.ts
7
+ * @input Uses React useCallback; DOM APIs for a singleton live-region pair
8
+ * @output Exports useAnnounce hook and AnnouncePoliteness type
9
+ * @position Core a11y hook; provides imperative screen-reader announcements
10
+ * via persistently-mounted polite/assertive live regions
11
+ *
12
+ * SYNC: When modified, update:
13
+ * - /packages/core/src/hooks/index.ts
14
+ */
15
+
16
+ import {useCallback} from 'react';
17
+
18
+ /**
19
+ * Announcement urgency:
20
+ * - `'polite'` (default): announced when the screen reader is idle. Use for
21
+ * status updates, result counts, "no results", non-urgent confirmations.
22
+ * - `'assertive'`: interrupts the current announcement. Reserve for errors and
23
+ * time-sensitive alerts.
24
+ */
25
+ export type AnnouncePoliteness = 'polite' | 'assertive';
26
+
27
+ /**
28
+ * Imperative screen-reader announcement function.
29
+ */
30
+ export type AnnounceFn = (
31
+ message: string,
32
+ politeness?: AnnouncePoliteness,
33
+ ) => void;
34
+
35
+ const CONTAINER_ATTR = 'data-astryx-live-region';
36
+
37
+ // Visually-hidden clip block (matches the VisuallyHidden primitive). Applied
38
+ // inline so the regions work without any stylesheet being present.
39
+ const VISUALLY_HIDDEN_CSS =
40
+ 'position:absolute;width:1px;height:1px;margin:-1px;padding:0;' +
41
+ 'overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;' +
42
+ 'inset-block-start:0;inset-inline-start:0;pointer-events:none;' +
43
+ 'user-select:none;';
44
+
45
+ interface LiveRegions {
46
+ polite: HTMLElement;
47
+ assertive: HTMLElement;
48
+ }
49
+
50
+ // Singleton: the live regions are created ONCE and stay mounted for the
51
+ // lifetime of the document. This is the crux of reliable announcements — many
52
+ // screen readers will not announce content injected into a live region that is
53
+ // created together with its content ("born with content"). By mounting empty
54
+ // regions up front and only mutating their text later, updates are announced.
55
+ let regions: LiveRegions | null = null;
56
+
57
+ function createRegion(politeness: AnnouncePoliteness): HTMLElement {
58
+ const el = document.createElement('div');
59
+ el.setAttribute(CONTAINER_ATTR, politeness);
60
+ el.setAttribute('aria-live', politeness);
61
+ el.setAttribute('aria-atomic', 'true');
62
+ el.setAttribute('role', politeness === 'assertive' ? 'alert' : 'status');
63
+ el.style.cssText = VISUALLY_HIDDEN_CSS;
64
+ document.body.appendChild(el);
65
+ return el;
66
+ }
67
+
68
+ function getRegions(): LiveRegions | null {
69
+ if (typeof document === 'undefined') {
70
+ return null;
71
+ }
72
+ if (regions) {
73
+ // Re-attach if a region was removed from the DOM (e.g. by a test cleanup).
74
+ if (!regions.polite.isConnected) {
75
+ document.body.appendChild(regions.polite);
76
+ }
77
+ if (!regions.assertive.isConnected) {
78
+ document.body.appendChild(regions.assertive);
79
+ }
80
+ return regions;
81
+ }
82
+ regions = {
83
+ polite: createRegion('polite'),
84
+ assertive: createRegion('assertive'),
85
+ };
86
+ return regions;
87
+ }
88
+
89
+ function announceMessage(
90
+ message: string,
91
+ politeness: AnnouncePoliteness,
92
+ ): void {
93
+ const r = getRegions();
94
+ if (!r) {
95
+ return;
96
+ }
97
+ const target = politeness === 'assertive' ? r.assertive : r.polite;
98
+ // Clearing first guarantees the mutation is observed even when the new
99
+ // message equals the current text — some AT deduplicate identical content.
100
+ target.textContent = '';
101
+ // A microtask/rAF-free re-set in the next frame is more reliable across AT
102
+ // than an immediate re-set, which can be coalesced with the clear.
103
+ requestAnimationFrame(() => {
104
+ target.textContent = message;
105
+ });
106
+ }
107
+
108
+ /**
109
+ * Clear any pending announcement from a region without announcing anything new.
110
+ * Used when the triggering context goes away (e.g. a search query is cleared),
111
+ * so stale status text does not linger in the accessibility tree.
112
+ */
113
+ function clearRegion(politeness: AnnouncePoliteness): void {
114
+ if (!regions) {
115
+ return;
116
+ }
117
+ const target =
118
+ politeness === 'assertive' ? regions.assertive : regions.polite;
119
+ target.textContent = '';
120
+ }
121
+
122
+ /**
123
+ * Returns an imperative `announce(message, politeness?)` function that speaks a
124
+ * message through a persistently-mounted, visually-hidden live region.
125
+ *
126
+ * The polite and assertive regions are created once on first use and kept
127
+ * mounted, so announcements are reliable even for messages that appear
128
+ * immediately (unlike a live region rendered together with its content).
129
+ *
130
+ * @example
131
+ * ```
132
+ * function Search() {
133
+ * const announce = useAnnounce();
134
+ * const onResults = (n: number) => {
135
+ * announce(n === 0 ? 'No results found' : `${n} results`);
136
+ * };
137
+ * // ...
138
+ * }
139
+ * ```
140
+ */
141
+ export function useAnnounce(): AnnounceFn {
142
+ return useCallback(
143
+ (message: string, politeness: AnnouncePoliteness = 'polite') => {
144
+ if (!message) {
145
+ // An empty message clears any lingering status from the region rather
146
+ // than announcing nothing — useful when the triggering context ends.
147
+ clearRegion(politeness);
148
+ return;
149
+ }
150
+ announceMessage(message, politeness);
151
+ },
152
+ [],
153
+ );
154
+ }
155
+
156
+ /**
157
+ * Test-only helper: removes the singleton live regions and resets state so
158
+ * each test starts clean. Not part of the public runtime API.
159
+ *
160
+ * @internal
161
+ */
162
+ export function __resetLiveRegionsForTest(): void {
163
+ if (regions) {
164
+ regions.polite.remove();
165
+ regions.assertive.remove();
166
+ regions = null;
167
+ }
168
+ }
@@ -5,18 +5,30 @@
5
5
  /**
6
6
  * @file useClickableContainer.ts
7
7
  * @input Container ref, interactive element ref, click/href handlers
8
- * @output onClick and onMouseUp handlers for the container
8
+ * @output onClick and onMouseUp handlers for the container; INTERACTIVE_SELECTORS list
9
9
  * @position Core hook for clickable containers that safely handle nested interactive elements
10
10
  *
11
11
  * Solves the "nested interactive elements" problem: when a card is clickable
12
12
  * but contains buttons/links, clicking those should NOT trigger the card's action.
13
+ *
14
+ * SYNC: When modified, update:
15
+ * - /packages/core/src/hooks/index.ts (export)
13
16
  */
14
17
 
15
18
  import {useCallback, useEffect, type RefObject, type MouseEvent} from 'react';
16
19
 
17
- // Interactive element selectors — clicks on these (or their descendants)
18
- // should NOT bubble to the container's click handler.
19
- const INTERACTIVE_SELECTORS = [
20
+ /**
21
+ * Canonical list of interactive element selectors — native controls plus
22
+ * role-based interactive elements. Clicks on these (or their descendants)
23
+ * should NOT bubble to a clickable container's click handler.
24
+ *
25
+ * Exported so other focus/interaction utilities can share one comprehensive
26
+ * definition of "interactive target" rather than hand-rolling divergent lists.
27
+ * Note: this list is about "don't bubble clicks", not focus-eligibility —
28
+ * consumers that need focusable elements must additionally exclude
29
+ * unfocusable/disabled targets (e.g. `[tabindex="-1"]`, `:disabled`).
30
+ */
31
+ export const INTERACTIVE_SELECTORS = [
20
32
  'button',
21
33
  'a',
22
34
  'input',
@@ -61,25 +61,37 @@ const scaleIn = stylex.keyframes({
61
61
 
62
62
  const styles = stylex.create({
63
63
  slideDown: {
64
- animationName: slideDown,
64
+ animationName: {
65
+ default: slideDown,
66
+ '@media (prefers-reduced-motion: reduce)': 'none',
67
+ },
65
68
  animationDuration: durationVars['--duration-fast-max'],
66
69
  animationTimingFunction: easeVars['--ease-standard'],
67
70
  animationFillMode: 'backwards',
68
71
  },
69
72
  slideUp: {
70
- animationName: slideUp,
73
+ animationName: {
74
+ default: slideUp,
75
+ '@media (prefers-reduced-motion: reduce)': 'none',
76
+ },
71
77
  animationDuration: durationVars['--duration-fast-max'],
72
78
  animationTimingFunction: easeVars['--ease-standard'],
73
79
  animationFillMode: 'backwards',
74
80
  },
75
81
  fadeIn: {
76
- animationName: fadeIn,
82
+ animationName: {
83
+ default: fadeIn,
84
+ '@media (prefers-reduced-motion: reduce)': 'none',
85
+ },
77
86
  animationDuration: durationVars['--duration-fast-max'],
78
87
  animationTimingFunction: easeVars['--ease-standard'],
79
88
  animationFillMode: 'backwards',
80
89
  },
81
90
  scaleIn: {
82
- animationName: scaleIn,
91
+ animationName: {
92
+ default: scaleIn,
93
+ '@media (prefers-reduced-motion: reduce)': 'none',
94
+ },
83
95
  animationDuration: durationVars['--duration-fast-max'],
84
96
  animationTimingFunction: easeVars['--ease-standard'],
85
97
  animationFillMode: 'backwards',