@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
@@ -2,7 +2,7 @@
2
2
 
3
3
  /**
4
4
  * @file InputGroup.test.tsx
5
- * @input Uses vitest, @testing-library/react, InputGroup and TextInput components
5
+ * @input Uses vitest, @testing-library/react, InputGroup, TextInput, NumberInput, DateInput components
6
6
  * @output Unit tests for InputGroup
7
7
  * @position Testing; validates InputGroup component implementation
8
8
  *
@@ -14,38 +14,275 @@ import {render, screen} from '@testing-library/react';
14
14
  import {InputGroup} from './InputGroup';
15
15
  import {InputGroupText} from './InputGroupText';
16
16
  import {TextInput} from '../TextInput';
17
+ import {NumberInput} from '../NumberInput';
18
+ import {DateInput} from '../DateInput';
19
+ import {Typeahead} from '../Typeahead';
20
+ import type {SearchableItem, SearchSource} from '../Typeahead';
21
+ import {Selector} from '../Selector';
22
+ import {MultiSelector} from '../MultiSelector';
23
+
24
+ const fruits: SearchableItem[] = [
25
+ {id: '1', label: 'Apple'},
26
+ {id: '2', label: 'Banana'},
27
+ ];
28
+
29
+ const fruitSource: SearchSource = {
30
+ search: (query: string) =>
31
+ fruits.filter(f => f.label.toLowerCase().includes(query.toLowerCase())),
32
+ bootstrap: () => fruits,
33
+ };
17
34
 
18
35
  describe('InputGroup', () => {
19
- it('renders a group with aria-label', () => {
36
+ it('names the group via the label element (forms-14)', () => {
20
37
  render(
21
38
  <InputGroup label="Price">
22
39
  <InputGroupText>$</InputGroupText>
23
- <TextInput
24
- label="Amount"
40
+ <TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
41
+ </InputGroup>,
42
+ );
43
+
44
+ // The group is named by the field label via aria-labelledby (not a
45
+ // duplicated aria-label). The label is rendered as a <span> (not a literal
46
+ // <label>, which can't name a group) and carries no orphaned htmlFor.
47
+ const group = screen.getByRole('group', {name: 'Price'});
48
+ expect(group).toBeInTheDocument();
49
+ expect(group).not.toHaveAttribute('aria-label');
50
+ const label = screen.getByText('Price');
51
+ expect(label.tagName).toBe('SPAN');
52
+ expect(label.closest('label')).toBeNull();
53
+ expect(label).not.toHaveAttribute('for');
54
+ expect(group.getAttribute('aria-labelledby')).toBe(label.id);
55
+ });
56
+
57
+ it('associates group description and status through aria-describedby', () => {
58
+ render(
59
+ <InputGroup
60
+ label="Price"
61
+ description="Enter the amount in USD"
62
+ status={{type: 'error', message: 'Price is required'}}>
63
+ <InputGroupText>$</InputGroupText>
64
+ <TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
65
+ </InputGroup>,
66
+ );
67
+
68
+ const group = screen.getByRole('group', {name: 'Price'});
69
+ const describedBy = group.getAttribute('aria-describedby');
70
+ expect(describedBy).toBeTruthy();
71
+ expect(describedBy!.split(' ')).toHaveLength(2);
72
+ expect(describedBy).toContain(
73
+ screen.getByText('Enter the amount in USD').id,
74
+ );
75
+ expect(describedBy).toContain(screen.getByText('Price is required').id);
76
+ });
77
+
78
+ it('labels grouped TextInput from the group and inner input labels', () => {
79
+ render(
80
+ <InputGroup
81
+ label="Price"
82
+ description="Enter the amount in USD"
83
+ status={{type: 'error', message: 'Price is required'}}>
84
+ <InputGroupText>$</InputGroupText>
85
+ <TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
86
+ </InputGroup>,
87
+ );
88
+
89
+ const group = screen.getByRole('group', {name: 'Price'});
90
+ const groupLabelID = group.getAttribute('aria-labelledby');
91
+ const describedBy = group.getAttribute('aria-describedby');
92
+ const input = screen.getByRole('textbox', {name: 'Price Amount'});
93
+ const labelledByIDs =
94
+ input.getAttribute('aria-labelledby')?.split(' ') ?? [];
95
+
96
+ expect(labelledByIDs).toHaveLength(2);
97
+ expect(labelledByIDs[0]).toBe(groupLabelID);
98
+ expect(document.getElementById(labelledByIDs[1])).toHaveTextContent(
99
+ 'Amount',
100
+ );
101
+ expect(input).not.toHaveAttribute('aria-label');
102
+ expect(input).toHaveAttribute('aria-describedby', describedBy);
103
+ });
104
+
105
+ it('labels grouped Typeahead from the group and inner input labels', () => {
106
+ const {container} = render(
107
+ <InputGroup label="Favorite fruit" description="Pick one fruit">
108
+ <InputGroupText>Fruit</InputGroupText>
109
+ <Typeahead
110
+ label="Selection"
25
111
  isLabelHidden
26
- value=""
112
+ searchSource={fruitSource}
113
+ value={null}
27
114
  onChange={() => {}}
28
115
  />
29
116
  </InputGroup>,
30
117
  );
31
118
 
32
- const group = screen.getByRole('group');
33
- expect(group).toBeInTheDocument();
34
- expect(group).toHaveAttribute('aria-label', 'Price');
119
+ const group = screen.getByRole('group', {name: 'Favorite fruit'});
120
+ const groupLabelID = group.getAttribute('aria-labelledby');
121
+ const input = screen.getByRole('combobox', {
122
+ name: 'Favorite fruit Selection',
123
+ });
124
+ const labelledByIDs =
125
+ input.getAttribute('aria-labelledby')?.split(' ') ?? [];
126
+
127
+ expect(labelledByIDs).toHaveLength(2);
128
+ expect(labelledByIDs[0]).toBe(groupLabelID);
129
+ expect(document.getElementById(labelledByIDs[1])).toHaveTextContent(
130
+ 'Selection',
131
+ );
132
+ expect(input).not.toHaveAttribute('aria-label');
133
+ expect(input).toHaveAttribute(
134
+ 'aria-describedby',
135
+ group.getAttribute('aria-describedby'),
136
+ );
137
+ expect(container.querySelectorAll('.astryx-field')).toHaveLength(1);
35
138
  });
36
139
 
37
- it('renders the visible label', () => {
140
+ it('labels grouped NumberInput from the group and inner input labels', () => {
38
141
  render(
39
- <InputGroup label="Price">
40
- <TextInput
142
+ <InputGroup label="Budget" description="Whole dollars only">
143
+ <InputGroupText>$</InputGroupText>
144
+ <NumberInput
41
145
  label="Amount"
42
146
  isLabelHidden
43
- value=""
147
+ value={null}
44
148
  onChange={() => {}}
45
149
  />
46
150
  </InputGroup>,
47
151
  );
48
152
 
153
+ const group = screen.getByRole('group', {name: 'Budget'});
154
+ const groupLabelID = group.getAttribute('aria-labelledby');
155
+ const input = screen.getByRole('spinbutton', {name: 'Budget Amount'});
156
+ const labelledByIDs =
157
+ input.getAttribute('aria-labelledby')?.split(' ') ?? [];
158
+
159
+ expect(labelledByIDs).toHaveLength(2);
160
+ expect(labelledByIDs[0]).toBe(groupLabelID);
161
+ expect(document.getElementById(labelledByIDs[1])).toHaveTextContent(
162
+ 'Amount',
163
+ );
164
+ expect(input).not.toHaveAttribute('aria-label');
165
+ expect(input).toHaveAttribute(
166
+ 'aria-describedby',
167
+ group.getAttribute('aria-describedby'),
168
+ );
169
+ });
170
+
171
+ it('labels grouped DateInput from the group and inner input labels', () => {
172
+ render(
173
+ <InputGroup label="Deadline" description="Use business days">
174
+ <InputGroupText>Due</InputGroupText>
175
+ <DateInput label="Date" isLabelHidden onChange={() => {}} />
176
+ </InputGroup>,
177
+ );
178
+
179
+ const group = screen.getByRole('group', {name: 'Deadline'});
180
+ const groupLabelID = group.getAttribute('aria-labelledby');
181
+ const input = screen.getByRole('combobox', {name: 'Deadline Date'});
182
+ const labelledByIDs =
183
+ input.getAttribute('aria-labelledby')?.split(' ') ?? [];
184
+
185
+ expect(labelledByIDs).toHaveLength(2);
186
+ expect(labelledByIDs[0]).toBe(groupLabelID);
187
+ expect(document.getElementById(labelledByIDs[1])).toHaveTextContent('Date');
188
+ expect(input).toHaveAttribute('aria-haspopup', 'dialog');
189
+ expect(input).toHaveAttribute(
190
+ 'aria-describedby',
191
+ group.getAttribute('aria-describedby'),
192
+ );
193
+ });
194
+
195
+ it('labels grouped Selector from the group and selector labels', () => {
196
+ render(
197
+ <InputGroup label="Destination" description="Where alerts are sent">
198
+ <InputGroupText>#</InputGroupText>
199
+ <Selector
200
+ label="Channel"
201
+ isLabelHidden
202
+ options={['General', 'Support']}
203
+ placeholder="Choose channel"
204
+ />
205
+ </InputGroup>,
206
+ );
207
+
208
+ const group = screen.getByRole('group', {name: 'Destination'});
209
+ const groupLabelID = group.getAttribute('aria-labelledby');
210
+ const trigger = screen.getByRole('combobox', {
211
+ name: 'Destination Channel',
212
+ });
213
+ const labelledByIDs =
214
+ trigger.getAttribute('aria-labelledby')?.split(' ') ?? [];
215
+
216
+ expect(labelledByIDs).toHaveLength(2);
217
+ expect(labelledByIDs[0]).toBe(groupLabelID);
218
+ expect(document.getElementById(labelledByIDs[1])).toHaveTextContent(
219
+ 'Channel',
220
+ );
221
+ expect(trigger).not.toHaveAttribute('aria-label');
222
+ expect(trigger).toHaveAttribute(
223
+ 'aria-describedby',
224
+ group.getAttribute('aria-describedby'),
225
+ );
226
+ });
227
+
228
+ it('labels grouped MultiSelector from the group and selector labels', () => {
229
+ render(
230
+ <InputGroup label="Destinations" description="Where alerts are sent">
231
+ <InputGroupText>#</InputGroupText>
232
+ <MultiSelector
233
+ label="Channels"
234
+ isLabelHidden
235
+ options={['General', 'Support']}
236
+ value={[]}
237
+ onChange={() => {}}
238
+ placeholder="Choose channels"
239
+ />
240
+ </InputGroup>,
241
+ );
242
+
243
+ const group = screen.getByRole('group', {name: 'Destinations'});
244
+ const groupLabelID = group.getAttribute('aria-labelledby');
245
+ const trigger = screen.getByRole('combobox', {
246
+ name: 'Destinations Channels',
247
+ });
248
+ const labelledByIDs =
249
+ trigger.getAttribute('aria-labelledby')?.split(' ') ?? [];
250
+
251
+ expect(labelledByIDs).toHaveLength(2);
252
+ expect(labelledByIDs[0]).toBe(groupLabelID);
253
+ expect(document.getElementById(labelledByIDs[1])).toHaveTextContent(
254
+ 'Channels',
255
+ );
256
+ expect(trigger).not.toHaveAttribute('aria-label');
257
+ expect(trigger).toHaveAttribute(
258
+ 'aria-describedby',
259
+ group.getAttribute('aria-describedby'),
260
+ );
261
+ });
262
+
263
+ it('keeps grouped DateInput calendar button and popover semantics', () => {
264
+ render(
265
+ <InputGroup label="Deadline">
266
+ <InputGroupText>Due</InputGroupText>
267
+ <DateInput label="Date" isLabelHidden onChange={() => {}} />
268
+ </InputGroup>,
269
+ );
270
+
271
+ expect(
272
+ screen.getByRole('button', {name: 'Open calendar'}),
273
+ ).toBeInTheDocument();
274
+ expect(
275
+ screen.getByRole('combobox', {name: 'Deadline Date'}),
276
+ ).toHaveAttribute('aria-expanded', 'false');
277
+ });
278
+
279
+ it('renders the visible label', () => {
280
+ render(
281
+ <InputGroup label="Price">
282
+ <TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
283
+ </InputGroup>,
284
+ );
285
+
49
286
  expect(screen.getByText('Price')).toBeInTheDocument();
50
287
  });
51
288
 
@@ -53,12 +290,7 @@ describe('InputGroup', () => {
53
290
  render(
54
291
  <InputGroup label="Price">
55
292
  <InputGroupText>$</InputGroupText>
56
- <TextInput
57
- label="Amount"
58
- isLabelHidden
59
- value=""
60
- onChange={() => {}}
61
- />
293
+ <TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
62
294
  </InputGroup>,
63
295
  );
64
296
 
@@ -68,12 +300,7 @@ describe('InputGroup', () => {
68
300
  it('renders the input', () => {
69
301
  render(
70
302
  <InputGroup label="Price">
71
- <TextInput
72
- label="Amount"
73
- isLabelHidden
74
- value=""
75
- onChange={() => {}}
76
- />
303
+ <TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
77
304
  </InputGroup>,
78
305
  );
79
306
 
@@ -97,12 +324,7 @@ describe('InputGroup', () => {
97
324
  it('applies data-testid', () => {
98
325
  render(
99
326
  <InputGroup label="Price" data-testid="price-group">
100
- <TextInput
101
- label="Amount"
102
- isLabelHidden
103
- value=""
104
- onChange={() => {}}
105
- />
327
+ <TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
106
328
  </InputGroup>,
107
329
  );
108
330
 
@@ -112,12 +334,7 @@ describe('InputGroup', () => {
112
334
  it('renders description text', () => {
113
335
  render(
114
336
  <InputGroup label="Price" description="Enter the price in USD">
115
- <TextInput
116
- label="Amount"
117
- isLabelHidden
118
- value=""
119
- onChange={() => {}}
120
- />
337
+ <TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
121
338
  </InputGroup>,
122
339
  );
123
340
 
@@ -129,12 +346,7 @@ describe('InputGroup', () => {
129
346
  <InputGroup
130
347
  label="Price"
131
348
  status={{type: 'error', message: 'Price is required'}}>
132
- <TextInput
133
- label="Amount"
134
- isLabelHidden
135
- value=""
136
- onChange={() => {}}
137
- />
349
+ <TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
138
350
  </InputGroup>,
139
351
  );
140
352
 
@@ -144,12 +356,7 @@ describe('InputGroup', () => {
144
356
  it('renders with hidden label', () => {
145
357
  render(
146
358
  <InputGroup label="Price" isLabelHidden>
147
- <TextInput
148
- label="Amount"
149
- isLabelHidden
150
- value=""
151
- onChange={() => {}}
152
- />
359
+ <TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
153
360
  </InputGroup>,
154
361
  );
155
362
 
@@ -160,24 +367,14 @@ describe('InputGroup', () => {
160
367
  it('renders with different sizes', () => {
161
368
  const {rerender} = render(
162
369
  <InputGroup label="Price" size="sm">
163
- <TextInput
164
- label="Amount"
165
- isLabelHidden
166
- value=""
167
- onChange={() => {}}
168
- />
370
+ <TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
169
371
  </InputGroup>,
170
372
  );
171
373
  expect(screen.getByRole('textbox')).toBeInTheDocument();
172
374
 
173
375
  rerender(
174
376
  <InputGroup label="Price" size="lg">
175
- <TextInput
176
- label="Amount"
177
- isLabelHidden
178
- value=""
179
- onChange={() => {}}
180
- />
377
+ <TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
181
378
  </InputGroup>,
182
379
  );
183
380
  expect(screen.getByRole('textbox')).toBeInTheDocument();
@@ -4,11 +4,12 @@
4
4
 
5
5
  /**
6
6
  * @file InputGroup.tsx
7
- * @input Uses React, StyleX, theme tokens, InputGroupContext
8
- * @output Exports InputGroup component
7
+ * @input Uses React, StyleX, theme tokens, InputGroupContext, Field
8
+ * @output Exports InputGroup component with group label/description ARIA wiring
9
9
  * @position Groups input with prefix/suffix addons; consumed by index.ts
10
10
  *
11
- * Children (TextInput, NumberInput) consume the InputGroup context
11
+ * Children (TextInput, NumberInput, TimeInput, DateInput, Typeahead,
12
+ * Selector, MultiSelector) consume the InputGroup context
12
13
  * to remove their own border/radius so the group container provides
13
14
  * the unified border treatment.
14
15
  *
@@ -156,9 +157,22 @@ export function InputGroup({
156
157
  }: InputGroupProps) {
157
158
  const size = useSize(sizeProp, 'md');
158
159
  const inputId = useId();
160
+ const labelID = useId();
161
+ const descriptionID = useId();
159
162
  const statusMessageId = useId();
160
163
 
161
- const contextValue = useMemo(() => ({isInGroup: true as const}), []);
164
+ const describedByIDs =
165
+ [
166
+ description ? descriptionID : null,
167
+ status?.message ? statusMessageId : null,
168
+ ]
169
+ .filter(Boolean)
170
+ .join(' ') || undefined;
171
+
172
+ const contextValue = useMemo(
173
+ () => ({isInGroup: true as const, labelID, describedByIDs}),
174
+ [labelID, describedByIDs],
175
+ );
162
176
 
163
177
  return (
164
178
  <InputGroupContext value={contextValue}>
@@ -168,6 +182,9 @@ export function InputGroup({
168
182
  isLabelHidden={isLabelHidden}
169
183
  description={description}
170
184
  inputID={inputId}
185
+ labelID={labelID}
186
+ descriptionID={description ? descriptionID : undefined}
187
+ isGroupLabel
171
188
  isOptional={isOptional}
172
189
  isRequired={isRequired}
173
190
  isDisabled={isDisabled}
@@ -185,7 +202,8 @@ export function InputGroup({
185
202
  <div
186
203
  ref={ref}
187
204
  role="group"
188
- aria-label={label}
205
+ aria-labelledby={labelID}
206
+ aria-describedby={describedByIDs}
189
207
  data-testid={testId}
190
208
  {...rest}
191
209
  {...mergeProps(
@@ -4,19 +4,24 @@
4
4
 
5
5
  /**
6
6
  * @file InputGroupContext.ts
7
- * @input None (pure context definition)
7
+ * @input React createContext/use
8
8
  * @output Exports InputGroup context and useInputGroup hook
9
- * @position Shared context; consumed by input components for group-aware styling
9
+ * @position Shared context; consumed by input components for group-aware styling and ARIA associations
10
10
  */
11
11
 
12
12
  import {createContext, use} from 'react';
13
13
 
14
14
  export interface InputGroupContextValue {
15
15
  isInGroup: true;
16
+ /** ID of the group label element, for aria-labelledby composition. */
17
+ labelID: string;
18
+ /** IDs of helper/status text owned by the group, for aria-describedby composition. */
19
+ describedByIDs?: string;
16
20
  }
17
21
 
18
- export const InputGroupContext =
19
- createContext<InputGroupContextValue | null>(null);
22
+ export const InputGroupContext = createContext<InputGroupContextValue | null>(
23
+ null,
24
+ );
20
25
  InputGroupContext.displayName = 'InputGroupContext';
21
26
 
22
27
  /**
@@ -4,7 +4,7 @@
4
4
  * @file groupStyles.ts
5
5
  * @input Uses StyleX, theme tokens
6
6
  * @output Exports shared group-aware styles for input components
7
- * @position Shared styles consumed by TextInput, NumberInput when inside an InputGroup
7
+ * @position Shared styles consumed by InputGroup-compatible controls
8
8
  */
9
9
 
10
10
  import * as stylex from '@stylexjs/stylex';
@@ -30,10 +30,16 @@ export const groupStyles = stylex.create({
30
30
  borderStartEndRadius: {
31
31
  default: 0,
32
32
  ':last-child': radiusVars['--radius-element'],
33
+ ':has(+ [popover]:last-child)': radiusVars['--radius-element'],
34
+ ':has(+ [popover] + [popover]:last-child)':
35
+ radiusVars['--radius-element'],
33
36
  },
34
37
  borderEndEndRadius: {
35
38
  default: 0,
36
39
  ':last-child': radiusVars['--radius-element'],
40
+ ':has(+ [popover]:last-child)': radiusVars['--radius-element'],
41
+ ':has(+ [popover] + [popover]:last-child)':
42
+ radiusVars['--radius-element'],
37
43
  },
38
44
  ':focus-within': {
39
45
  zIndex: 1,
@@ -16,3 +16,4 @@ export {InputGroupText} from './InputGroupText';
16
16
  export type {InputGroupTextProps} from './InputGroupText';
17
17
 
18
18
  export {useInputGroup} from './InputGroupContext';
19
+ export type {InputGroupContextValue} from './InputGroupContext';
@@ -72,10 +72,28 @@ describe('Kbd', () => {
72
72
  expect(screen.getByText('Esc')).toBeInTheDocument();
73
73
  });
74
74
 
75
- it('is aria-hidden', () => {
76
- const {container} = render(<Kbd keys="mod+k" />);
77
- const wrapper = container.firstChild as HTMLElement;
78
- expect(wrapper.getAttribute('aria-hidden')).toBe('true');
75
+ it('exposes a spoken accessible name and hides the glyphs (obs-1)', () => {
76
+ render(<Kbd keys="mod+shift+k" />);
77
+ // The wrapper carries a screen-reader name built from spoken key labels
78
+ // (jsdom is non-Mac, so mod → "Control").
79
+ const img = screen.getByRole('img');
80
+ expect(img).toHaveAttribute('aria-label', 'Control + Shift + K');
81
+ // The visual glyph elements are hidden from assistive tech.
82
+ const glyphs = img.querySelectorAll('kbd');
83
+ glyphs.forEach(g => expect(g).toHaveAttribute('aria-hidden', 'true'));
84
+ expect(img).not.toHaveAttribute('aria-hidden');
85
+ });
86
+
87
+ it('uses "Command" in the accessible name for mod on Mac', () => {
88
+ Object.defineProperty(navigator, 'platform', {
89
+ value: 'MacIntel',
90
+ configurable: true,
91
+ });
92
+ render(<Kbd keys="mod+k" />);
93
+ expect(screen.getByRole('img')).toHaveAttribute(
94
+ 'aria-label',
95
+ 'Command + K',
96
+ );
79
97
  });
80
98
 
81
99
  it('uppercases unknown keys', () => {
package/src/Kbd/Kbd.tsx CHANGED
@@ -87,6 +87,33 @@ function getKeyDisplay(key: string, isMac: boolean): string {
87
87
  return KEY_DISPLAY[key] ?? key.toUpperCase();
88
88
  }
89
89
 
90
+ /**
91
+ * Spoken-word labels for screen readers. The visual `KEY_DISPLAY` uses glyphs
92
+ * (⌘, ⇧, ↵, …) that assistive tech cannot announce meaningfully, so the
93
+ * accessible name for the shortcut is built from these words instead.
94
+ */
95
+ const KEY_LABEL: Record<string, string> = {
96
+ ctrl: 'Control',
97
+ alt: 'Alt',
98
+ shift: 'Shift',
99
+ enter: 'Enter',
100
+ backspace: 'Backspace',
101
+ escape: 'Escape',
102
+ tab: 'Tab',
103
+ up: 'Up arrow',
104
+ down: 'Down arrow',
105
+ left: 'Left arrow',
106
+ right: 'Right arrow',
107
+ plus: 'Plus',
108
+ };
109
+
110
+ function getKeyLabel(key: string, isMac: boolean): string {
111
+ if (key === 'mod') {
112
+ return isMac ? 'Command' : 'Control';
113
+ }
114
+ return KEY_LABEL[key] ?? key.toUpperCase();
115
+ }
116
+
90
117
  function subscribeToPlatformChanges(): () => void {
91
118
  return () => {};
92
119
  }
@@ -155,19 +182,24 @@ export function Kbd({keys, ref, xstyle, className, style, ...rest}: KbdProps) {
155
182
 
156
183
  const parts = keys.split('+').map(key => key.trim().toLowerCase());
157
184
 
185
+ // Screen-reader name: the joined spoken labels (e.g. "Command + K"), since
186
+ // the visual glyphs below are announced meaninglessly by assistive tech.
187
+ const accessibleName = parts.map(key => getKeyLabel(key, isMac)).join(' + ');
188
+
158
189
  return (
159
190
  <span
160
191
  ref={ref}
192
+ role="img"
193
+ aria-label={accessibleName}
161
194
  {...rest}
162
195
  {...mergeProps(
163
196
  themeProps('kbd'),
164
197
  stylex.props(styles.wrapper, xstyle),
165
198
  className,
166
199
  style,
167
- )}
168
- aria-hidden="true">
200
+ )}>
169
201
  {parts.map(key => (
170
- <kbd key={key} {...stylex.props(styles.kbd)}>
202
+ <kbd key={key} aria-hidden="true" {...stylex.props(styles.kbd)}>
171
203
  {getKeyDisplay(key, isMac)}
172
204
  </kbd>
173
205
  ))}
@@ -72,22 +72,38 @@ const animationBase = {
72
72
  *
73
73
  * Keyed by LayerPlacement ('above' | 'below' | 'start' | 'end')
74
74
  * for easy lookup: `layerAnimations[placement]`.
75
+ *
76
+ * Each entry disables its keyframe animation under
77
+ * `prefers-reduced-motion: reduce` so the layer appears instantly instead of
78
+ * translating/scaling in (infra-6).
75
79
  */
76
80
  export const layerAnimations = stylex.create({
77
81
  below: {
78
- animationName: enterBelow,
82
+ animationName: {
83
+ default: enterBelow,
84
+ '@media (prefers-reduced-motion: reduce)': 'none',
85
+ },
79
86
  ...animationBase,
80
87
  },
81
88
  above: {
82
- animationName: enterAbove,
89
+ animationName: {
90
+ default: enterAbove,
91
+ '@media (prefers-reduced-motion: reduce)': 'none',
92
+ },
83
93
  ...animationBase,
84
94
  },
85
95
  end: {
86
- animationName: enterEnd,
96
+ animationName: {
97
+ default: enterEnd,
98
+ '@media (prefers-reduced-motion: reduce)': 'none',
99
+ },
87
100
  ...animationBase,
88
101
  },
89
102
  start: {
90
- animationName: enterStart,
103
+ animationName: {
104
+ default: enterStart,
105
+ '@media (prefers-reduced-motion: reduce)': 'none',
106
+ },
91
107
  ...animationBase,
92
108
  },
93
109
  });
@@ -144,6 +144,11 @@ export const docsDense = {
144
144
  guidance: true,
145
145
  description: 'Build on Popover/HoverCard/Tooltip for common overlay patterns.',
146
146
  },
147
+ {
148
+ guidance: true,
149
+ description:
150
+ 'Rely on the Popover API top layer to escape clipping/stacking: render inline (no portal) to inherit the trigger theme cascade and natural focus order. Use `as: "span"` when the layer must be valid in inline contexts like a paragraph.',
151
+ },
147
152
  {
148
153
  guidance: false,
149
154
  description: