@astryxdesign/core 0.1.2 → 0.1.3

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
@@ -9,12 +9,43 @@
9
9
  * SYNC: When TextInput.tsx changes, update tests to match new behavior
10
10
  */
11
11
 
12
- import {describe, it, expect, vi} from 'vitest';
13
- import {render, screen, fireEvent} from '@testing-library/react';
12
+ import {describe, it, expect, vi, beforeEach} from 'vitest';
13
+ import {render, screen, fireEvent, waitFor} from '@testing-library/react';
14
14
  import userEvent from '@testing-library/user-event';
15
15
  import {MagnifyingGlassIcon} from '@heroicons/react/24/outline';
16
16
  import {TextInput} from './TextInput';
17
17
 
18
+ // Mock showPopover/hidePopover since jsdom does not implement them. Used by the
19
+ // disabledMessage tooltip.
20
+ beforeEach(() => {
21
+ HTMLElement.prototype.showPopover = vi.fn(function (this: HTMLElement) {
22
+ this.setAttribute('popover-open', '');
23
+ const event = new Event('toggle', {bubbles: false});
24
+ Object.defineProperty(event, 'newState', {value: 'open'});
25
+ this.dispatchEvent(event);
26
+ });
27
+ HTMLElement.prototype.hidePopover = vi.fn(function (this: HTMLElement) {
28
+ this.removeAttribute('popover-open');
29
+ const event = new Event('toggle', {bubbles: false});
30
+ Object.defineProperty(event, 'newState', {value: 'closed'});
31
+ this.dispatchEvent(event);
32
+ });
33
+ const originalMatches = HTMLElement.prototype.matches;
34
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
35
+ (HTMLElement.prototype as any).matches = function (
36
+ selector: string,
37
+ ): boolean {
38
+ if (selector === ':popover-open') {
39
+ return this.hasAttribute('popover-open');
40
+ }
41
+ return originalMatches.call(this, selector);
42
+ };
43
+ });
44
+
45
+ // jsdom popover content is in the DOM but may not be "visible" in the
46
+ // accessibility tree. Use hidden: true to find it.
47
+ const h = {hidden: true} as const;
48
+
18
49
  describe('TextInput', () => {
19
50
  it('renders with label', () => {
20
51
  render(<TextInput label="Name" value="" onChange={() => {}} />);
@@ -62,31 +93,20 @@ describe('TextInput', () => {
62
93
 
63
94
  it('displays controlled value', () => {
64
95
  render(
65
- <TextInput
66
- label="Name"
67
- value="Controlled value"
68
- onChange={() => {}}
69
- />,
96
+ <TextInput label="Name" value="Controlled value" onChange={() => {}} />,
70
97
  );
71
98
  expect(screen.getByRole('textbox')).toHaveValue('Controlled value');
72
99
  });
73
100
 
74
101
  it('forwards ref correctly', () => {
75
102
  const ref = vi.fn();
76
- render(
77
- <TextInput ref={ref} label="Name" value="" onChange={() => {}} />,
78
- );
103
+ render(<TextInput ref={ref} label="Name" value="" onChange={() => {}} />);
79
104
  expect(ref).toHaveBeenCalledWith(expect.any(HTMLInputElement));
80
105
  });
81
106
 
82
107
  it('visually hides label when isLabelHidden is true', () => {
83
108
  render(
84
- <TextInput
85
- label="Search"
86
- isLabelHidden
87
- value=""
88
- onChange={() => {}}
89
- />,
109
+ <TextInput label="Search" isLabelHidden value="" onChange={() => {}} />,
90
110
  );
91
111
  const label = screen.getByText('Search');
92
112
  expect(label).toBeInTheDocument();
@@ -116,9 +136,7 @@ describe('TextInput', () => {
116
136
  });
117
137
 
118
138
  it('sets disabled attribute when isDisabled is true', () => {
119
- render(
120
- <TextInput label="Name" isDisabled value="" onChange={() => {}} />,
121
- );
139
+ render(<TextInput label="Name" isDisabled value="" onChange={() => {}} />);
122
140
  expect(screen.getByRole('textbox')).toBeDisabled();
123
141
  });
124
142
 
@@ -410,12 +428,7 @@ describe('TextInput', () => {
410
428
  describe('hasClear', () => {
411
429
  it('shows clear button when hasClear is true and value is non-empty', () => {
412
430
  render(
413
- <TextInput
414
- label="Name"
415
- value="hello"
416
- onChange={() => {}}
417
- hasClear
418
- />,
431
+ <TextInput label="Name" value="hello" onChange={() => {}} hasClear />,
419
432
  );
420
433
  expect(
421
434
  screen.getByRole('button', {name: 'Clear Name'}),
@@ -423,9 +436,7 @@ describe('TextInput', () => {
423
436
  });
424
437
 
425
438
  it('does not show clear button when value is empty', () => {
426
- render(
427
- <TextInput label="Name" value="" onChange={() => {}} hasClear />,
428
- );
439
+ render(<TextInput label="Name" value="" onChange={() => {}} hasClear />);
429
440
  expect(
430
441
  screen.queryByRole('button', {name: 'Clear Name'}),
431
442
  ).not.toBeInTheDocument();
@@ -457,12 +468,7 @@ describe('TextInput', () => {
457
468
  const user = userEvent.setup();
458
469
  const onChange = vi.fn();
459
470
  render(
460
- <TextInput
461
- label="Name"
462
- value="hello"
463
- onChange={onChange}
464
- hasClear
465
- />,
471
+ <TextInput label="Name" value="hello" onChange={onChange} hasClear />,
466
472
  );
467
473
  await user.click(screen.getByRole('button', {name: 'Clear Name'}));
468
474
  expect(onChange).toHaveBeenCalledWith('', null);
@@ -524,4 +530,132 @@ describe('TextInput', () => {
524
530
  expect(fieldRoot.getAttribute('style') ?? '').not.toContain('100%');
525
531
  });
526
532
  });
533
+
534
+ describe('disabledMessage', () => {
535
+ it('shows the reason tooltip on hover when disabled with a reason', async () => {
536
+ render(
537
+ <TextInput
538
+ label="Owner"
539
+ value=""
540
+ onChange={() => {}}
541
+ isDisabled
542
+ disabledMessage="You need the Editor role"
543
+ />,
544
+ );
545
+
546
+ const input = screen.getByRole('textbox');
547
+ const container = input.parentElement as HTMLElement;
548
+ const tooltip = screen.getByRole('tooltip', h);
549
+ expect(tooltip).toHaveTextContent('You need the Editor role');
550
+
551
+ fireEvent.mouseEnter(container);
552
+ await waitFor(() => {
553
+ expect(tooltip).toHaveAttribute('popover-open');
554
+ });
555
+
556
+ fireEvent.mouseLeave(container);
557
+ await waitFor(() => {
558
+ expect(tooltip).not.toHaveAttribute('popover-open');
559
+ });
560
+ });
561
+
562
+ it('shows the reason tooltip on keyboard focus', async () => {
563
+ const user = userEvent.setup();
564
+ render(
565
+ <TextInput
566
+ label="Owner"
567
+ value=""
568
+ onChange={() => {}}
569
+ isDisabled
570
+ disabledMessage="You need the Editor role"
571
+ />,
572
+ );
573
+
574
+ const tooltip = screen.getByRole('tooltip', h);
575
+ await user.tab();
576
+ expect(screen.getByRole('textbox')).toHaveFocus();
577
+ await waitFor(() => {
578
+ expect(tooltip).toHaveAttribute('popover-open');
579
+ });
580
+ });
581
+
582
+ it('does not render a tooltip when not disabled', () => {
583
+ render(
584
+ <TextInput
585
+ label="Owner"
586
+ value=""
587
+ onChange={() => {}}
588
+ disabledMessage="You need the Editor role"
589
+ />,
590
+ );
591
+ expect(screen.queryByRole('tooltip', h)).not.toBeInTheDocument();
592
+ });
593
+
594
+ it('does not render a tooltip when disabled without a reason', () => {
595
+ render(
596
+ <TextInput label="Owner" value="" onChange={() => {}} isDisabled />,
597
+ );
598
+ expect(screen.queryByRole('tooltip', h)).not.toBeInTheDocument();
599
+ });
600
+
601
+ it('keeps the input focusable via aria-disabled when a reason is provided', () => {
602
+ render(
603
+ <TextInput
604
+ label="Owner"
605
+ value=""
606
+ onChange={() => {}}
607
+ isDisabled
608
+ disabledMessage="You need the Editor role"
609
+ />,
610
+ );
611
+ const input = screen.getByRole('textbox');
612
+ expect(input).not.toBeDisabled();
613
+ expect(input).toHaveAttribute('aria-disabled', 'true');
614
+ expect(input).toHaveAttribute('readonly');
615
+ });
616
+
617
+ it('links the reason tooltip from the input via aria-describedby', () => {
618
+ render(
619
+ <TextInput
620
+ label="Owner"
621
+ value=""
622
+ onChange={() => {}}
623
+ isDisabled
624
+ disabledMessage="You need the Editor role"
625
+ />,
626
+ );
627
+ const input = screen.getByRole('textbox');
628
+ const tooltip = screen.getByRole('tooltip', h);
629
+ expect(input.getAttribute('aria-describedby')).toContain(tooltip.id);
630
+ });
631
+
632
+ it('blocks value changes while focusable-disabled', async () => {
633
+ const user = userEvent.setup();
634
+ const onChange = vi.fn();
635
+ render(
636
+ <TextInput
637
+ label="Owner"
638
+ value=""
639
+ onChange={onChange}
640
+ isDisabled
641
+ disabledMessage="You need the Editor role"
642
+ />,
643
+ );
644
+
645
+ const input = screen.getByRole('textbox');
646
+ await user.click(input);
647
+ await user.keyboard('hello');
648
+ expect(onChange).not.toHaveBeenCalled();
649
+ expect(input).toHaveValue('');
650
+ });
651
+
652
+ it('remains natively disabled when disabled without a reason', () => {
653
+ render(
654
+ <TextInput label="Owner" value="" onChange={() => {}} isDisabled />,
655
+ );
656
+ const input = screen.getByRole('textbox');
657
+ expect(input).toBeDisabled();
658
+ expect(input).not.toHaveAttribute('aria-disabled');
659
+ });
660
+ });
527
661
  });
@@ -4,7 +4,7 @@
4
4
 
5
5
  /**
6
6
  * @file TextInput.tsx
7
- * @input Uses React, useId, ChangeEvent, Field, Icon
7
+ * @input Uses React, useId, ChangeEvent, Field, Icon, InputGroupContext
8
8
  * @output Exports TextInput component, TextInputProps
9
9
  * @position Core implementation; consumed by index.ts, tested by TextInput.test.tsx
10
10
  *
@@ -47,6 +47,9 @@ import {
47
47
  } from '../Field';
48
48
  import {Icon, renderIconSlot, type IconType} from '../Icon';
49
49
  import {Spinner} from '../Spinner';
50
+ import {useTooltip} from '../Tooltip';
51
+ import {VisuallyHidden} from '../VisuallyHidden';
52
+ import {getInputARIA} from '../utils';
50
53
 
51
54
  const styles = stylex.create({
52
55
  clearButton: {
@@ -162,6 +165,27 @@ export interface TextInputProps extends Omit<
162
165
  * @default false
163
166
  */
164
167
  isDisabled?: boolean;
168
+ /**
169
+ * Explains why the input is disabled. When set together with `isDisabled`,
170
+ * the input shows a tooltip with this text on hover and keyboard focus, and
171
+ * stays focusable (via `aria-disabled`) so the reason is discoverable by
172
+ * keyboard and assistive technology. The field cannot be edited (it becomes
173
+ * read-only) while disabled.
174
+ *
175
+ * Use this instead of wrapping a disabled input in `Tooltip` — disabled
176
+ * controls don't emit the pointer events an external tooltip needs.
177
+ *
178
+ * @example
179
+ * ```
180
+ * <TextInput
181
+ * label="Owner"
182
+ * value={owner}
183
+ * isDisabled
184
+ * disabledMessage="You need the Editor role to change this"
185
+ * />
186
+ * ```
187
+ */
188
+ disabledMessage?: string;
165
189
  /**
166
190
  * Icon to display at the start of the input.
167
191
  * Accepts a ReactNode (e.g. `<Icon icon={SearchIcon} />`) or an SVG icon component directly.
@@ -252,6 +276,7 @@ export function TextInput({
252
276
  isOptional = false,
253
277
  isRequired = false,
254
278
  isDisabled = false,
279
+ disabledMessage,
255
280
  startIcon,
256
281
  status,
257
282
  size: sizeProp,
@@ -276,6 +301,7 @@ export function TextInput({
276
301
  const size = useSize(sizeProp, 'md');
277
302
 
278
303
  const id = useId();
304
+ const inputLabelID = useId();
279
305
  const descriptionID = useId();
280
306
  const statusMessageID = useId();
281
307
  const inputRef = useRef<HTMLInputElement | null>(null);
@@ -286,6 +312,20 @@ export function TextInput({
286
312
  const [optimisticValue, setOptimisticValue] = useOptimistic(value);
287
313
  const isBusy = isLoading || optimisticValue !== value;
288
314
 
315
+ // Disabled-reason tooltip. Disabled controls swallow pointer events, so the
316
+ // tooltip listeners attach to the input container (which already exists) and
317
+ // the input stays perceivable via aria-disabled instead of the native
318
+ // disabled attribute. The field is made read-only so it can't be typed into,
319
+ // and value mutation is blocked by the isDisabled guard in handleChange.
320
+ const showsDisabledMessage = isDisabled && !!disabledMessage;
321
+ const disabledMessageTooltip = useTooltip({
322
+ placement: 'above',
323
+ // The container div is not naturally focusable; focusin bubbles up from
324
+ // the input, so always attach focus listeners.
325
+ focusTrigger: 'always',
326
+ isEnabled: showsDisabledMessage,
327
+ });
328
+
289
329
  const statusIconMap: Record<InputStatusType, IconName> = {
290
330
  warning: 'warning',
291
331
  error: 'error',
@@ -301,15 +341,23 @@ export function TextInput({
301
341
  success: 'success',
302
342
  };
303
343
 
304
- const ariaDescribedBy =
344
+ const {ariaLabelledBy, ariaDescribedBy} = getInputARIA(
345
+ inputLabelID,
305
346
  [
306
347
  description ? descriptionID : null,
307
348
  status?.message ? statusMessageID : null,
308
- ]
309
- .filter(Boolean)
310
- .join(' ') || undefined;
349
+ showsDisabledMessage ? disabledMessageTooltip.describedBy : null,
350
+ ],
351
+ inputGroup,
352
+ );
311
353
 
312
354
  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
355
+ // Value can't change while showing a disabled message (the field is
356
+ // read-only and non-native-disabled), but guard the handler too so the
357
+ // optimistic value and callbacks never fire.
358
+ if (isDisabled) {
359
+ return;
360
+ }
313
361
  const newValue = e.target.value;
314
362
  onChange?.(newValue, e);
315
363
  if (changeAction && !e.defaultPrevented) {
@@ -336,7 +384,13 @@ export function TextInput({
336
384
 
337
385
  const inputWrapper = (
338
386
  <div
339
- ref={containerRef}
387
+ ref={el => {
388
+ containerRef.current = el;
389
+ // Anchor + hover/focus listeners for the disabled-message tooltip.
390
+ // Handlers are gated internally by isEnabled, and anchor names
391
+ // compose, so attaching unconditionally is safe.
392
+ disabledMessageTooltip.ref(el);
393
+ }}
340
394
  onClick={handleWrapperClick}
341
395
  onMouseUp={handleWrapperMouseUp}
342
396
  {...mergeProps(
@@ -355,6 +409,7 @@ export function TextInput({
355
409
  style,
356
410
  )}>
357
411
  {startIcon && renderIconSlot(startIcon, {size: 'sm', color: 'secondary'})}
412
+ {inputGroup && <VisuallyHidden id={inputLabelID}>{label}</VisuallyHidden>}
358
413
  <input
359
414
  {...rest}
360
415
  ref={mergeRefs(ref, inputRef)}
@@ -374,14 +429,19 @@ export function TextInput({
374
429
  : undefined
375
430
  }
376
431
  placeholder={placeholder}
377
- disabled={isDisabled}
432
+ // With a disabledMessage the input keeps focusability via aria-disabled
433
+ // so the reason is focus-discoverable; readOnly + the handleChange guard
434
+ // keep the value from changing.
435
+ disabled={isDisabled && !showsDisabledMessage}
436
+ aria-disabled={showsDisabledMessage ? 'true' : undefined}
437
+ readOnly={showsDisabledMessage || undefined}
378
438
  autoFocus={hasAutoFocus}
379
439
  data-autofocus={hasAutoFocus || undefined}
380
440
  aria-describedby={ariaDescribedBy}
381
441
  aria-required={isRequired === true ? 'true' : undefined}
382
442
  aria-invalid={status?.type === 'error' ? 'true' : undefined}
383
443
  aria-busy={isBusy || undefined}
384
- aria-label={inputGroup ? label : undefined}
444
+ aria-labelledby={ariaLabelledBy}
385
445
  {...stylex.props(styles.input, isDisabled && styles.inputDisabled)}
386
446
  />
387
447
  {hasClear && value !== '' && !isDisabled && (
@@ -405,7 +465,13 @@ export function TextInput({
405
465
  );
406
466
 
407
467
  if (inputGroup) {
408
- return inputWrapper;
468
+ return (
469
+ <>
470
+ {inputWrapper}
471
+ {showsDisabledMessage &&
472
+ disabledMessageTooltip.renderTooltip(disabledMessage)}
473
+ </>
474
+ );
409
475
  }
410
476
 
411
477
  return (
@@ -430,6 +496,8 @@ export function TextInput({
430
496
  labelTooltip={labelTooltip}
431
497
  width={width}>
432
498
  {inputWrapper}
499
+ {showsDisabledMessage &&
500
+ disabledMessageTooltip.renderTooltip(disabledMessage)}
433
501
  </Field>
434
502
  );
435
503
  }
@@ -126,11 +126,11 @@ export const docsDense = {
126
126
  description:
127
127
  'Compact square image preview. Shimmer while uploading, image on success, placeholder when empty. Use in chat composers, file lists, or small media previews.',
128
128
  bestPractices: [
129
- {guidance: true, description: 'Always set label (file name) for a11y \u2014 powers screen reader announce + hover tooltip.'},
129
+ {guidance: true, description: 'Always set label (file name) for a11y; powers screen reader announce + hover tooltip.'},
130
130
  {guidance: true, description: 'isLoading w/o src \u2192 skeleton; isLoading w/ src \u2192 spinner overlay. Two distinct loading states.'},
131
- {guidance: true, description: 'onClick adds button semantics + hover shadow \u2014 pair with lightbox for full preview.'},
132
- {guidance: false, description: "Don't use for non-image files (PDF, xlsx) \u2014 use file attachment component with icon instead."},
133
- {guidance: false, description: "Don't omit alt when src present \u2014 screen readers need image content description, not just label."},
131
+ {guidance: true, description: 'onClick adds button semantics + hover shadow; pair with lightbox for full preview.'},
132
+ {guidance: false, description: "Don't use for non-image files (PDF, xlsx); use file attachment component with icon instead."},
133
+ {guidance: false, description: "Don't omit alt when src present; screen readers need image content description, not just label."},
134
134
  ],
135
135
  },
136
136
  propDescriptions: {