@astryxdesign/core 0.1.2 → 0.1.3-canary.1e94ba0

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 (581) 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 +31 -12
  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 +12 -5
  54. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  55. package/dist/ContextMenu/ContextMenu.js +96 -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 +13 -9
  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 +79 -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 +4 -1
  207. package/dist/Table/index.d.ts.map +1 -1
  208. package/dist/Table/index.js +3 -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/rowExpansion/index.d.ts +3 -0
  215. package/dist/Table/plugins/rowExpansion/index.d.ts.map +1 -0
  216. package/dist/Table/plugins/rowExpansion/index.js +3 -0
  217. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts +90 -0
  218. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -0
  219. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +398 -0
  220. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  221. package/dist/Table/plugins/sortable/useTableSortable.js +59 -3
  222. package/dist/Table/tableContextMenu.d.ts +37 -0
  223. package/dist/Table/tableContextMenu.d.ts.map +1 -0
  224. package/dist/Table/tableContextMenu.js +140 -0
  225. package/dist/Table/types.d.ts +66 -0
  226. package/dist/Table/types.d.ts.map +1 -1
  227. package/dist/TextArea/TextArea.d.ts +22 -1
  228. package/dist/TextArea/TextArea.d.ts.map +1 -1
  229. package/dist/TextArea/TextArea.js +41 -9
  230. package/dist/TextInput/TextInput.d.ts +23 -2
  231. package/dist/TextInput/TextInput.d.ts.map +1 -1
  232. package/dist/TextInput/TextInput.js +55 -10
  233. package/dist/TimeInput/TimeInput.d.ts +23 -1
  234. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  235. package/dist/TimeInput/TimeInput.js +147 -76
  236. package/dist/Toast/Toast.d.ts.map +1 -1
  237. package/dist/Toast/Toast.js +14 -0
  238. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  239. package/dist/Toast/ToastViewport.js +131 -3
  240. package/dist/Tokenizer/Tokenizer.d.ts +12 -1
  241. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  242. package/dist/Tokenizer/Tokenizer.js +26 -4
  243. package/dist/Toolbar/Toolbar.d.ts +3 -3
  244. package/dist/Toolbar/Toolbar.d.ts.map +1 -1
  245. package/dist/Toolbar/Toolbar.js +51 -7
  246. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  247. package/dist/Tooltip/useTooltip.js +56 -9
  248. package/dist/TopNav/TopNavHeading.d.ts +7 -1
  249. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  250. package/dist/TopNav/TopNavHeading.js +8 -0
  251. package/dist/TreeList/TreeList.d.ts +1 -1
  252. package/dist/TreeList/TreeList.d.ts.map +1 -1
  253. package/dist/TreeList/TreeList.js +72 -2
  254. package/dist/TreeList/TreeListItem.d.ts +11 -1
  255. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  256. package/dist/TreeList/TreeListItem.js +51 -12
  257. package/dist/TreeList/treeListItem.markers.stylex.d.ts +16 -0
  258. package/dist/TreeList/treeListItem.markers.stylex.d.ts.map +1 -0
  259. package/dist/TreeList/treeListItem.markers.stylex.js +22 -0
  260. package/dist/Typeahead/BaseTypeahead.d.ts +13 -0
  261. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  262. package/dist/Typeahead/BaseTypeahead.js +69 -6
  263. package/dist/Typeahead/Typeahead.d.ts +26 -3
  264. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  265. package/dist/Typeahead/Typeahead.js +65 -29
  266. package/dist/VisuallyHidden/VisuallyHidden.d.ts +61 -0
  267. package/dist/VisuallyHidden/VisuallyHidden.d.ts.map +1 -0
  268. package/dist/VisuallyHidden/VisuallyHidden.js +65 -0
  269. package/dist/VisuallyHidden/index.d.ts +11 -0
  270. package/dist/VisuallyHidden/index.d.ts.map +1 -0
  271. package/dist/VisuallyHidden/index.js +13 -0
  272. package/dist/astryx.css +22 -0
  273. package/dist/astryx.umd.js +54 -54
  274. package/dist/astryx.umd.js.map +4 -4
  275. package/dist/hooks/focusableSelector.d.ts +22 -0
  276. package/dist/hooks/focusableSelector.d.ts.map +1 -0
  277. package/dist/hooks/focusableSelector.js +24 -0
  278. package/dist/hooks/index.d.ts +12 -2
  279. package/dist/hooks/index.d.ts.map +1 -1
  280. package/dist/hooks/index.js +7 -2
  281. package/dist/hooks/useAnnounce.d.ts +40 -0
  282. package/dist/hooks/useAnnounce.d.ts.map +1 -0
  283. package/dist/hooks/useAnnounce.js +142 -0
  284. package/dist/hooks/useClickableContainer.d.ts +16 -1
  285. package/dist/hooks/useClickableContainer.d.ts.map +1 -1
  286. package/dist/hooks/useClickableContainer.js +16 -4
  287. package/dist/hooks/useEntryAnimation.d.ts.map +1 -1
  288. package/dist/hooks/useEntryAnimation.js +4 -4
  289. package/dist/hooks/useFocusTrap.d.ts +18 -0
  290. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  291. package/dist/hooks/useFocusTrap.js +87 -3
  292. package/dist/hooks/useGridFocus.d.ts +88 -1
  293. package/dist/hooks/useGridFocus.d.ts.map +1 -1
  294. package/dist/hooks/useGridFocus.js +261 -62
  295. package/dist/hooks/useKeyboardHint.d.ts +82 -0
  296. package/dist/hooks/useKeyboardHint.d.ts.map +1 -0
  297. package/dist/hooks/useKeyboardHint.js +220 -0
  298. package/dist/hooks/useListFocus.d.ts +78 -7
  299. package/dist/hooks/useListFocus.d.ts.map +1 -1
  300. package/dist/hooks/useListFocus.js +305 -52
  301. package/dist/hooks/useLongPress.d.ts +21 -0
  302. package/dist/hooks/useLongPress.d.ts.map +1 -0
  303. package/dist/hooks/useLongPress.js +89 -0
  304. package/dist/hooks/useTreeFocus.d.ts +157 -0
  305. package/dist/hooks/useTreeFocus.d.ts.map +1 -0
  306. package/dist/hooks/useTreeFocus.js +337 -0
  307. package/dist/hooks/useTypeahead.d.ts +63 -0
  308. package/dist/hooks/useTypeahead.d.ts.map +1 -0
  309. package/dist/hooks/useTypeahead.js +117 -0
  310. package/dist/index.d.ts +1 -0
  311. package/dist/index.d.ts.map +1 -1
  312. package/dist/index.js +1 -0
  313. package/dist/utils/dateTypes.d.ts +12 -0
  314. package/dist/utils/dateTypes.d.ts.map +1 -1
  315. package/dist/utils/dateTypes.js +41 -1
  316. package/dist/utils/index.d.ts +4 -0
  317. package/dist/utils/index.d.ts.map +1 -1
  318. package/dist/utils/index.js +3 -1
  319. package/dist/utils/inputAria.d.ts +29 -0
  320. package/dist/utils/inputAria.d.ts.map +1 -0
  321. package/dist/utils/inputAria.js +30 -0
  322. package/dist/utils/timeParser.d.ts.map +1 -1
  323. package/dist/utils/timeParser.js +5 -2
  324. package/docs.mjs +2 -2
  325. package/package.json +12 -8
  326. package/src/Avatar/Avatar.doc.mjs +2 -2
  327. package/src/Avatar/Avatar.test.tsx +37 -0
  328. package/src/Avatar/Avatar.tsx +10 -5
  329. package/src/Breadcrumbs/BreadcrumbItem.tsx +25 -7
  330. package/src/Breadcrumbs/Breadcrumbs.test.tsx +31 -10
  331. package/src/Button/Button.tsx +42 -22
  332. package/src/ButtonGroup/ButtonGroup.test.tsx +9 -9
  333. package/src/ButtonGroup/ButtonGroup.tsx +0 -1
  334. package/src/Calendar/Calendar.doc.mjs +4 -4
  335. package/src/Calendar/Calendar.test.tsx +168 -30
  336. package/src/Calendar/Calendar.tsx +121 -66
  337. package/src/Calendar/hooks/index.ts +0 -6
  338. package/src/Calendar/index.ts +1 -3
  339. package/src/Calendar/styles.ts +4 -9
  340. package/src/Carousel/Carousel.doc.mjs +7 -1
  341. package/src/Carousel/Carousel.test.tsx +20 -0
  342. package/src/Carousel/Carousel.tsx +16 -1
  343. package/src/Center/Center.doc.mjs +12 -2
  344. package/src/Center/Center.tsx +28 -3
  345. package/src/Chat/ChatComposerInput.test.tsx +26 -7
  346. package/src/Chat/ChatComposerInput.tsx +0 -1
  347. package/src/Chat/ChatDictationButton.doc.mjs +1 -1
  348. package/src/Chat/ChatMessageList.doc.mjs +8 -0
  349. package/src/Chat/ChatMessageList.test.tsx +18 -0
  350. package/src/Chat/ChatMessageList.tsx +16 -0
  351. package/src/Chat/useTriggerMenu.tsx +22 -4
  352. package/src/CheckboxInput/CheckboxInput.doc.mjs +10 -0
  353. package/src/CheckboxInput/CheckboxInput.test.tsx +172 -27
  354. package/src/CheckboxInput/CheckboxInput.tsx +78 -6
  355. package/src/CheckboxList/CheckboxList.doc.mjs +9 -0
  356. package/src/CheckboxList/CheckboxList.test.tsx +192 -26
  357. package/src/CheckboxList/CheckboxList.tsx +56 -3
  358. package/src/CheckboxList/CheckboxListContext.tsx +7 -0
  359. package/src/CheckboxList/CheckboxListItem.tsx +0 -3
  360. package/src/Citation/Citation.doc.mjs +10 -0
  361. package/src/Citation/Citation.test.tsx +121 -0
  362. package/src/Citation/Citation.tsx +15 -3
  363. package/src/CodeBlock/CodeBlock.test.tsx +115 -0
  364. package/src/CodeBlock/CodeBlock.tsx +63 -33
  365. package/src/CommandPalette/CommandPalette.test.tsx +47 -1
  366. package/src/CommandPalette/CommandPalette.tsx +9 -21
  367. package/src/ContextMenu/ContextMenu.doc.mjs +4 -4
  368. package/src/ContextMenu/ContextMenu.test.tsx +155 -1
  369. package/src/ContextMenu/ContextMenu.tsx +129 -16
  370. package/src/DateInput/DateInput.doc.mjs +286 -56
  371. package/src/DateInput/DateInput.test.tsx +248 -2
  372. package/src/DateInput/DateInput.tsx +196 -100
  373. package/src/DateRangeInput/DateRangeInput.doc.mjs +251 -46
  374. package/src/DateRangeInput/DateRangeInput.test.tsx +182 -20
  375. package/src/DateRangeInput/DateRangeInput.tsx +63 -5
  376. package/src/DateTimeInput/DateTimeInput.doc.mjs +368 -67
  377. package/src/DateTimeInput/DateTimeInput.test.tsx +279 -11
  378. package/src/DateTimeInput/DateTimeInput.tsx +125 -17
  379. package/src/Dialog/Dialog.doc.mjs +2 -2
  380. package/src/Dialog/Dialog.tsx +12 -0
  381. package/src/DropdownMenu/DropdownMenu.doc.mjs +1 -8
  382. package/src/DropdownMenu/DropdownMenu.test.tsx +56 -42
  383. package/src/DropdownMenu/DropdownMenu.tsx +52 -18
  384. package/src/Field/Field.doc.mjs +59 -18
  385. package/src/Field/Field.test.tsx +32 -0
  386. package/src/Field/Field.tsx +23 -5
  387. package/src/Field/FieldLabel.tsx +55 -17
  388. package/src/FileInput/FileInput.doc.mjs +17 -0
  389. package/src/FileInput/FileInput.test.tsx +283 -49
  390. package/src/FileInput/FileInput.tsx +76 -4
  391. package/src/Grid/Grid.doc.mjs +17 -4
  392. package/src/Grid/Grid.test.tsx +43 -30
  393. package/src/Grid/Grid.tsx +38 -3
  394. package/src/Icon/Icon.doc.mjs +3 -3
  395. package/src/InputGroup/InputGroup.doc.mjs +111 -23
  396. package/src/InputGroup/InputGroup.test.tsx +257 -60
  397. package/src/InputGroup/InputGroup.tsx +23 -5
  398. package/src/InputGroup/InputGroupContext.ts +9 -4
  399. package/src/InputGroup/groupStyles.ts +7 -1
  400. package/src/InputGroup/index.ts +1 -0
  401. package/src/Kbd/Kbd.test.tsx +22 -4
  402. package/src/Kbd/Kbd.tsx +35 -3
  403. package/src/Layer/layerAnimations.stylex.ts +20 -4
  404. package/src/Layer/useLayer.doc.mjs +5 -0
  405. package/src/Layer/useLayer.test.tsx +111 -0
  406. package/src/Layer/useLayer.tsx +90 -9
  407. package/src/Layout/Layout.tsx +8 -16
  408. package/src/Layout/LayoutFooter.doc.mjs +4 -4
  409. package/src/Layout/LayoutFooter.tsx +3 -3
  410. package/src/Layout/LayoutHeader.doc.mjs +4 -4
  411. package/src/Layout/LayoutHeader.tsx +3 -3
  412. package/src/Layout/LayoutPanel.tsx +3 -3
  413. package/src/Layout/__tests__/edgeCompensation.test.tsx +72 -0
  414. package/src/Layout/padding.stylex.ts +52 -0
  415. package/src/Lightbox/Lightbox.doc.mjs +9 -0
  416. package/src/Lightbox/Lightbox.test.tsx +53 -5
  417. package/src/Lightbox/Lightbox.tsx +9 -4
  418. package/src/Link/Link.doc.mjs +14 -0
  419. package/src/Link/Link.test.tsx +50 -0
  420. package/src/Link/Link.tsx +39 -4
  421. package/src/Markdown/Markdown.test.tsx +11 -0
  422. package/src/Markdown/Markdown.tsx +7 -0
  423. package/src/MetadataList/MetadataListItem.doc.mjs +4 -0
  424. package/src/MoreMenu/MoreMenu.doc.mjs +2 -17
  425. package/src/MoreMenu/MoreMenu.tsx +0 -9
  426. package/src/MultiSelector/MultiSelector.doc.mjs +30 -0
  427. package/src/MultiSelector/MultiSelector.test.tsx +375 -8
  428. package/src/MultiSelector/MultiSelector.tsx +194 -48
  429. package/src/MultiSelector/hooks.ts +27 -0
  430. package/src/NavMenu/NavHeadingMenu.test.tsx +77 -1
  431. package/src/NavMenu/NavHeadingMenu.tsx +50 -3
  432. package/src/NumberInput/NumberInput.doc.mjs +17 -0
  433. package/src/NumberInput/NumberInput.test.tsx +242 -40
  434. package/src/NumberInput/NumberInput.tsx +89 -11
  435. package/src/Pagination/Pagination.doc.mjs +3 -3
  436. package/src/Pagination/Pagination.test.tsx +117 -5
  437. package/src/Pagination/Pagination.tsx +21 -1
  438. package/src/Popover/Popover.doc.mjs +26 -0
  439. package/src/Popover/Popover.test.tsx +121 -0
  440. package/src/Popover/Popover.tsx +23 -2
  441. package/src/Popover/usePopover.doc.mjs +9 -3
  442. package/src/Popover/usePopover.tsx +70 -12
  443. package/src/PowerSearch/PowerSearch.doc.mjs +15 -0
  444. package/src/PowerSearch/PowerSearch.test.tsx +97 -1
  445. package/src/PowerSearch/PowerSearch.tsx +16 -3
  446. package/src/ProgressBar/ProgressBar.test.tsx +34 -26
  447. package/src/ProgressBar/ProgressBar.tsx +3 -4
  448. package/src/RadioList/RadioList.doc.mjs +9 -0
  449. package/src/RadioList/RadioList.test.tsx +252 -16
  450. package/src/RadioList/RadioList.tsx +166 -10
  451. package/src/RadioList/RadioListItem.tsx +14 -2
  452. package/src/SegmentedControl/SegmentedControl.doc.mjs +9 -0
  453. package/src/SegmentedControl/SegmentedControl.test.tsx +214 -42
  454. package/src/SegmentedControl/SegmentedControl.tsx +102 -54
  455. package/src/SegmentedControl/SegmentedControlContext.ts +7 -0
  456. package/src/SegmentedControl/SegmentedControlItem.tsx +14 -1
  457. package/src/SelectableCard/SelectableCard.doc.mjs +1 -1
  458. package/src/Selector/Selector.doc.mjs +26 -0
  459. package/src/Selector/Selector.test.tsx +387 -15
  460. package/src/Selector/Selector.tsx +175 -67
  461. package/src/Selector/hooks.ts +23 -0
  462. package/src/SideNav/SideNav.test.tsx +48 -0
  463. package/src/SideNav/SideNavHeading.tsx +8 -2
  464. package/src/SideNav/SideNavItem.tsx +2 -4
  465. package/src/Skeleton/Skeleton.test.tsx +25 -0
  466. package/src/Skeleton/Skeleton.tsx +11 -1
  467. package/src/Slider/Slider.doc.mjs +15 -0
  468. package/src/Slider/Slider.test.tsx +155 -2
  469. package/src/Slider/Slider.tsx +53 -5
  470. package/src/Spinner/Spinner.tsx +7 -1
  471. package/src/Stack/Stack.doc.mjs +77 -0
  472. package/src/Stack/Stack.test.tsx +55 -5
  473. package/src/Stack/Stack.tsx +73 -24
  474. package/src/Stack/StackItem.test.tsx +23 -0
  475. package/src/Stack/StackItem.tsx +20 -23
  476. package/src/Switch/Switch.doc.mjs +15 -0
  477. package/src/Switch/Switch.test.tsx +162 -27
  478. package/src/Switch/Switch.tsx +61 -21
  479. package/src/TabList/Tab.tsx +6 -0
  480. package/src/TabList/TabList.doc.mjs +6 -0
  481. package/src/TabList/TabList.test.tsx +251 -0
  482. package/src/TabList/TabList.tsx +103 -12
  483. package/src/TabList/TabListContext.ts +7 -3
  484. package/src/TabList/TabMenu.tsx +6 -3
  485. package/src/Table/BaseTable.tsx +24 -18
  486. package/src/Table/Table.doc.mjs +2 -0
  487. package/src/Table/Table.test.tsx +10 -0
  488. package/src/Table/Table.tsx +8 -0
  489. package/src/Table/TableCell.tsx +105 -24
  490. package/src/Table/TableHeaderCell.tsx +28 -29
  491. package/src/Table/index.ts +8 -2
  492. package/src/Table/plugins/pagination/paginateData.ts +10 -3
  493. package/src/Table/plugins/pagination/useTablePagination.test.tsx +16 -0
  494. package/src/Table/plugins/pagination/useTablePagination.tsx +8 -1
  495. package/src/Table/plugins/rowExpansion/index.ts +7 -0
  496. package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +155 -0
  497. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +590 -0
  498. package/src/Table/plugins/sortable/useTableSortable.test.tsx +91 -2
  499. package/src/Table/plugins/sortable/useTableSortable.tsx +53 -1
  500. package/src/Table/tableContextMenu.test.tsx +181 -0
  501. package/src/Table/tableContextMenu.tsx +160 -0
  502. package/src/Table/types.ts +74 -0
  503. package/src/Table/useTableColumnResize.doc.mjs +3 -3
  504. package/src/Table/useTablePagination.doc.mjs +4 -1
  505. package/src/Table/useTableRowExpansion.doc.mjs +63 -0
  506. package/src/Table/useTableSortable.doc.mjs +4 -1
  507. package/src/Table/useTableStickyColumns.doc.mjs +2 -2
  508. package/src/Text/Text.doc.mjs +18 -18
  509. package/src/TextArea/TextArea.doc.mjs +17 -0
  510. package/src/TextArea/TextArea.test.tsx +167 -35
  511. package/src/TextArea/TextArea.tsx +62 -15
  512. package/src/TextInput/TextInput.doc.mjs +17 -0
  513. package/src/TextInput/TextInput.test.tsx +168 -34
  514. package/src/TextInput/TextInput.tsx +77 -9
  515. package/src/Thumbnail/Thumbnail.doc.mjs +4 -4
  516. package/src/TimeInput/TimeInput.doc.mjs +345 -60
  517. package/src/TimeInput/TimeInput.test.tsx +255 -7
  518. package/src/TimeInput/TimeInput.tsx +176 -70
  519. package/src/Timestamp/Timestamp.doc.mjs +19 -19
  520. package/src/Toast/Toast.tsx +14 -0
  521. package/src/Toast/ToastViewport.test.tsx +214 -0
  522. package/src/Toast/ToastViewport.tsx +167 -21
  523. package/src/Tokenizer/Tokenizer.doc.mjs +29 -14
  524. package/src/Tokenizer/Tokenizer.test.tsx +105 -1
  525. package/src/Tokenizer/Tokenizer.tsx +37 -1
  526. package/src/Toolbar/Toolbar.test.tsx +109 -6
  527. package/src/Toolbar/Toolbar.tsx +59 -5
  528. package/src/Tooltip/Tooltip.test.tsx +68 -0
  529. package/src/Tooltip/useTooltip.tsx +55 -8
  530. package/src/TopNav/TopNav.test.tsx +50 -0
  531. package/src/TopNav/TopNavHeading.tsx +17 -1
  532. package/src/TreeList/TreeList.test.tsx +295 -6
  533. package/src/TreeList/TreeList.tsx +73 -1
  534. package/src/TreeList/TreeListItem.tsx +51 -5
  535. package/src/TreeList/treeListItem.markers.stylex.ts +20 -0
  536. package/src/Typeahead/BaseTypeahead.tsx +93 -9
  537. package/src/Typeahead/Typeahead.doc.mjs +141 -30
  538. package/src/Typeahead/Typeahead.test.tsx +331 -1
  539. package/src/Typeahead/Typeahead.tsx +105 -33
  540. package/src/VisuallyHidden/VisuallyHidden.doc.mjs +80 -0
  541. package/src/VisuallyHidden/VisuallyHidden.test.tsx +76 -0
  542. package/src/VisuallyHidden/VisuallyHidden.tsx +113 -0
  543. package/src/VisuallyHidden/index.ts +15 -0
  544. package/src/docs-script.test.mjs +50 -0
  545. package/src/hooks/focusableSelector.ts +25 -0
  546. package/src/hooks/index.ts +28 -2
  547. package/src/hooks/useAnnounce.test.tsx +101 -0
  548. package/src/hooks/useAnnounce.ts +168 -0
  549. package/src/hooks/useClickableContainer.ts +16 -4
  550. package/src/hooks/useEntryAnimation.ts +16 -4
  551. package/src/hooks/useFocusTrap.test.tsx +132 -0
  552. package/src/hooks/useFocusTrap.ts +98 -4
  553. package/src/hooks/useGridFocus.doc.mjs +40 -2
  554. package/src/hooks/useGridFocus.test.tsx +132 -0
  555. package/src/hooks/useGridFocus.ts +343 -67
  556. package/src/hooks/useKeyboardHint.doc.mjs +101 -0
  557. package/src/hooks/useKeyboardHint.test.tsx +70 -0
  558. package/src/hooks/useKeyboardHint.tsx +332 -0
  559. package/src/hooks/useListFocus.doc.mjs +50 -10
  560. package/src/hooks/useListFocus.test.tsx +375 -0
  561. package/src/hooks/useListFocus.ts +395 -57
  562. package/src/hooks/useLongPress.test.tsx +134 -0
  563. package/src/hooks/useLongPress.ts +119 -0
  564. package/src/hooks/useTreeFocus.doc.mjs +140 -0
  565. package/src/hooks/useTreeFocus.test.tsx +214 -0
  566. package/src/hooks/useTreeFocus.ts +559 -0
  567. package/src/hooks/useTypeahead.test.tsx +109 -0
  568. package/src/hooks/useTypeahead.ts +183 -0
  569. package/src/index.ts +1 -0
  570. package/src/theme/derivedVarRegistry.test.ts +10 -5
  571. package/src/utils/dateTypes.test.ts +40 -0
  572. package/src/utils/dateTypes.ts +40 -0
  573. package/src/utils/index.ts +9 -0
  574. package/src/utils/inputAria.test.ts +39 -0
  575. package/src/utils/inputAria.ts +58 -0
  576. package/src/utils/timeParser.test.ts +10 -0
  577. package/src/utils/timeParser.ts +5 -2
  578. package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts +0 -57
  579. package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts.map +0 -1
  580. package/dist/Calendar/hooks/useCalendarRovingTabindex.js +0 -96
  581. package/src/Calendar/hooks/useCalendarRovingTabindex.ts +0 -118
@@ -124,15 +124,15 @@ export const docs = {
124
124
  description:
125
125
  'Text renders styled body text and headings from the theme. Use Text with a semantic type for body copy, labels, and captions, and Heading for section titles that output the correct h1\u2013h6 element.',
126
126
  bestPractices: [
127
- { guidance: true, description: 'Pick a semantic type (body, label, supporting, large, code) instead of manually setting size and weight \u2014 the theme handles the details.' },
127
+ { guidance: true, description: 'Pick a semantic type (body, label, supporting, large, code) instead of manually setting size and weight; the theme handles the details.' },
128
128
  { guidance: true, description: 'Set accessibilityLevel on Heading when the visual level differs from the document outline so screen readers announce the correct hierarchy.' },
129
- { guidance: true, description: 'Use maxLines with a number to truncate long content \u2014 a tooltip appears automatically on hover so no text is lost.' },
129
+ { guidance: true, description: 'Use maxLines with a number to truncate long content; a tooltip appears automatically on hover so no text is lost.' },
130
130
  { guidance: true, description: 'Enable hasTabularNumbers for columns of numeric data so digits align vertically across rows.' },
131
- { guidance: false, description: 'Override size and weight when a semantic type already matches \u2014 extra overrides fight the theme and break when themes change.' },
132
- { guidance: false, description: 'Skip heading levels in the document outline \u2014 go h1 then h2 then h3, never h1 then h3.' },
133
- { guidance: false, description: 'Use raw HTML tags like <p>, <h1>\u2013<h6>, or <span> for text \u2014 Text and Heading apply the correct theme tokens automatically.' },
134
- { guidance: false, description: 'Pass a `variant` prop \u2014 Text does not have a `variant` prop. Use `type` for semantic styling (body, label, large, supporting, code) or use Heading for headings.' },
135
- { guidance: false, description: 'Use Text for headings \u2014 use Heading with a `level` prop (1\u20136) for section titles and headings.' },
131
+ { guidance: false, description: 'Override size and weight when a semantic type already matches; extra overrides fight the theme and break when themes change.' },
132
+ { guidance: false, description: 'Skip heading levels in the document outline; go h1 then h2 then h3, never h1 then h3.' },
133
+ { guidance: false, description: 'Use raw HTML tags like <p>, <h1>\u2013<h6>, or <span> for text; Text and Heading apply the correct theme tokens automatically.' },
134
+ { guidance: false, description: 'Pass a `variant` prop; Text does not have a `variant` prop. Use `type` for semantic styling (body, label, large, supporting, code) or use Heading for headings.' },
135
+ { guidance: false, description: 'Use Text for headings; use Heading with a `level` prop (1\u20136) for section titles and headings.' },
136
136
  ],
137
137
  },
138
138
  };
@@ -143,15 +143,15 @@ export const docsZh = {
143
143
  description:
144
144
  'Text renders styled body text and headings from the theme. Use Text with a semantic type for body copy, labels, and captions, and Heading for section titles that output the correct h1\u2013h6 element.',
145
145
  bestPractices: [
146
- { guidance: true, description: 'Pick a semantic type (body, label, supporting, large, code) instead of manually setting size and weight \u2014 the theme handles the details.' },
146
+ { guidance: true, description: 'Pick a semantic type (body, label, supporting, large, code) instead of manually setting size and weight; the theme handles the details.' },
147
147
  { guidance: true, description: 'Set accessibilityLevel on Heading when the visual level differs from the document outline so screen readers announce the correct hierarchy.' },
148
- { guidance: true, description: 'Use maxLines with a number to truncate long content \u2014 a tooltip appears automatically on hover so no text is lost.' },
148
+ { guidance: true, description: 'Use maxLines with a number to truncate long content; a tooltip appears automatically on hover so no text is lost.' },
149
149
  { guidance: true, description: 'Enable hasTabularNumbers for columns of numeric data so digits align vertically across rows.' },
150
- { guidance: false, description: 'Override size and weight when a semantic type already matches \u2014 extra overrides fight the theme and break when themes change.' },
151
- { guidance: false, description: 'Skip heading levels in the document outline \u2014 go h1 then h2 then h3, never h1 then h3.' },
152
- { guidance: false, description: 'Use raw HTML tags like <p>, <h1>\u2013<h6>, or <span> for text \u2014 Text and Heading apply the correct theme tokens automatically.' },
153
- { guidance: false, description: 'Pass a `variant` prop \u2014 Text does not have a `variant` prop. Use `type` for semantic styling (body, label, large, supporting, code) or use Heading for headings.' },
154
- { guidance: false, description: 'Use Text for headings \u2014 use Heading with a `level` prop (1\u20136) for section titles and headings.' },
150
+ { guidance: false, description: 'Override size and weight when a semantic type already matches; extra overrides fight the theme and break when themes change.' },
151
+ { guidance: false, description: 'Skip heading levels in the document outline; go h1 then h2 then h3, never h1 then h3.' },
152
+ { guidance: false, description: 'Use raw HTML tags like <p>, <h1>\u2013<h6>, or <span> for text; Text and Heading apply the correct theme tokens automatically.' },
153
+ { guidance: false, description: 'Pass a `variant` prop; Text does not have a `variant` prop. Use `type` for semantic styling (body, label, large, supporting, code) or use Heading for headings.' },
154
+ { guidance: false, description: 'Use Text for headings; use Heading with a `level` prop (1\u20136) for section titles and headings.' },
155
155
  ],
156
156
  },
157
157
  };
@@ -165,12 +165,12 @@ export const docsDense = {
165
165
  bestPractices: [
166
166
  { guidance: true, description: 'Semantic type (body, label, supporting, large, code) instead of manual size/weight.' },
167
167
  { guidance: true, description: 'accessibilityLevel on Heading when visual level differs from document outline.' },
168
- { guidance: true, description: 'maxLines for truncation \u2014 tooltip shows full text on hover.' },
168
+ { guidance: true, description: 'maxLines for truncation; tooltip shows full text on hover.' },
169
169
  { guidance: true, description: 'hasTabularNumbers for aligned numeric columns.' },
170
170
  { guidance: false, description: 'Override size/weight when a semantic type already matches.' },
171
- { guidance: false, description: 'Skip heading levels \u2014 sequential h1 \u2192 h2 \u2192 h3.' },
172
- { guidance: false, description: 'Raw <p>/<h1>/<span> \u2014 use Text/Heading for theme tokens.' },
173
- { guidance: false, description: '`variant` prop \u2014 does not exist. Use `type` for text styling or Heading for headings.' },
171
+ { guidance: false, description: 'Skip heading levels; sequential h1 \u2192 h2 \u2192 h3.' },
172
+ { guidance: false, description: 'Raw <p>/<h1>/<span>; use Text/Heading for theme tokens.' },
173
+ { guidance: false, description: '`variant` prop, which does not exist. Use `type` for text styling or Heading for headings.' },
174
174
  { guidance: false, description: 'Text for headings: use Heading with level (1\u20136).' },
175
175
  ],
176
176
  },
@@ -70,6 +70,12 @@ export const docs = {
70
70
  description: 'Disables the textarea, preventing interaction.',
71
71
  default: 'false',
72
72
  },
73
+ {
74
+ name: 'disabledMessage',
75
+ type: 'string',
76
+ description:
77
+ 'Explains why the textarea is disabled. With isDisabled, shows a tooltip on hover/keyboard focus and keeps the textarea focusable via aria-disabled (the field becomes read-only). Use this instead of wrapping a disabled TextArea in Tooltip. Disabled controls swallow the hover events an external Tooltip needs.',
78
+ },
73
79
  {
74
80
  name: 'isLoading',
75
81
  type: 'boolean',
@@ -174,6 +180,7 @@ export const docs = {
174
180
  { guidance: false, description: 'Avoid using TextArea for short, single-line values like names or emails; use TextInput instead.' },
175
181
  { guidance: false, description: 'Don\'t rely solely on placeholder text to communicate the purpose of the field; placeholders disappear on focus and are not accessible labels.' },
176
182
  { guidance: false, description: 'Don\'t show a status message without also setting the status type; the colored border and icon are what draw the user\'s attention to the message.' },
183
+ { guidance: false, description: 'Don\'t wrap a disabled TextArea in Tooltip to explain why it\'s disabled; disabled controls swallow the hover events the wrapper needs. Use the disabledMessage prop instead.' },
177
184
  ],
178
185
  },
179
186
  };
@@ -239,6 +246,12 @@ export const docsZh = {
239
246
  description: '禁用文本域,阻止交互。',
240
247
  default: 'false',
241
248
  },
249
+ {
250
+ name: 'disabledMessage',
251
+ type: 'string',
252
+ description:
253
+ '说明文本域被禁用的原因。与 isDisabled 一起使用时,在悬停/键盘聚焦时显示工具提示,并通过 aria-disabled 保持文本域可聚焦(字段变为只读)。请使用此属性,而不是用 Tooltip 包裹已禁用的 TextArea。',
254
+ },
242
255
  {
243
256
  name: 'isLoading',
244
257
  type: 'boolean',
@@ -336,6 +349,7 @@ export const docsZh = {
336
349
  { guidance: false, description: 'Avoid using TextArea for short, single-line values like names or emails; use TextInput instead.' },
337
350
  { guidance: false, description: 'Don\'t rely solely on placeholder text to communicate the purpose of the field; placeholders disappear on focus and are not accessible labels.' },
338
351
  { guidance: false, description: 'Don\'t show a status message without also setting the status type; the colored border and icon are what draw the user\'s attention to the message.' },
352
+ { guidance: false, description: 'Don\'t wrap a disabled TextArea in Tooltip to explain why it\'s disabled; disabled controls swallow the hover events the wrapper needs. Use the disabledMessage prop instead.' },
339
353
  ],
340
354
  },
341
355
  };
@@ -354,6 +368,7 @@ export const docsDense = {
354
368
  { guidance: false, description: 'Avoid TextArea for single-line values; use TextInput.' },
355
369
  { guidance: false, description: 'Don\'t use placeholder as only label; disappears on focus, not accessible.' },
356
370
  { guidance: false, description: 'Don\'t show status message without status type; border and icon draw attention.' },
371
+ { guidance: false, description: 'Don\'t wrap a disabled TextArea in Tooltip to explain the disabled state; use the disabledMessage prop instead.' },
357
372
  ],
358
373
  },
359
374
  propDescriptions: {
@@ -367,6 +382,8 @@ export const docsDense = {
367
382
  isOptional: 'Shows "Optional" indicator. Mutually exclusive w/ isRequired.',
368
383
  isRequired: 'Shows "Required" indicator+sets aria-required. Mutually exclusive w/ isOptional.',
369
384
  isDisabled: 'Disables textarea, prevents interaction.',
385
+ disabledMessage:
386
+ 'Explains why textarea is disabled. With isDisabled, shows tooltip on hover/focus + keeps textarea focusable via aria-disabled (field becomes read-only). Use instead of wrapping a disabled TextArea in Tooltip.',
370
387
  isLoading: 'Loading state w/ spinner inside input.',
371
388
  placeholder: 'Placeholder when textarea empty.',
372
389
  rows: 'Visible text rows.',
@@ -10,12 +10,43 @@
10
10
  */
11
11
 
12
12
  import {useState} from 'react';
13
- import {describe, it, expect, vi} from 'vitest';
14
- import {render, screen, fireEvent} from '@testing-library/react';
13
+ import {describe, it, expect, vi, beforeEach} from 'vitest';
14
+ import {render, screen, fireEvent, waitFor} from '@testing-library/react';
15
15
  import userEvent from '@testing-library/user-event';
16
16
  import {MagnifyingGlassIcon} from '@heroicons/react/24/outline';
17
17
  import {TextArea} from './TextArea';
18
18
 
19
+ // Mock showPopover/hidePopover since jsdom does not implement them. Used by the
20
+ // disabledMessage tooltip.
21
+ beforeEach(() => {
22
+ HTMLElement.prototype.showPopover = vi.fn(function (this: HTMLElement) {
23
+ this.setAttribute('popover-open', '');
24
+ const event = new Event('toggle', {bubbles: false});
25
+ Object.defineProperty(event, 'newState', {value: 'open'});
26
+ this.dispatchEvent(event);
27
+ });
28
+ HTMLElement.prototype.hidePopover = vi.fn(function (this: HTMLElement) {
29
+ this.removeAttribute('popover-open');
30
+ const event = new Event('toggle', {bubbles: false});
31
+ Object.defineProperty(event, 'newState', {value: 'closed'});
32
+ this.dispatchEvent(event);
33
+ });
34
+ const originalMatches = HTMLElement.prototype.matches;
35
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
+ (HTMLElement.prototype as any).matches = function (
37
+ selector: string,
38
+ ): boolean {
39
+ if (selector === ':popover-open') {
40
+ return this.hasAttribute('popover-open');
41
+ }
42
+ return originalMatches.call(this, selector);
43
+ };
44
+ });
45
+
46
+ // jsdom popover content is in the DOM but may not be "visible" in the
47
+ // accessibility tree. Use hidden: true to find it.
48
+ const h = {hidden: true} as const;
49
+
19
50
  describe('TextArea', () => {
20
51
  it('renders with label', () => {
21
52
  render(<TextArea label="Description" value="" onChange={() => {}} />);
@@ -39,9 +70,7 @@ describe('TextArea', () => {
39
70
  it('calls onChange with value and event when typing', async () => {
40
71
  const user = userEvent.setup();
41
72
  const handleChange = vi.fn();
42
- render(
43
- <TextArea label="Description" value="" onChange={handleChange} />,
44
- );
73
+ render(<TextArea label="Description" value="" onChange={handleChange} />);
45
74
 
46
75
  const textarea = screen.getByRole('textbox');
47
76
  await user.type(textarea, 'Hi');
@@ -73,24 +102,14 @@ describe('TextArea', () => {
73
102
  it('forwards ref correctly', () => {
74
103
  const ref = vi.fn();
75
104
  render(
76
- <TextArea
77
- ref={ref}
78
- label="Description"
79
- value=""
80
- onChange={() => {}}
81
- />,
105
+ <TextArea ref={ref} label="Description" value="" onChange={() => {}} />,
82
106
  );
83
107
  expect(ref).toHaveBeenCalledWith(expect.any(HTMLTextAreaElement));
84
108
  });
85
109
 
86
110
  it('visually hides label when isLabelHidden is true', () => {
87
111
  render(
88
- <TextArea
89
- label="Comments"
90
- isLabelHidden
91
- value=""
92
- onChange={() => {}}
93
- />,
112
+ <TextArea label="Comments" isLabelHidden value="" onChange={() => {}} />,
94
113
  );
95
114
  const label = screen.getByText('Comments');
96
115
  expect(label).toBeInTheDocument();
@@ -133,12 +152,7 @@ describe('TextArea', () => {
133
152
 
134
153
  it('is disabled when isDisabled is true', () => {
135
154
  render(
136
- <TextArea
137
- label="Description"
138
- isDisabled
139
- value=""
140
- onChange={() => {}}
141
- />,
155
+ <TextArea label="Description" isDisabled value="" onChange={() => {}} />,
142
156
  );
143
157
  expect(screen.getByRole('textbox')).toBeDisabled();
144
158
  });
@@ -150,12 +164,7 @@ describe('TextArea', () => {
150
164
 
151
165
  it('shows aria-busy when isLoading is true', () => {
152
166
  render(
153
- <TextArea
154
- label="Description"
155
- isLoading
156
- value=""
157
- onChange={() => {}}
158
- />,
167
+ <TextArea label="Description" isLoading value="" onChange={() => {}} />,
159
168
  );
160
169
  expect(screen.getByRole('textbox')).toHaveAttribute('aria-busy', 'true');
161
170
  expect(screen.getByRole('textbox')).not.toBeDisabled();
@@ -340,12 +349,7 @@ describe('TextArea', () => {
340
349
 
341
350
  it('renders with size="lg"', () => {
342
351
  render(
343
- <TextArea
344
- label="Description"
345
- value=""
346
- onChange={() => {}}
347
- size="lg"
348
- />,
352
+ <TextArea label="Description" value="" onChange={() => {}} size="lg" />,
349
353
  );
350
354
  expect(screen.getByLabelText('Description')).toBeInTheDocument();
351
355
  });
@@ -595,4 +599,132 @@ describe('TextArea', () => {
595
599
  expect(textarea).toHaveFocus();
596
600
  });
597
601
  });
602
+
603
+ describe('disabledMessage', () => {
604
+ it('shows the reason tooltip on hover when disabled with a reason', async () => {
605
+ render(
606
+ <TextArea
607
+ label="Notes"
608
+ value=""
609
+ onChange={() => {}}
610
+ isDisabled
611
+ disabledMessage="You need the Editor role"
612
+ />,
613
+ );
614
+
615
+ const textarea = screen.getByRole('textbox');
616
+ const container = textarea.parentElement as HTMLElement;
617
+ const tooltip = screen.getByRole('tooltip', h);
618
+ expect(tooltip).toHaveTextContent('You need the Editor role');
619
+
620
+ fireEvent.mouseEnter(container);
621
+ await waitFor(() => {
622
+ expect(tooltip).toHaveAttribute('popover-open');
623
+ });
624
+
625
+ fireEvent.mouseLeave(container);
626
+ await waitFor(() => {
627
+ expect(tooltip).not.toHaveAttribute('popover-open');
628
+ });
629
+ });
630
+
631
+ it('shows the reason tooltip on keyboard focus', async () => {
632
+ const user = userEvent.setup();
633
+ render(
634
+ <TextArea
635
+ label="Notes"
636
+ value=""
637
+ onChange={() => {}}
638
+ isDisabled
639
+ disabledMessage="You need the Editor role"
640
+ />,
641
+ );
642
+
643
+ const tooltip = screen.getByRole('tooltip', h);
644
+ await user.tab();
645
+ expect(screen.getByRole('textbox')).toHaveFocus();
646
+ await waitFor(() => {
647
+ expect(tooltip).toHaveAttribute('popover-open');
648
+ });
649
+ });
650
+
651
+ it('does not render a tooltip when not disabled', () => {
652
+ render(
653
+ <TextArea
654
+ label="Notes"
655
+ value=""
656
+ onChange={() => {}}
657
+ disabledMessage="You need the Editor role"
658
+ />,
659
+ );
660
+ expect(screen.queryByRole('tooltip', h)).not.toBeInTheDocument();
661
+ });
662
+
663
+ it('does not render a tooltip when disabled without a reason', () => {
664
+ render(
665
+ <TextArea label="Notes" value="" onChange={() => {}} isDisabled />,
666
+ );
667
+ expect(screen.queryByRole('tooltip', h)).not.toBeInTheDocument();
668
+ });
669
+
670
+ it('keeps the textarea focusable via aria-disabled when a reason is provided', () => {
671
+ render(
672
+ <TextArea
673
+ label="Notes"
674
+ value=""
675
+ onChange={() => {}}
676
+ isDisabled
677
+ disabledMessage="You need the Editor role"
678
+ />,
679
+ );
680
+ const textarea = screen.getByRole('textbox');
681
+ expect(textarea).not.toBeDisabled();
682
+ expect(textarea).toHaveAttribute('aria-disabled', 'true');
683
+ expect(textarea).toHaveAttribute('readonly');
684
+ });
685
+
686
+ it('links the reason tooltip from the textarea via aria-describedby', () => {
687
+ render(
688
+ <TextArea
689
+ label="Notes"
690
+ value=""
691
+ onChange={() => {}}
692
+ isDisabled
693
+ disabledMessage="You need the Editor role"
694
+ />,
695
+ );
696
+ const textarea = screen.getByRole('textbox');
697
+ const tooltip = screen.getByRole('tooltip', h);
698
+ expect(textarea.getAttribute('aria-describedby')).toContain(tooltip.id);
699
+ });
700
+
701
+ it('blocks value changes while focusable-disabled', async () => {
702
+ const user = userEvent.setup();
703
+ const onChange = vi.fn();
704
+ render(
705
+ <TextArea
706
+ label="Notes"
707
+ value=""
708
+ onChange={onChange}
709
+ isDisabled
710
+ disabledMessage="You need the Editor role"
711
+ />,
712
+ );
713
+
714
+ const textarea = screen.getByRole('textbox');
715
+ await user.click(textarea);
716
+ await user.keyboard('hello');
717
+ expect(onChange).not.toHaveBeenCalled();
718
+ expect(textarea).toHaveValue('');
719
+ });
720
+
721
+ it('remains natively disabled when disabled without a reason', () => {
722
+ render(
723
+ <TextArea label="Notes" value="" onChange={() => {}} isDisabled />,
724
+ );
725
+ const textarea = screen.getByRole('textbox');
726
+ expect(textarea).toBeDisabled();
727
+ expect(textarea).not.toHaveAttribute('aria-disabled');
728
+ });
729
+ });
598
730
  });
@@ -43,12 +43,14 @@ import {
43
43
  } from '../Field';
44
44
  import {Icon, renderIconSlot, type IconType} from '../Icon';
45
45
  import {Spinner} from '../Spinner';
46
+ import {useTooltip} from '../Tooltip';
46
47
  import {mergeProps, mergeRefs} from '../utils';
47
48
  import type {BaseProps} from '../BaseProps';
48
49
  import type {SizeValue} from '../utils/types';
49
50
  import {useInputContainer} from '../hooks/useInputContainer';
50
51
  import {useSize} from '../SizeContext/SizeContext';
51
52
  import {themeProps} from '../utils/themeProps';
53
+ import {VisuallyHidden} from '../VisuallyHidden';
52
54
 
53
55
  const COUNTER_WARNING_THRESHOLD = 0.8;
54
56
 
@@ -93,17 +95,6 @@ const styles = stylex.create({
93
95
  counterError: {
94
96
  color: colorVars['--color-error'],
95
97
  },
96
- srOnly: {
97
- position: 'absolute',
98
- width: '1px',
99
- height: '1px',
100
- padding: 0,
101
- margin: '-1px',
102
- overflow: 'hidden',
103
- clip: 'rect(0,0,0,0)',
104
- whiteSpace: 'nowrap',
105
- borderWidth: 0,
106
- },
107
98
  statusIcon: {
108
99
  position: 'absolute',
109
100
  top: spacingVars['--spacing-2'],
@@ -199,6 +190,27 @@ export interface TextAreaProps extends Omit<
199
190
  * @default false
200
191
  */
201
192
  isDisabled?: boolean;
193
+ /**
194
+ * Explains why the textarea is disabled. When set together with
195
+ * `isDisabled`, the textarea shows a tooltip with this text on hover and
196
+ * keyboard focus, and stays focusable (via `aria-disabled`) so the reason is
197
+ * discoverable by keyboard and assistive technology. The field cannot be
198
+ * edited (it becomes read-only) while disabled.
199
+ *
200
+ * Use this instead of wrapping a disabled textarea in `Tooltip` — disabled
201
+ * controls don't emit the pointer events an external tooltip needs.
202
+ *
203
+ * @example
204
+ * ```
205
+ * <TextArea
206
+ * label="Notes"
207
+ * value={notes}
208
+ * isDisabled
209
+ * disabledMessage="Notes are locked after submission"
210
+ * />
211
+ * ```
212
+ */
213
+ disabledMessage?: string;
202
214
  /**
203
215
  * Status indicator for the textarea.
204
216
  * When set, displays a colored border and status icon.
@@ -284,6 +296,7 @@ export function TextArea({
284
296
  placeholder,
285
297
  rows = 3,
286
298
  isDisabled = false,
299
+ disabledMessage,
287
300
  status,
288
301
  labelTooltip,
289
302
  startIcon,
@@ -314,6 +327,20 @@ export function TextArea({
314
327
  const [optimisticValue, setOptimisticValue] = useOptimistic(value);
315
328
  const isBusy = isLoading || optimisticValue !== value;
316
329
 
330
+ // Disabled-reason tooltip. Disabled controls swallow pointer events, so the
331
+ // tooltip listeners attach to the textarea container (which already exists)
332
+ // and the textarea stays perceivable via aria-disabled instead of the native
333
+ // disabled attribute. The field is made read-only so it can't be typed into,
334
+ // and value mutation is blocked by the isDisabled guard in handleChange.
335
+ const showsDisabledMessage = isDisabled && !!disabledMessage;
336
+ const disabledMessageTooltip = useTooltip({
337
+ placement: 'above',
338
+ // The container div is not naturally focusable; focusin bubbles up from
339
+ // the textarea, so always attach focus listeners.
340
+ focusTrigger: 'always',
341
+ isEnabled: showsDisabledMessage,
342
+ });
343
+
317
344
  const statusIconMap: Record<TextAreaStatusType, IconName> = {
318
345
  warning: 'warning',
319
346
  error: 'error',
@@ -334,11 +361,18 @@ export function TextArea({
334
361
  description ? descriptionID : null,
335
362
  status?.message ? statusMessageID : null,
336
363
  maxLength != null ? counterID : null,
364
+ showsDisabledMessage ? disabledMessageTooltip.describedBy : null,
337
365
  ]
338
366
  .filter(Boolean)
339
367
  .join(' ') || undefined;
340
368
 
341
369
  const handleChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
370
+ // Value can't change while showing a disabled message (the field is
371
+ // read-only and non-native-disabled), but guard the handler too so the
372
+ // optimistic value and callbacks never fire.
373
+ if (isDisabled) {
374
+ return;
375
+ }
342
376
  const newValue = e.target.value;
343
377
  onChange?.(newValue, e);
344
378
  if (changeAction && !e.defaultPrevented) {
@@ -381,7 +415,13 @@ export function TextArea({
381
415
  labelTooltip={labelTooltip}
382
416
  width={width}>
383
417
  <div
384
- ref={containerRef}
418
+ ref={el => {
419
+ containerRef.current = el;
420
+ // Anchor + hover/focus listeners for the disabled-message tooltip.
421
+ // Handlers are gated internally by isEnabled, and anchor names
422
+ // compose, so attaching unconditionally is safe.
423
+ disabledMessageTooltip.ref(el);
424
+ }}
385
425
  onClick={handleWrapperClick}
386
426
  onMouseUp={handleWrapperMouseUp}
387
427
  {...mergeProps(
@@ -413,7 +453,12 @@ export function TextArea({
413
453
  onBlur={onBlur}
414
454
  placeholder={placeholder}
415
455
  rows={rows}
416
- disabled={isDisabled}
456
+ // With a disabledMessage the textarea keeps focusability via
457
+ // aria-disabled so the reason is focus-discoverable; readOnly + the
458
+ // handleChange guard keep the value from changing.
459
+ disabled={isDisabled && !showsDisabledMessage}
460
+ aria-disabled={showsDisabledMessage ? 'true' : undefined}
461
+ readOnly={showsDisabledMessage || undefined}
417
462
  spellCheck={hasSpellCheck}
418
463
  autoFocus={hasAutoFocus}
419
464
  data-autofocus={hasAutoFocus || undefined}
@@ -451,15 +496,17 @@ export function TextArea({
451
496
  optimisticValue.length > maxLength && styles.counterError,
452
497
  )}>
453
498
  {optimisticValue.length}/{maxLength}
454
- <span aria-live="polite" {...stylex.props(styles.srOnly)}>
499
+ <VisuallyHidden aria-live="polite">
455
500
  {optimisticValue.length >= maxLength * COUNTER_WARNING_THRESHOLD
456
501
  ? optimisticValue.length > maxLength
457
502
  ? `${optimisticValue.length - maxLength} characters over limit`
458
503
  : `${maxLength - optimisticValue.length} characters remaining`
459
504
  : ''}
460
- </span>
505
+ </VisuallyHidden>
461
506
  </div>
462
507
  )}
508
+ {showsDisabledMessage &&
509
+ disabledMessageTooltip.renderTooltip(disabledMessage)}
463
510
  </Field>
464
511
  );
465
512
  }
@@ -78,6 +78,12 @@ export const docs = {
78
78
  'Disables the input, preventing interaction and dimming the element.',
79
79
  default: 'false',
80
80
  },
81
+ {
82
+ name: 'disabledMessage',
83
+ type: 'string',
84
+ description:
85
+ 'Explains why the input is disabled. With isDisabled, shows a tooltip on hover/keyboard focus and keeps the input focusable via aria-disabled (the field becomes read-only). Use this instead of wrapping a disabled TextInput in Tooltip. Disabled controls swallow the hover events an external Tooltip needs.',
86
+ },
81
87
  {
82
88
  name: 'isLoading',
83
89
  type: 'boolean',
@@ -144,6 +150,7 @@ export const docs = {
144
150
  {guidance: false, description: "Don't use placeholder text as a replacement for a label; placeholders disappear on focus and are not reliably read by screen readers."},
145
151
  {guidance: false, description: "Don't use TextInput for multi-line content like comments or descriptions; use TextArea instead."},
146
152
  {guidance: false, description: "Don't mark every field as required; only flag mandatory fields so users are not overwhelmed by validation errors."},
153
+ {guidance: false, description: "Don't wrap a disabled TextInput in Tooltip to explain why it's disabled; disabled controls swallow the hover events the wrapper needs. Use the disabledMessage prop instead."},
147
154
  ],
148
155
  anatomy: [
149
156
  {name: 'Label', required: true, description: 'Text that identifies the field. Always rendered for accessibility even when visually hidden.'},
@@ -231,6 +238,12 @@ export const docsZh = {
231
238
  '禁用输入框,阻止交互并使元素变暗。',
232
239
  default: 'false',
233
240
  },
241
+ {
242
+ name: 'disabledMessage',
243
+ type: 'string',
244
+ description:
245
+ '说明输入框被禁用的原因。与 isDisabled 一起使用时,在悬停/键盘聚焦时显示工具提示,并通过 aria-disabled 保持输入框可聚焦(字段变为只读)。请使用此属性,而不是用 Tooltip 包裹已禁用的 TextInput——已禁用的控件会吞掉外部 Tooltip 所需的悬停事件。',
246
+ },
234
247
  {
235
248
  name: 'isLoading',
236
249
  type: 'boolean',
@@ -296,6 +309,7 @@ export const docsZh = {
296
309
  {guidance: false, description: "Don't use placeholder text as a replacement for a label; placeholders disappear on focus and are not reliably read by screen readers."},
297
310
  {guidance: false, description: "Don't use TextInput for multi-line content like comments or descriptions; use TextArea instead."},
298
311
  {guidance: false, description: "Don't mark every field as required; only flag mandatory fields so users are not overwhelmed by validation errors."},
312
+ {guidance: false, description: "Don't wrap a disabled TextInput in Tooltip to explain why it's disabled; disabled controls swallow the hover events the wrapper needs. Use the disabledMessage prop instead."},
299
313
  ],
300
314
  anatomy: [
301
315
  {name: 'Label', required: true, description: 'Text that identifies the field. Always rendered for accessibility even when visually hidden.'},
@@ -323,6 +337,7 @@ export const docsDense = {
323
337
  {guidance: false, description: "Don't use placeholder text as a replacement for a label; placeholders disappear on focus and are not reliably read by screen readers."},
324
338
  {guidance: false, description: "Don't use TextInput for multi-line content like comments or descriptions; use TextArea instead."},
325
339
  {guidance: false, description: "Don't mark every field as required; only flag mandatory fields so users are not overwhelmed by validation errors."},
340
+ {guidance: false, description: "Don't wrap a disabled TextInput in Tooltip to explain why it's disabled; disabled controls swallow the hover events the wrapper needs. Use the disabledMessage prop instead."},
326
341
  ],
327
342
  anatomy: [
328
343
  {name: 'Label', required: true, description: 'Text that identifies the field. Always rendered for accessibility even when visually hidden.'},
@@ -346,6 +361,8 @@ export const docsDense = {
346
361
  isOptional: 'Shows "Optional" indicator. Mutually exclusive w/ isRequired.',
347
362
  isRequired: 'Shows "Required" indicator+sets aria-required. Mutually exclusive w/ isOptional.',
348
363
  isDisabled: 'Disables input, prevents interaction, dims element.',
364
+ disabledMessage:
365
+ 'Explains why input is disabled. With isDisabled, shows tooltip on hover/focus + keeps input focusable via aria-disabled (field becomes read-only). Use instead of wrapping a disabled TextInput in Tooltip.',
349
366
  isLoading: 'Loading state w/ spinner+aria-busy.',
350
367
  placeholder: 'Placeholder when input empty.',
351
368
  labelTooltip: 'Tooltip in info icon at label end.',