@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
@@ -95,6 +95,12 @@ export const docs = {
95
95
  description: 'Whether the slider is disabled.',
96
96
  default: 'false',
97
97
  },
98
+ {
99
+ name: 'disabledMessage',
100
+ type: 'string',
101
+ description:
102
+ 'Explains why the slider is disabled. With isDisabled, shows a tooltip on hover/keyboard focus and keeps the thumb focusable via aria-disabled (value changes stay blocked). Use this instead of wrapping a disabled Slider in Tooltip — disabled controls swallow the hover events an external Tooltip needs.',
103
+ },
98
104
  {
99
105
  name: 'isOptional',
100
106
  type: 'boolean',
@@ -151,6 +157,7 @@ export const docs = {
151
157
  {guidance: true, description: 'Format values with meaningful units like "$50" or "75%" instead of raw numbers.'},
152
158
  {guidance: false, description: 'Use for precise numeric entry; pair with a text input or use NumberInput instead.'},
153
159
  {guidance: false, description: 'Set a step size so large that only a few positions are possible; use SegmentedControl or radio buttons instead.'},
160
+ {guidance: false, description: 'Wrap a disabled slider in Tooltip to explain why it is disabled; disabled controls swallow the hover events the wrapper needs. Use the disabledMessage prop instead.'},
154
161
  ],
155
162
  },
156
163
  };
@@ -237,6 +244,12 @@ export const docsZh = {
237
244
  description: '是否禁用滑块。',
238
245
  default: 'false',
239
246
  },
247
+ {
248
+ name: 'disabledMessage',
249
+ type: 'string',
250
+ description:
251
+ 'Explains why the slider is disabled. With isDisabled, shows a tooltip on hover/keyboard focus and keeps the thumb focusable via aria-disabled (value changes stay blocked). Use this instead of wrapping a disabled Slider in Tooltip — disabled controls swallow the hover events an external Tooltip needs.',
252
+ },
240
253
  {
241
254
  name: 'isOptional',
242
255
  type: 'boolean',
@@ -293,6 +306,7 @@ export const docsZh = {
293
306
  {guidance: true, description: 'Format values with meaningful units like "$50" or "75%" instead of raw numbers.'},
294
307
  {guidance: false, description: 'Use for precise numeric entry; pair with a text input or use NumberInput instead.'},
295
308
  {guidance: false, description: 'Set a step size so large that only a few positions are possible; use SegmentedControl or radio buttons instead.'},
309
+ {guidance: false, description: 'Wrap a disabled slider in Tooltip to explain why it is disabled; disabled controls swallow the hover events the wrapper needs. Use the disabledMessage prop instead.'},
296
310
  ],
297
311
  },
298
312
  };
@@ -307,6 +321,7 @@ export const docsDense = {
307
321
  {guidance: true, description: 'Format values with meaningful units like "$50" or "75%" instead of raw numbers.'},
308
322
  {guidance: false, description: 'Use for precise numeric entry; pair with a text input or use NumberInput instead.'},
309
323
  {guidance: false, description: 'Set a step size so large that only a few positions are possible; use SegmentedControl or radio buttons instead.'},
324
+ {guidance: false, description: 'Wrap a disabled slider in Tooltip to explain why it is disabled; disabled controls swallow the hover events the wrapper needs. Use the disabledMessage prop instead.'},
310
325
  ],
311
326
  },
312
327
  propDescriptions: {
@@ -9,11 +9,44 @@
9
9
  * SYNC: When Slider.tsx changes, update tests to match new behavior
10
10
  */
11
11
 
12
- import {describe, it, expect, vi} from 'vitest';
13
- import {render, screen, act, fireEvent} from '@testing-library/react';
12
+ import {describe, it, expect, vi, beforeEach} from 'vitest';
13
+ import {render, screen, act, fireEvent, waitFor} from '@testing-library/react';
14
14
  import userEvent from '@testing-library/user-event';
15
15
  import {Slider} from './Slider';
16
16
 
17
+ // Mock showPopover/hidePopover (not implemented in jsdom) so the tooltip layer
18
+ // reflects its open state via a `popover-open` attribute the tests can assert.
19
+ beforeEach(() => {
20
+ HTMLElement.prototype.showPopover = vi.fn(function (this: HTMLElement) {
21
+ this.setAttribute('popover-open', '');
22
+ const event = new Event('toggle', {bubbles: false});
23
+ Object.defineProperty(event, 'newState', {value: 'open'});
24
+ this.dispatchEvent(event);
25
+ });
26
+ HTMLElement.prototype.hidePopover = vi.fn(function (this: HTMLElement) {
27
+ this.removeAttribute('popover-open');
28
+ const event = new Event('toggle', {bubbles: false});
29
+ Object.defineProperty(event, 'newState', {value: 'closed'});
30
+ this.dispatchEvent(event);
31
+ });
32
+ const originalMatches = HTMLElement.prototype.matches;
33
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
34
+ (HTMLElement.prototype as any).matches = function (
35
+ selector: string,
36
+ ): boolean {
37
+ if (selector === ':popover-open') {
38
+ return this.hasAttribute('popover-open');
39
+ }
40
+ // jsdom does not derive :focus-visible from keyboard focus for a
41
+ // div[role="slider"] thumb; treat the focused thumb as focus-visible so the
42
+ // disabled-reason tooltip's keyboard-focus path can be exercised.
43
+ if (selector === ':focus-visible') {
44
+ return this === document.activeElement;
45
+ }
46
+ return originalMatches.call(this, selector);
47
+ };
48
+ });
49
+
17
50
  describe('Slider', () => {
18
51
  // --- Aria labels ---
19
52
 
@@ -382,4 +415,124 @@ describe('Slider', () => {
382
415
  await user.keyboard('{ArrowLeft}');
383
416
  expect(handleChange).toHaveBeenCalledWith(0);
384
417
  });
418
+
419
+ describe('disabledMessage', () => {
420
+ const h = {hidden: true} as const;
421
+
422
+ function getTrack(): HTMLElement {
423
+ return screen.getByRole('slider').parentElement!;
424
+ }
425
+
426
+ it('shows the reason tooltip on hover when disabled with a reason', async () => {
427
+ render(
428
+ <Slider
429
+ label="Volume"
430
+ value={50}
431
+ valueDisplay="none"
432
+ isDisabled
433
+ disabledMessage="Volume is locked while sharing your screen"
434
+ />,
435
+ );
436
+ const tooltip = screen.getByRole('tooltip', h);
437
+ expect(tooltip).toHaveTextContent(
438
+ 'Volume is locked while sharing your screen',
439
+ );
440
+ fireEvent.mouseEnter(getTrack());
441
+ await waitFor(() => expect(tooltip).toHaveAttribute('popover-open'));
442
+ fireEvent.mouseLeave(getTrack());
443
+ await waitFor(() => expect(tooltip).not.toHaveAttribute('popover-open'));
444
+ });
445
+
446
+ it('shows the reason tooltip on keyboard focus', async () => {
447
+ const user = userEvent.setup();
448
+ render(
449
+ <Slider
450
+ label="Volume"
451
+ value={50}
452
+ valueDisplay="none"
453
+ isDisabled
454
+ disabledMessage="Volume is locked while sharing your screen"
455
+ />,
456
+ );
457
+ const tooltip = screen.getByRole('tooltip', h);
458
+ await user.tab();
459
+ expect(screen.getByRole('slider')).toHaveFocus();
460
+ await waitFor(() => expect(tooltip).toHaveAttribute('popover-open'));
461
+ });
462
+
463
+ it('does not render a tooltip when not disabled', () => {
464
+ render(
465
+ <Slider
466
+ label="Volume"
467
+ value={50}
468
+ valueDisplay="none"
469
+ disabledMessage="Volume is locked while sharing your screen"
470
+ />,
471
+ );
472
+ expect(screen.queryByRole('tooltip', h)).not.toBeInTheDocument();
473
+ });
474
+
475
+ it('does not render a tooltip when disabled without a reason', () => {
476
+ render(
477
+ <Slider label="Volume" value={50} valueDisplay="none" isDisabled />,
478
+ );
479
+ expect(screen.queryByRole('tooltip', h)).not.toBeInTheDocument();
480
+ });
481
+
482
+ it('keeps the thumb focusable via aria-disabled when a reason is provided', () => {
483
+ render(
484
+ <Slider
485
+ label="Volume"
486
+ value={50}
487
+ valueDisplay="none"
488
+ isDisabled
489
+ disabledMessage="Volume is locked while sharing your screen"
490
+ />,
491
+ );
492
+ const thumb = screen.getByRole('slider');
493
+ expect(thumb).toHaveAttribute('aria-disabled', 'true');
494
+ expect(thumb).toHaveAttribute('tabindex', '0');
495
+ });
496
+
497
+ it('links the reason tooltip via aria-describedby', () => {
498
+ render(
499
+ <Slider
500
+ label="Volume"
501
+ value={50}
502
+ valueDisplay="none"
503
+ isDisabled
504
+ disabledMessage="Volume is locked while sharing your screen"
505
+ />,
506
+ );
507
+ const thumb = screen.getByRole('slider');
508
+ const tooltip = screen.getByRole('tooltip', h);
509
+ expect(thumb.getAttribute('aria-describedby')).toContain(tooltip.id);
510
+ });
511
+
512
+ it('blocks value changes while focusable-disabled', async () => {
513
+ const user = userEvent.setup();
514
+ const onChange = vi.fn();
515
+ render(
516
+ <Slider
517
+ label="Volume"
518
+ value={50}
519
+ valueDisplay="none"
520
+ onChange={onChange}
521
+ isDisabled
522
+ disabledMessage="Volume is locked while sharing your screen"
523
+ />,
524
+ );
525
+ const thumb = screen.getByRole('slider');
526
+ thumb.focus();
527
+ await user.keyboard('{ArrowRight}');
528
+ expect(onChange).not.toHaveBeenCalled();
529
+ });
530
+
531
+ it('remains non-focusable when disabled without a reason', () => {
532
+ render(
533
+ <Slider label="Volume" value={50} valueDisplay="none" isDisabled />,
534
+ );
535
+ expect(screen.getByRole('slider')).toHaveAttribute('tabindex', '-1');
536
+ });
537
+ });
385
538
  });
@@ -4,7 +4,7 @@
4
4
 
5
5
  /**
6
6
  * @file Slider.tsx
7
- * @input Uses React, useId, useRef, useCallback, Field, Tooltip
7
+ * @input Uses React, useId, useRef, useCallback, Field, Tooltip, useTooltip
8
8
  * @output Exports Slider component, SliderProps, SliderSingleProps, SliderRangeProps, SliderBaseProps
9
9
  * @position Core implementation; consumed by index.ts, tested by Slider.test.tsx
10
10
  *
@@ -37,6 +37,7 @@ import {
37
37
  } from '../theme/tokens.stylex';
38
38
  import {Field} from '../Field/Field';
39
39
  import {Tooltip} from '../Tooltip/Tooltip';
40
+ import {useTooltip} from '../Tooltip';
40
41
  import type {InputStatus} from '../Field/types';
41
42
  import {mergeProps, mergeRefs} from '../utils';
42
43
  import type {BaseProps} from '../BaseProps';
@@ -61,6 +62,27 @@ export interface SliderBaseProps extends Omit<
61
62
  description?: string;
62
63
  /** Whether the slider is disabled. @default false */
63
64
  isDisabled?: boolean;
65
+ /**
66
+ * Explains why the slider is disabled. When set together with `isDisabled`,
67
+ * the slider shows a tooltip with this text on hover and keyboard focus, and
68
+ * the thumb stays focusable (via `aria-disabled`) so the reason is
69
+ * discoverable by keyboard and assistive technology. Value changes stay
70
+ * blocked.
71
+ *
72
+ * Use this instead of wrapping a disabled slider in `Tooltip` — disabled
73
+ * controls don't emit the pointer events an external tooltip needs.
74
+ *
75
+ * @example
76
+ * ```
77
+ * <Slider
78
+ * label="Volume"
79
+ * value={50}
80
+ * isDisabled
81
+ * disabledMessage="Volume is locked while sharing your screen"
82
+ * />
83
+ * ```
84
+ */
85
+ disabledMessage?: string;
64
86
  /** Whether the field is optional. @default false */
65
87
  isOptional?: boolean;
66
88
  /** Whether the field is required. @default false */
@@ -331,6 +353,7 @@ export function Slider({ref, ...props}: SliderProps) {
331
353
  isLabelHidden = false,
332
354
  description,
333
355
  isDisabled = false,
356
+ disabledMessage,
334
357
  isOptional = false,
335
358
  isRequired = false,
336
359
  status,
@@ -368,6 +391,20 @@ export function Slider({ref, ...props}: SliderProps) {
368
391
  const draggingThumbRef = useRef<number | null>(null);
369
392
  const [draggingThumb, setDraggingThumb] = useState<number | null>(null);
370
393
 
394
+ // Disabled-reason tooltip. This is a *separate* useTooltip instance from the
395
+ // per-thumb value bubble (the `<Tooltip>` component below): it anchors to the
396
+ // track container and fires on hover/focus of the whole control. Disabled
397
+ // controls swallow pointer events, so the thumb stays perceivable via
398
+ // aria-disabled while pointer/keyboard handlers early-return on isDisabled.
399
+ const showsDisabledMessage = isDisabled && !!disabledMessage;
400
+ const disabledMessageTooltip = useTooltip({
401
+ placement: 'above',
402
+ // The track container is not naturally focusable; focusin bubbles up from
403
+ // the thumb, so always attach focus listeners.
404
+ focusTrigger: 'always',
405
+ isEnabled: showsDisabledMessage,
406
+ });
407
+
371
408
  // Build aria-describedby
372
409
  const describedByParts: string[] = [];
373
410
  if (description) {
@@ -376,6 +413,9 @@ export function Slider({ref, ...props}: SliderProps) {
376
413
  if (status?.message) {
377
414
  describedByParts.push(statusMessageID);
378
415
  }
416
+ if (showsDisabledMessage) {
417
+ describedByParts.push(disabledMessageTooltip.describedBy);
418
+ }
379
419
  const ariaDescribedBy =
380
420
  describedByParts.length > 0 ? describedByParts.join(' ') : undefined;
381
421
 
@@ -641,7 +681,10 @@ export function Slider({ref, ...props}: SliderProps) {
641
681
  : `${label}, maximum value`
642
682
  : label;
643
683
 
644
- const useTooltip = valueDisplay === 'tooltip';
684
+ // Suppress the per-thumb value bubble while the disabled-message tooltip is
685
+ // showing, so a disabled slider surfaces the *reason* on hover/focus rather
686
+ // than stacking two tooltips over the same thumb.
687
+ const useValueTooltip = valueDisplay === 'tooltip' && !showsDisabledMessage;
645
688
  const tooltipPlacement = isHorizontal ? 'above' : 'start';
646
689
 
647
690
  const thumbElement = (
@@ -649,7 +692,10 @@ export function Slider({ref, ...props}: SliderProps) {
649
692
  key={thumbIndex}
650
693
  id={!isRange ? id : undefined}
651
694
  role="slider"
652
- tabIndex={isDisabled ? -1 : 0}
695
+ // With a disabledMessage the thumb keeps focusability so the reason is
696
+ // focus-discoverable; value changes stay blocked by the isDisabled
697
+ // guards in the pointer/keyboard handlers.
698
+ tabIndex={isDisabled && !showsDisabledMessage ? -1 : 0}
653
699
  aria-valuemin={min}
654
700
  aria-valuemax={max}
655
701
  aria-valuenow={val}
@@ -678,7 +724,7 @@ export function Slider({ref, ...props}: SliderProps) {
678
724
  />
679
725
  );
680
726
 
681
- if (useTooltip) {
727
+ if (useValueTooltip) {
682
728
  return (
683
729
  <Tooltip
684
730
  key={thumbIndex}
@@ -758,7 +804,7 @@ export function Slider({ref, ...props}: SliderProps) {
758
804
  stylex.props(styles.sliderRow),
759
805
  )}>
760
806
  <div
761
- ref={mergeRefs(ref, trackRef)}
807
+ ref={mergeRefs(ref, trackRef, disabledMessageTooltip.ref)}
762
808
  {...(isRange ? {role: 'group', 'aria-label': label} : undefined)}
763
809
  onPointerDown={handlePointerDown}
764
810
  onPointerMove={handlePointerMove}
@@ -855,6 +901,8 @@ export function Slider({ref, ...props}: SliderProps) {
855
901
 
856
902
  {textDisplay}
857
903
  </div>
904
+ {showsDisabledMessage &&
905
+ disabledMessageTooltip.renderTooltip(disabledMessage)}
858
906
  </Field>
859
907
  );
860
908
  }
@@ -70,7 +70,13 @@ const styles = stylex.create({
70
70
  canvas: {
71
71
  backfaceVisibility: 'hidden',
72
72
  display: 'block',
73
- animationDuration: durationVars['--duration-slow-min'],
73
+ // Slow the rotation dramatically under reduced-motion rather than freezing
74
+ // it (a frozen spinner reads as broken), matching ProgressBar's approach.
75
+ // The role="status" + "Loading" label still convey busy state (obs-6).
76
+ animationDuration: {
77
+ default: durationVars['--duration-slow-min'],
78
+ '@media (prefers-reduced-motion: reduce)': '3s',
79
+ },
74
80
  animationIterationCount: 'infinite',
75
81
  animationName: rotation,
76
82
  animationTimingFunction: 'linear',
@@ -28,6 +28,31 @@ export const docs = {
28
28
  description:
29
29
  'Spacing step (number literal): 0, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8, 10. Pass as a JSX number expression e.g. gap={4}, NOT a string like gap="4".',
30
30
  },
31
+ {
32
+ name: 'padding',
33
+ type: 'SpacingStep',
34
+ description:
35
+ 'Inner padding on all sides, using the spacing scale (0, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8, 10). Matches the padding prop on Card, LayoutContent, and LayoutPanel. Pass as a JSX number expression e.g. padding={3}.',
36
+ },
37
+ {
38
+ name: 'paddingInline',
39
+ type: 'SpacingStep',
40
+ description:
41
+ 'Inline (horizontal) padding, using the spacing scale. Overrides padding on the inline axis when both are set.',
42
+ },
43
+ {
44
+ name: 'paddingBlock',
45
+ type: 'SpacingStep',
46
+ description:
47
+ 'Block (vertical) padding, using the spacing scale. Overrides padding on the block axis when both are set.',
48
+ },
49
+ {
50
+ name: 'isScrollable',
51
+ type: 'boolean',
52
+ description:
53
+ 'Enables scrollable overflow (overflow: auto). Matches isScrollable on LayoutContent and LayoutPanel.',
54
+ default: 'false',
55
+ },
31
56
  {
32
57
  name: 'width',
33
58
  type: 'SizeValue',
@@ -38,6 +63,16 @@ export const docs = {
38
63
  type: 'SizeValue',
39
64
  description: "Height of the stack container. Numbers are treated as pixels, strings are used as-is (e.g., '100%').",
40
65
  },
66
+ {
67
+ name: 'maxWidth',
68
+ type: 'SizeValue',
69
+ description: "Maximum width of the stack container. Numbers are treated as pixels, strings are used as-is (e.g., '100%').",
70
+ },
71
+ {
72
+ name: 'minHeight',
73
+ type: 'SizeValue',
74
+ description: "Minimum height of the stack container. Numbers are treated as pixels, strings are used as-is (e.g., '100%').",
75
+ },
41
76
  {
42
77
  name: 'hAlign',
43
78
  type: "'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'",
@@ -96,6 +131,31 @@ export const docs = {
96
131
  description:
97
132
  'Spacing step (number literal): 0, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8, 10. Pass as a JSX number expression e.g. gap={4}, NOT a string like gap="4".',
98
133
  },
134
+ {
135
+ name: 'padding',
136
+ type: 'SpacingStep',
137
+ description:
138
+ 'Inner padding on all sides, using the spacing scale (0, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8, 10). Matches the padding prop on Card, LayoutContent, and LayoutPanel. Pass as a JSX number expression e.g. padding={3}.',
139
+ },
140
+ {
141
+ name: 'paddingInline',
142
+ type: 'SpacingStep',
143
+ description:
144
+ 'Inline (horizontal) padding, using the spacing scale. Overrides padding on the inline axis when both are set.',
145
+ },
146
+ {
147
+ name: 'paddingBlock',
148
+ type: 'SpacingStep',
149
+ description:
150
+ 'Block (vertical) padding, using the spacing scale. Overrides padding on the block axis when both are set.',
151
+ },
152
+ {
153
+ name: 'isScrollable',
154
+ type: 'boolean',
155
+ description:
156
+ 'Enables scrollable overflow (overflow: auto). Matches isScrollable on LayoutContent and LayoutPanel.',
157
+ default: 'false',
158
+ },
99
159
  {
100
160
  name: 'width',
101
161
  type: 'SizeValue',
@@ -106,6 +166,16 @@ export const docs = {
106
166
  type: 'SizeValue',
107
167
  description: "Height of the stack container. Numbers are treated as pixels, strings are used as-is (e.g., '100%').",
108
168
  },
169
+ {
170
+ name: 'maxWidth',
171
+ type: 'SizeValue',
172
+ description: "Maximum width of the stack container. Numbers are treated as pixels, strings are used as-is (e.g., '100%').",
173
+ },
174
+ {
175
+ name: 'minHeight',
176
+ type: 'SizeValue',
177
+ description: "Minimum height of the stack container. Numbers are treated as pixels, strings are used as-is (e.g., '100%').",
178
+ },
109
179
  {
110
180
  name: 'hAlign',
111
181
  type: "'start' | 'center' | 'end' | 'stretch'",
@@ -160,6 +230,13 @@ export const docs = {
160
230
  'Flex grow behavior: static keeps natural size, fill expands to consume remaining space.',
161
231
  default: "'static'",
162
232
  },
233
+ {
234
+ name: 'isScrollable',
235
+ type: 'boolean',
236
+ description:
237
+ 'Enables scrollable overflow (overflow: auto). StackItem already applies the flex min-height/min-width reset, so <StackItem size="fill" isScrollable> is a complete scroll region. Matches isScrollable on LayoutContent and LayoutPanel.',
238
+ default: 'false',
239
+ },
163
240
  {
164
241
  name: 'crossAlignSelf',
165
242
  type: "'start' | 'center' | 'end' | 'stretch'",
@@ -253,15 +253,65 @@ describe('Stack', () => {
253
253
 
254
254
  it('applies both width and height together', () => {
255
255
  render(
256
- <Stack
257
- direction="vertical"
258
- width={400}
259
- height="100%"
260
- data-testid="stack">
256
+ <Stack direction="vertical" width={400} height="100%" data-testid="stack">
261
257
  <div>Item</div>
262
258
  </Stack>,
263
259
  );
264
260
  const el = screen.getByTestId('stack');
265
261
  expect(el).toHaveStyle({width: '400px', height: '100%'});
266
262
  });
263
+
264
+ it('applies a class when padding is set', () => {
265
+ render(
266
+ <Stack padding={3} data-testid="stack">
267
+ <div>Item</div>
268
+ </Stack>,
269
+ );
270
+ expect(screen.getByTestId('stack').className).not.toBe('');
271
+ });
272
+
273
+ it('accepts paddingInline and paddingBlock without error', () => {
274
+ render(
275
+ <Stack paddingInline={4} paddingBlock={2} data-testid="stack">
276
+ <div>Item</div>
277
+ </Stack>,
278
+ );
279
+ expect(screen.getByTestId('stack')).toBeInTheDocument();
280
+ });
281
+
282
+ it('lets paddingInline/paddingBlock override padding on their axis', () => {
283
+ // padding sets both axes; paddingInline overrides the inline axis. The
284
+ // component should render without conflict and carry a class.
285
+ render(
286
+ <Stack padding={2} paddingInline={5} data-testid="stack">
287
+ <div>Item</div>
288
+ </Stack>,
289
+ );
290
+ expect(screen.getByTestId('stack').className).not.toBe('');
291
+ });
292
+
293
+ it('applies a class when isScrollable is set', () => {
294
+ render(
295
+ <Stack isScrollable data-testid="stack">
296
+ <div>Item</div>
297
+ </Stack>,
298
+ );
299
+ expect(screen.getByTestId('stack').className).not.toBe('');
300
+ });
301
+
302
+ it('does not set overflow class when isScrollable is false', () => {
303
+ const {rerender} = render(
304
+ <Stack data-testid="stack">
305
+ <div>Item</div>
306
+ </Stack>,
307
+ );
308
+ const withoutScroll = screen.getByTestId('stack').className;
309
+ rerender(
310
+ <Stack isScrollable data-testid="stack">
311
+ <div>Item</div>
312
+ </Stack>,
313
+ );
314
+ const withScroll = screen.getByTestId('stack').className;
315
+ expect(withScroll).not.toBe(withoutScroll);
316
+ });
267
317
  });