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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (567) hide show
  1. package/CHANGELOG.md +165 -0
  2. package/README.md +12 -12
  3. package/dist/Avatar/Avatar.d.ts.map +1 -1
  4. package/dist/Avatar/Avatar.js +11 -5
  5. package/dist/Breadcrumbs/BreadcrumbItem.d.ts +1 -1
  6. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  7. package/dist/Breadcrumbs/BreadcrumbItem.js +24 -5
  8. package/dist/Button/Button.d.ts.map +1 -1
  9. package/dist/Button/Button.js +2 -4
  10. package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
  11. package/dist/ButtonGroup/ButtonGroup.js +0 -1
  12. package/dist/Calendar/Calendar.d.ts +5 -4
  13. package/dist/Calendar/Calendar.d.ts.map +1 -1
  14. package/dist/Calendar/Calendar.js +82 -43
  15. package/dist/Calendar/hooks/index.d.ts +0 -2
  16. package/dist/Calendar/hooks/index.d.ts.map +1 -1
  17. package/dist/Calendar/hooks/index.js +1 -2
  18. package/dist/Calendar/index.d.ts +3 -3
  19. package/dist/Calendar/index.d.ts.map +1 -1
  20. package/dist/Calendar/index.js +1 -1
  21. package/dist/Calendar/styles.d.ts +3 -9
  22. package/dist/Calendar/styles.d.ts.map +1 -1
  23. package/dist/Calendar/styles.js +3 -11
  24. package/dist/Carousel/Carousel.d.ts.map +1 -1
  25. package/dist/Carousel/Carousel.js +17 -3
  26. package/dist/Center/Center.d.ts +11 -1
  27. package/dist/Center/Center.d.ts.map +1 -1
  28. package/dist/Center/Center.js +9 -3
  29. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  30. package/dist/Chat/ChatComposerInput.js +0 -1
  31. package/dist/Chat/ChatMessageList.d.ts +14 -1
  32. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  33. package/dist/Chat/ChatMessageList.js +2 -0
  34. package/dist/Chat/useTriggerMenu.d.ts +8 -1
  35. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  36. package/dist/Chat/useTriggerMenu.js +15 -3
  37. package/dist/CheckboxInput/CheckboxInput.d.ts +23 -2
  38. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  39. package/dist/CheckboxInput/CheckboxInput.js +51 -9
  40. package/dist/CheckboxList/CheckboxList.d.ts +13 -1
  41. package/dist/CheckboxList/CheckboxList.d.ts.map +1 -1
  42. package/dist/CheckboxList/CheckboxList.js +39 -9
  43. package/dist/CheckboxList/CheckboxListContext.d.ts +7 -0
  44. package/dist/CheckboxList/CheckboxListContext.d.ts.map +1 -1
  45. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  46. package/dist/CheckboxList/CheckboxListItem.js +0 -1
  47. package/dist/Citation/Citation.d.ts.map +1 -1
  48. package/dist/Citation/Citation.js +9 -5
  49. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  50. package/dist/CodeBlock/CodeBlock.js +51 -37
  51. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  52. package/dist/CommandPalette/CommandPalette.js +5 -5
  53. package/dist/ContextMenu/ContextMenu.d.ts +4 -5
  54. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  55. package/dist/ContextMenu/ContextMenu.js +93 -11
  56. package/dist/DateInput/DateInput.d.ts +23 -1
  57. package/dist/DateInput/DateInput.d.ts.map +1 -1
  58. package/dist/DateInput/DateInput.js +167 -99
  59. package/dist/DateRangeInput/DateRangeInput.d.ts +23 -1
  60. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  61. package/dist/DateRangeInput/DateRangeInput.js +42 -9
  62. package/dist/DateTimeInput/DateTimeInput.d.ts +35 -2
  63. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  64. package/dist/DateTimeInput/DateTimeInput.js +78 -15
  65. package/dist/Dialog/Dialog.d.ts.map +1 -1
  66. package/dist/Dialog/Dialog.js +12 -0
  67. package/dist/DropdownMenu/DropdownMenu.d.ts +1 -8
  68. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  69. package/dist/DropdownMenu/DropdownMenu.js +42 -14
  70. package/dist/Field/Field.d.ts +19 -2
  71. package/dist/Field/Field.d.ts.map +1 -1
  72. package/dist/Field/Field.js +4 -0
  73. package/dist/Field/FieldLabel.d.ts +21 -2
  74. package/dist/Field/FieldLabel.d.ts.map +1 -1
  75. package/dist/Field/FieldLabel.js +41 -26
  76. package/dist/FileInput/FileInput.d.ts +22 -1
  77. package/dist/FileInput/FileInput.d.ts.map +1 -1
  78. package/dist/FileInput/FileInput.js +56 -10
  79. package/dist/Grid/Grid.d.ts +11 -1
  80. package/dist/Grid/Grid.d.ts.map +1 -1
  81. package/dist/Grid/Grid.js +32 -6
  82. package/dist/InputGroup/InputGroup.d.ts +4 -3
  83. package/dist/InputGroup/InputGroup.d.ts.map +1 -1
  84. package/dist/InputGroup/InputGroup.js +16 -6
  85. package/dist/InputGroup/InputGroupContext.d.ts +4 -0
  86. package/dist/InputGroup/InputGroupContext.d.ts.map +1 -1
  87. package/dist/InputGroup/InputGroupContext.js +2 -2
  88. package/dist/InputGroup/groupStyles.d.ts +1 -1
  89. package/dist/InputGroup/groupStyles.d.ts.map +1 -1
  90. package/dist/InputGroup/groupStyles.js +3 -3
  91. package/dist/InputGroup/index.d.ts +1 -0
  92. package/dist/InputGroup/index.d.ts.map +1 -1
  93. package/dist/Kbd/Kbd.d.ts.map +1 -1
  94. package/dist/Kbd/Kbd.js +33 -1
  95. package/dist/Layer/layerAnimations.stylex.d.ts +4 -0
  96. package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
  97. package/dist/Layer/layerAnimations.stylex.js +8 -4
  98. package/dist/Layer/useLayer.d.ts +10 -0
  99. package/dist/Layer/useLayer.d.ts.map +1 -1
  100. package/dist/Layer/useLayer.js +64 -9
  101. package/dist/Layout/Layout.d.ts +4 -11
  102. package/dist/Layout/Layout.d.ts.map +1 -1
  103. package/dist/Layout/Layout.js +10 -11
  104. package/dist/Layout/LayoutFooter.d.ts +2 -2
  105. package/dist/Layout/LayoutFooter.d.ts.map +1 -1
  106. package/dist/Layout/LayoutHeader.d.ts +2 -2
  107. package/dist/Layout/LayoutHeader.d.ts.map +1 -1
  108. package/dist/Layout/LayoutPanel.d.ts +2 -2
  109. package/dist/Layout/LayoutPanel.d.ts.map +1 -1
  110. package/dist/Layout/padding.stylex.d.ts +51 -0
  111. package/dist/Layout/padding.stylex.d.ts.map +1 -1
  112. package/dist/Layout/padding.stylex.js +63 -0
  113. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  114. package/dist/Lightbox/Lightbox.js +4 -2
  115. package/dist/Link/Link.d.ts +16 -1
  116. package/dist/Link/Link.d.ts.map +1 -1
  117. package/dist/Link/Link.js +18 -7
  118. package/dist/Markdown/Markdown.d.ts.map +1 -1
  119. package/dist/Markdown/Markdown.js +7 -0
  120. package/dist/MoreMenu/MoreMenu.d.ts +1 -7
  121. package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
  122. package/dist/MoreMenu/MoreMenu.js +0 -2
  123. package/dist/MultiSelector/MultiSelector.d.ts +27 -2
  124. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  125. package/dist/MultiSelector/MultiSelector.js +141 -42
  126. package/dist/MultiSelector/hooks.d.ts +12 -1
  127. package/dist/MultiSelector/hooks.d.ts.map +1 -1
  128. package/dist/MultiSelector/hooks.js +14 -1
  129. package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
  130. package/dist/NavMenu/NavHeadingMenu.js +34 -3
  131. package/dist/NumberInput/NumberInput.d.ts +23 -2
  132. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  133. package/dist/NumberInput/NumberInput.js +62 -12
  134. package/dist/Pagination/Pagination.d.ts +1 -1
  135. package/dist/Pagination/Pagination.d.ts.map +1 -1
  136. package/dist/Pagination/Pagination.js +15 -1
  137. package/dist/Popover/Popover.d.ts +18 -2
  138. package/dist/Popover/Popover.d.ts.map +1 -1
  139. package/dist/Popover/Popover.js +5 -2
  140. package/dist/Popover/usePopover.d.ts +38 -3
  141. package/dist/Popover/usePopover.d.ts.map +1 -1
  142. package/dist/Popover/usePopover.js +24 -9
  143. package/dist/PowerSearch/PowerSearch.d.ts +11 -1
  144. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  145. package/dist/PowerSearch/PowerSearch.js +6 -1
  146. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  147. package/dist/ProgressBar/ProgressBar.js +3 -5
  148. package/dist/RadioList/RadioList.d.ts +20 -2
  149. package/dist/RadioList/RadioList.d.ts.map +1 -1
  150. package/dist/RadioList/RadioList.js +105 -9
  151. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  152. package/dist/RadioList/RadioListItem.js +13 -2
  153. package/dist/SegmentedControl/SegmentedControl.d.ts +13 -2
  154. package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  155. package/dist/SegmentedControl/SegmentedControl.js +78 -44
  156. package/dist/SegmentedControl/SegmentedControlContext.d.ts +7 -0
  157. package/dist/SegmentedControl/SegmentedControlContext.d.ts.map +1 -1
  158. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  159. package/dist/SegmentedControl/SegmentedControlItem.js +13 -2
  160. package/dist/Selector/Selector.d.ts +24 -1
  161. package/dist/Selector/Selector.d.ts.map +1 -1
  162. package/dist/Selector/Selector.js +122 -43
  163. package/dist/Selector/hooks.d.ts +8 -1
  164. package/dist/Selector/hooks.d.ts.map +1 -1
  165. package/dist/Selector/hooks.js +14 -1
  166. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  167. package/dist/SideNav/SideNavHeading.js +2 -0
  168. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  169. package/dist/SideNav/SideNavItem.js +1 -1
  170. package/dist/Skeleton/Skeleton.d.ts.map +1 -1
  171. package/dist/Skeleton/Skeleton.js +8 -2
  172. package/dist/Slider/Slider.d.ts +21 -0
  173. package/dist/Slider/Slider.d.ts.map +1 -1
  174. package/dist/Slider/Slider.js +36 -9
  175. package/dist/Spinner/Spinner.d.ts.map +1 -1
  176. package/dist/Spinner/Spinner.js +1 -1
  177. package/dist/Stack/Stack.d.ts +38 -23
  178. package/dist/Stack/Stack.d.ts.map +1 -1
  179. package/dist/Stack/Stack.js +25 -1
  180. package/dist/Stack/StackItem.d.ts +12 -23
  181. package/dist/Stack/StackItem.d.ts.map +1 -1
  182. package/dist/Stack/StackItem.js +8 -1
  183. package/dist/Switch/Switch.d.ts +23 -2
  184. package/dist/Switch/Switch.d.ts.map +1 -1
  185. package/dist/Switch/Switch.js +41 -11
  186. package/dist/TabList/Tab.d.ts.map +1 -1
  187. package/dist/TabList/Tab.js +6 -0
  188. package/dist/TabList/TabList.d.ts +16 -4
  189. package/dist/TabList/TabList.d.ts.map +1 -1
  190. package/dist/TabList/TabList.js +87 -10
  191. package/dist/TabList/TabListContext.d.ts +5 -0
  192. package/dist/TabList/TabListContext.d.ts.map +1 -1
  193. package/dist/TabList/TabListContext.js +5 -0
  194. package/dist/TabList/TabMenu.d.ts.map +1 -1
  195. package/dist/TabList/TabMenu.js +6 -1
  196. package/dist/Table/BaseTable.d.ts.map +1 -1
  197. package/dist/Table/BaseTable.js +11 -8
  198. package/dist/Table/Table.d.ts.map +1 -1
  199. package/dist/Table/Table.js +10 -1
  200. package/dist/Table/TableCell.d.ts +8 -1
  201. package/dist/Table/TableCell.d.ts.map +1 -1
  202. package/dist/Table/TableCell.js +10 -10
  203. package/dist/Table/TableHeaderCell.d.ts +8 -1
  204. package/dist/Table/TableHeaderCell.d.ts.map +1 -1
  205. package/dist/Table/TableHeaderCell.js +16 -16
  206. package/dist/Table/index.d.ts +2 -1
  207. package/dist/Table/index.d.ts.map +1 -1
  208. package/dist/Table/index.js +2 -2
  209. package/dist/Table/plugins/pagination/paginateData.d.ts +2 -1
  210. package/dist/Table/plugins/pagination/paginateData.d.ts.map +1 -1
  211. package/dist/Table/plugins/pagination/paginateData.js +8 -3
  212. package/dist/Table/plugins/pagination/useTablePagination.d.ts.map +1 -1
  213. package/dist/Table/plugins/pagination/useTablePagination.js +6 -1
  214. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  215. package/dist/Table/plugins/sortable/useTableSortable.js +59 -3
  216. package/dist/Table/tableContextMenu.d.ts +33 -0
  217. package/dist/Table/tableContextMenu.d.ts.map +1 -0
  218. package/dist/Table/tableContextMenu.js +133 -0
  219. package/dist/Table/types.d.ts +66 -0
  220. package/dist/Table/types.d.ts.map +1 -1
  221. package/dist/TextArea/TextArea.d.ts +22 -1
  222. package/dist/TextArea/TextArea.d.ts.map +1 -1
  223. package/dist/TextArea/TextArea.js +41 -9
  224. package/dist/TextInput/TextInput.d.ts +23 -2
  225. package/dist/TextInput/TextInput.d.ts.map +1 -1
  226. package/dist/TextInput/TextInput.js +55 -10
  227. package/dist/TimeInput/TimeInput.d.ts +23 -1
  228. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  229. package/dist/TimeInput/TimeInput.js +147 -76
  230. package/dist/Toast/Toast.d.ts.map +1 -1
  231. package/dist/Toast/Toast.js +14 -0
  232. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  233. package/dist/Toast/ToastViewport.js +131 -3
  234. package/dist/Tokenizer/Tokenizer.d.ts +12 -1
  235. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  236. package/dist/Tokenizer/Tokenizer.js +26 -4
  237. package/dist/Toolbar/Toolbar.d.ts +3 -3
  238. package/dist/Toolbar/Toolbar.d.ts.map +1 -1
  239. package/dist/Toolbar/Toolbar.js +51 -7
  240. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  241. package/dist/Tooltip/useTooltip.js +56 -9
  242. package/dist/TopNav/TopNavHeading.d.ts +7 -1
  243. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  244. package/dist/TopNav/TopNavHeading.js +8 -0
  245. package/dist/TreeList/TreeList.d.ts +1 -1
  246. package/dist/TreeList/TreeList.d.ts.map +1 -1
  247. package/dist/TreeList/TreeList.js +72 -2
  248. package/dist/TreeList/TreeListItem.d.ts +11 -1
  249. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  250. package/dist/TreeList/TreeListItem.js +51 -12
  251. package/dist/TreeList/treeListItem.markers.stylex.d.ts +16 -0
  252. package/dist/TreeList/treeListItem.markers.stylex.d.ts.map +1 -0
  253. package/dist/TreeList/treeListItem.markers.stylex.js +22 -0
  254. package/dist/Typeahead/BaseTypeahead.d.ts +13 -0
  255. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  256. package/dist/Typeahead/BaseTypeahead.js +69 -6
  257. package/dist/Typeahead/Typeahead.d.ts +26 -3
  258. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  259. package/dist/Typeahead/Typeahead.js +65 -29
  260. package/dist/VisuallyHidden/VisuallyHidden.d.ts +61 -0
  261. package/dist/VisuallyHidden/VisuallyHidden.d.ts.map +1 -0
  262. package/dist/VisuallyHidden/VisuallyHidden.js +65 -0
  263. package/dist/VisuallyHidden/index.d.ts +11 -0
  264. package/dist/VisuallyHidden/index.d.ts.map +1 -0
  265. package/dist/VisuallyHidden/index.js +13 -0
  266. package/dist/astryx.css +18 -0
  267. package/dist/astryx.umd.js +55 -55
  268. package/dist/astryx.umd.js.map +4 -4
  269. package/dist/hooks/focusableSelector.d.ts +22 -0
  270. package/dist/hooks/focusableSelector.d.ts.map +1 -0
  271. package/dist/hooks/focusableSelector.js +24 -0
  272. package/dist/hooks/index.d.ts +12 -2
  273. package/dist/hooks/index.d.ts.map +1 -1
  274. package/dist/hooks/index.js +7 -2
  275. package/dist/hooks/useAnnounce.d.ts +40 -0
  276. package/dist/hooks/useAnnounce.d.ts.map +1 -0
  277. package/dist/hooks/useAnnounce.js +142 -0
  278. package/dist/hooks/useClickableContainer.d.ts +16 -1
  279. package/dist/hooks/useClickableContainer.d.ts.map +1 -1
  280. package/dist/hooks/useClickableContainer.js +16 -4
  281. package/dist/hooks/useEntryAnimation.d.ts.map +1 -1
  282. package/dist/hooks/useEntryAnimation.js +4 -4
  283. package/dist/hooks/useFocusTrap.d.ts +18 -0
  284. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  285. package/dist/hooks/useFocusTrap.js +87 -3
  286. package/dist/hooks/useGridFocus.d.ts +88 -1
  287. package/dist/hooks/useGridFocus.d.ts.map +1 -1
  288. package/dist/hooks/useGridFocus.js +261 -62
  289. package/dist/hooks/useKeyboardHint.d.ts +82 -0
  290. package/dist/hooks/useKeyboardHint.d.ts.map +1 -0
  291. package/dist/hooks/useKeyboardHint.js +220 -0
  292. package/dist/hooks/useListFocus.d.ts +78 -7
  293. package/dist/hooks/useListFocus.d.ts.map +1 -1
  294. package/dist/hooks/useListFocus.js +305 -52
  295. package/dist/hooks/useLongPress.d.ts +21 -0
  296. package/dist/hooks/useLongPress.d.ts.map +1 -0
  297. package/dist/hooks/useLongPress.js +89 -0
  298. package/dist/hooks/useTreeFocus.d.ts +157 -0
  299. package/dist/hooks/useTreeFocus.d.ts.map +1 -0
  300. package/dist/hooks/useTreeFocus.js +337 -0
  301. package/dist/hooks/useTypeahead.d.ts +63 -0
  302. package/dist/hooks/useTypeahead.d.ts.map +1 -0
  303. package/dist/hooks/useTypeahead.js +117 -0
  304. package/dist/index.d.ts +1 -0
  305. package/dist/index.d.ts.map +1 -1
  306. package/dist/index.js +1 -0
  307. package/dist/utils/dateTypes.d.ts +12 -0
  308. package/dist/utils/dateTypes.d.ts.map +1 -1
  309. package/dist/utils/dateTypes.js +41 -1
  310. package/dist/utils/index.d.ts +4 -0
  311. package/dist/utils/index.d.ts.map +1 -1
  312. package/dist/utils/index.js +3 -1
  313. package/dist/utils/inputAria.d.ts +29 -0
  314. package/dist/utils/inputAria.d.ts.map +1 -0
  315. package/dist/utils/inputAria.js +30 -0
  316. package/dist/utils/timeParser.d.ts.map +1 -1
  317. package/dist/utils/timeParser.js +5 -2
  318. package/docs.mjs +2 -2
  319. package/package.json +12 -8
  320. package/src/Avatar/Avatar.test.tsx +37 -0
  321. package/src/Avatar/Avatar.tsx +10 -5
  322. package/src/Breadcrumbs/BreadcrumbItem.tsx +25 -7
  323. package/src/Breadcrumbs/Breadcrumbs.test.tsx +31 -10
  324. package/src/Button/Button.tsx +3 -16
  325. package/src/ButtonGroup/ButtonGroup.test.tsx +9 -9
  326. package/src/ButtonGroup/ButtonGroup.tsx +0 -1
  327. package/src/Calendar/Calendar.doc.mjs +4 -4
  328. package/src/Calendar/Calendar.test.tsx +168 -30
  329. package/src/Calendar/Calendar.tsx +121 -66
  330. package/src/Calendar/hooks/index.ts +0 -6
  331. package/src/Calendar/index.ts +1 -3
  332. package/src/Calendar/styles.ts +4 -9
  333. package/src/Carousel/Carousel.doc.mjs +7 -1
  334. package/src/Carousel/Carousel.test.tsx +20 -0
  335. package/src/Carousel/Carousel.tsx +16 -1
  336. package/src/Center/Center.doc.mjs +12 -2
  337. package/src/Center/Center.tsx +28 -3
  338. package/src/Chat/ChatComposerInput.test.tsx +26 -7
  339. package/src/Chat/ChatComposerInput.tsx +0 -1
  340. package/src/Chat/ChatDictationButton.doc.mjs +1 -1
  341. package/src/Chat/ChatMessageList.doc.mjs +8 -0
  342. package/src/Chat/ChatMessageList.test.tsx +18 -0
  343. package/src/Chat/ChatMessageList.tsx +16 -0
  344. package/src/Chat/useTriggerMenu.tsx +22 -4
  345. package/src/CheckboxInput/CheckboxInput.doc.mjs +10 -0
  346. package/src/CheckboxInput/CheckboxInput.test.tsx +172 -27
  347. package/src/CheckboxInput/CheckboxInput.tsx +78 -6
  348. package/src/CheckboxList/CheckboxList.doc.mjs +9 -0
  349. package/src/CheckboxList/CheckboxList.test.tsx +192 -26
  350. package/src/CheckboxList/CheckboxList.tsx +56 -3
  351. package/src/CheckboxList/CheckboxListContext.tsx +7 -0
  352. package/src/CheckboxList/CheckboxListItem.tsx +0 -3
  353. package/src/Citation/Citation.doc.mjs +10 -0
  354. package/src/Citation/Citation.test.tsx +121 -0
  355. package/src/Citation/Citation.tsx +15 -3
  356. package/src/CodeBlock/CodeBlock.test.tsx +115 -0
  357. package/src/CodeBlock/CodeBlock.tsx +63 -33
  358. package/src/CommandPalette/CommandPalette.test.tsx +47 -1
  359. package/src/CommandPalette/CommandPalette.tsx +9 -21
  360. package/src/ContextMenu/ContextMenu.doc.mjs +4 -4
  361. package/src/ContextMenu/ContextMenu.test.tsx +155 -1
  362. package/src/ContextMenu/ContextMenu.tsx +113 -16
  363. package/src/DateInput/DateInput.doc.mjs +286 -56
  364. package/src/DateInput/DateInput.test.tsx +248 -2
  365. package/src/DateInput/DateInput.tsx +196 -100
  366. package/src/DateRangeInput/DateRangeInput.doc.mjs +251 -46
  367. package/src/DateRangeInput/DateRangeInput.test.tsx +182 -20
  368. package/src/DateRangeInput/DateRangeInput.tsx +63 -5
  369. package/src/DateTimeInput/DateTimeInput.doc.mjs +368 -67
  370. package/src/DateTimeInput/DateTimeInput.test.tsx +279 -11
  371. package/src/DateTimeInput/DateTimeInput.tsx +125 -17
  372. package/src/Dialog/Dialog.doc.mjs +2 -2
  373. package/src/Dialog/Dialog.tsx +12 -0
  374. package/src/DropdownMenu/DropdownMenu.doc.mjs +1 -8
  375. package/src/DropdownMenu/DropdownMenu.test.tsx +56 -42
  376. package/src/DropdownMenu/DropdownMenu.tsx +52 -18
  377. package/src/Field/Field.doc.mjs +59 -18
  378. package/src/Field/Field.test.tsx +32 -0
  379. package/src/Field/Field.tsx +23 -5
  380. package/src/Field/FieldLabel.tsx +55 -17
  381. package/src/FileInput/FileInput.doc.mjs +17 -0
  382. package/src/FileInput/FileInput.test.tsx +283 -49
  383. package/src/FileInput/FileInput.tsx +76 -4
  384. package/src/Grid/Grid.doc.mjs +17 -4
  385. package/src/Grid/Grid.test.tsx +43 -30
  386. package/src/Grid/Grid.tsx +38 -3
  387. package/src/Icon/Icon.doc.mjs +3 -3
  388. package/src/InputGroup/InputGroup.doc.mjs +111 -23
  389. package/src/InputGroup/InputGroup.test.tsx +257 -60
  390. package/src/InputGroup/InputGroup.tsx +23 -5
  391. package/src/InputGroup/InputGroupContext.ts +9 -4
  392. package/src/InputGroup/groupStyles.ts +7 -1
  393. package/src/InputGroup/index.ts +1 -0
  394. package/src/Kbd/Kbd.test.tsx +22 -4
  395. package/src/Kbd/Kbd.tsx +35 -3
  396. package/src/Layer/layerAnimations.stylex.ts +20 -4
  397. package/src/Layer/useLayer.doc.mjs +5 -0
  398. package/src/Layer/useLayer.test.tsx +111 -0
  399. package/src/Layer/useLayer.tsx +90 -9
  400. package/src/Layout/Layout.tsx +8 -16
  401. package/src/Layout/LayoutFooter.doc.mjs +4 -4
  402. package/src/Layout/LayoutFooter.tsx +3 -3
  403. package/src/Layout/LayoutHeader.doc.mjs +4 -4
  404. package/src/Layout/LayoutHeader.tsx +3 -3
  405. package/src/Layout/LayoutPanel.tsx +3 -3
  406. package/src/Layout/padding.stylex.ts +52 -0
  407. package/src/Lightbox/Lightbox.doc.mjs +9 -0
  408. package/src/Lightbox/Lightbox.test.tsx +53 -5
  409. package/src/Lightbox/Lightbox.tsx +9 -4
  410. package/src/Link/Link.doc.mjs +14 -0
  411. package/src/Link/Link.test.tsx +50 -0
  412. package/src/Link/Link.tsx +39 -4
  413. package/src/Markdown/Markdown.test.tsx +11 -0
  414. package/src/Markdown/Markdown.tsx +7 -0
  415. package/src/MetadataList/MetadataListItem.doc.mjs +4 -0
  416. package/src/MoreMenu/MoreMenu.doc.mjs +2 -17
  417. package/src/MoreMenu/MoreMenu.tsx +0 -9
  418. package/src/MultiSelector/MultiSelector.doc.mjs +30 -0
  419. package/src/MultiSelector/MultiSelector.test.tsx +375 -8
  420. package/src/MultiSelector/MultiSelector.tsx +194 -48
  421. package/src/MultiSelector/hooks.ts +27 -0
  422. package/src/NavMenu/NavHeadingMenu.test.tsx +77 -1
  423. package/src/NavMenu/NavHeadingMenu.tsx +50 -3
  424. package/src/NumberInput/NumberInput.doc.mjs +17 -0
  425. package/src/NumberInput/NumberInput.test.tsx +242 -40
  426. package/src/NumberInput/NumberInput.tsx +89 -11
  427. package/src/Pagination/Pagination.doc.mjs +3 -3
  428. package/src/Pagination/Pagination.test.tsx +117 -5
  429. package/src/Pagination/Pagination.tsx +21 -1
  430. package/src/Popover/Popover.doc.mjs +26 -0
  431. package/src/Popover/Popover.test.tsx +121 -0
  432. package/src/Popover/Popover.tsx +23 -2
  433. package/src/Popover/usePopover.doc.mjs +9 -3
  434. package/src/Popover/usePopover.tsx +70 -12
  435. package/src/PowerSearch/PowerSearch.doc.mjs +15 -0
  436. package/src/PowerSearch/PowerSearch.test.tsx +97 -1
  437. package/src/PowerSearch/PowerSearch.tsx +16 -3
  438. package/src/ProgressBar/ProgressBar.test.tsx +34 -26
  439. package/src/ProgressBar/ProgressBar.tsx +3 -4
  440. package/src/RadioList/RadioList.doc.mjs +9 -0
  441. package/src/RadioList/RadioList.test.tsx +252 -16
  442. package/src/RadioList/RadioList.tsx +166 -10
  443. package/src/RadioList/RadioListItem.tsx +14 -2
  444. package/src/SegmentedControl/SegmentedControl.doc.mjs +9 -0
  445. package/src/SegmentedControl/SegmentedControl.test.tsx +214 -42
  446. package/src/SegmentedControl/SegmentedControl.tsx +102 -54
  447. package/src/SegmentedControl/SegmentedControlContext.ts +7 -0
  448. package/src/SegmentedControl/SegmentedControlItem.tsx +14 -1
  449. package/src/SelectableCard/SelectableCard.doc.mjs +1 -1
  450. package/src/Selector/Selector.doc.mjs +26 -0
  451. package/src/Selector/Selector.test.tsx +387 -15
  452. package/src/Selector/Selector.tsx +175 -67
  453. package/src/Selector/hooks.ts +23 -0
  454. package/src/SideNav/SideNav.test.tsx +48 -0
  455. package/src/SideNav/SideNavHeading.tsx +8 -2
  456. package/src/SideNav/SideNavItem.tsx +2 -4
  457. package/src/Skeleton/Skeleton.test.tsx +25 -0
  458. package/src/Skeleton/Skeleton.tsx +11 -1
  459. package/src/Slider/Slider.doc.mjs +15 -0
  460. package/src/Slider/Slider.test.tsx +155 -2
  461. package/src/Slider/Slider.tsx +53 -5
  462. package/src/Spinner/Spinner.tsx +7 -1
  463. package/src/Stack/Stack.doc.mjs +77 -0
  464. package/src/Stack/Stack.test.tsx +55 -5
  465. package/src/Stack/Stack.tsx +73 -24
  466. package/src/Stack/StackItem.test.tsx +23 -0
  467. package/src/Stack/StackItem.tsx +20 -23
  468. package/src/Switch/Switch.doc.mjs +15 -0
  469. package/src/Switch/Switch.test.tsx +162 -27
  470. package/src/Switch/Switch.tsx +61 -21
  471. package/src/TabList/Tab.tsx +6 -0
  472. package/src/TabList/TabList.doc.mjs +6 -0
  473. package/src/TabList/TabList.test.tsx +251 -0
  474. package/src/TabList/TabList.tsx +103 -12
  475. package/src/TabList/TabListContext.ts +7 -3
  476. package/src/TabList/TabMenu.tsx +6 -3
  477. package/src/Table/BaseTable.tsx +21 -17
  478. package/src/Table/Table.doc.mjs +2 -0
  479. package/src/Table/Table.test.tsx +10 -0
  480. package/src/Table/Table.tsx +8 -0
  481. package/src/Table/TableCell.tsx +25 -23
  482. package/src/Table/TableHeaderCell.tsx +28 -29
  483. package/src/Table/index.ts +3 -2
  484. package/src/Table/plugins/pagination/paginateData.ts +10 -3
  485. package/src/Table/plugins/pagination/useTablePagination.test.tsx +16 -0
  486. package/src/Table/plugins/pagination/useTablePagination.tsx +8 -1
  487. package/src/Table/plugins/sortable/useTableSortable.test.tsx +91 -2
  488. package/src/Table/plugins/sortable/useTableSortable.tsx +53 -1
  489. package/src/Table/tableContextMenu.test.tsx +157 -0
  490. package/src/Table/tableContextMenu.tsx +142 -0
  491. package/src/Table/types.ts +74 -0
  492. package/src/Table/useTableColumnResize.doc.mjs +3 -3
  493. package/src/Table/useTableStickyColumns.doc.mjs +2 -2
  494. package/src/Text/Text.doc.mjs +18 -18
  495. package/src/TextArea/TextArea.doc.mjs +17 -0
  496. package/src/TextArea/TextArea.test.tsx +167 -35
  497. package/src/TextArea/TextArea.tsx +62 -15
  498. package/src/TextInput/TextInput.doc.mjs +17 -0
  499. package/src/TextInput/TextInput.test.tsx +168 -34
  500. package/src/TextInput/TextInput.tsx +77 -9
  501. package/src/Thumbnail/Thumbnail.doc.mjs +4 -4
  502. package/src/TimeInput/TimeInput.doc.mjs +340 -60
  503. package/src/TimeInput/TimeInput.test.tsx +255 -7
  504. package/src/TimeInput/TimeInput.tsx +176 -70
  505. package/src/Timestamp/Timestamp.doc.mjs +19 -19
  506. package/src/Toast/Toast.tsx +14 -0
  507. package/src/Toast/ToastViewport.test.tsx +214 -0
  508. package/src/Toast/ToastViewport.tsx +167 -21
  509. package/src/Tokenizer/Tokenizer.doc.mjs +29 -14
  510. package/src/Tokenizer/Tokenizer.test.tsx +105 -1
  511. package/src/Tokenizer/Tokenizer.tsx +37 -1
  512. package/src/Toolbar/Toolbar.test.tsx +109 -6
  513. package/src/Toolbar/Toolbar.tsx +59 -5
  514. package/src/Tooltip/Tooltip.test.tsx +68 -0
  515. package/src/Tooltip/useTooltip.tsx +55 -8
  516. package/src/TopNav/TopNav.test.tsx +50 -0
  517. package/src/TopNav/TopNavHeading.tsx +17 -1
  518. package/src/TreeList/TreeList.test.tsx +295 -6
  519. package/src/TreeList/TreeList.tsx +73 -1
  520. package/src/TreeList/TreeListItem.tsx +51 -5
  521. package/src/TreeList/treeListItem.markers.stylex.ts +20 -0
  522. package/src/Typeahead/BaseTypeahead.tsx +93 -9
  523. package/src/Typeahead/Typeahead.doc.mjs +141 -30
  524. package/src/Typeahead/Typeahead.test.tsx +331 -1
  525. package/src/Typeahead/Typeahead.tsx +105 -33
  526. package/src/VisuallyHidden/VisuallyHidden.doc.mjs +80 -0
  527. package/src/VisuallyHidden/VisuallyHidden.test.tsx +76 -0
  528. package/src/VisuallyHidden/VisuallyHidden.tsx +113 -0
  529. package/src/VisuallyHidden/index.ts +15 -0
  530. package/src/docs-script.test.mjs +50 -0
  531. package/src/hooks/focusableSelector.ts +25 -0
  532. package/src/hooks/index.ts +28 -2
  533. package/src/hooks/useAnnounce.test.tsx +101 -0
  534. package/src/hooks/useAnnounce.ts +168 -0
  535. package/src/hooks/useClickableContainer.ts +16 -4
  536. package/src/hooks/useEntryAnimation.ts +16 -4
  537. package/src/hooks/useFocusTrap.test.tsx +132 -0
  538. package/src/hooks/useFocusTrap.ts +98 -4
  539. package/src/hooks/useGridFocus.doc.mjs +40 -2
  540. package/src/hooks/useGridFocus.test.tsx +132 -0
  541. package/src/hooks/useGridFocus.ts +343 -67
  542. package/src/hooks/useKeyboardHint.doc.mjs +101 -0
  543. package/src/hooks/useKeyboardHint.test.tsx +70 -0
  544. package/src/hooks/useKeyboardHint.tsx +332 -0
  545. package/src/hooks/useListFocus.doc.mjs +50 -10
  546. package/src/hooks/useListFocus.test.tsx +375 -0
  547. package/src/hooks/useListFocus.ts +395 -57
  548. package/src/hooks/useLongPress.test.tsx +134 -0
  549. package/src/hooks/useLongPress.ts +119 -0
  550. package/src/hooks/useTreeFocus.doc.mjs +140 -0
  551. package/src/hooks/useTreeFocus.test.tsx +214 -0
  552. package/src/hooks/useTreeFocus.ts +559 -0
  553. package/src/hooks/useTypeahead.test.tsx +109 -0
  554. package/src/hooks/useTypeahead.ts +183 -0
  555. package/src/index.ts +1 -0
  556. package/src/theme/derivedVarRegistry.test.ts +10 -5
  557. package/src/utils/dateTypes.test.ts +40 -0
  558. package/src/utils/dateTypes.ts +40 -0
  559. package/src/utils/index.ts +9 -0
  560. package/src/utils/inputAria.test.ts +39 -0
  561. package/src/utils/inputAria.ts +58 -0
  562. package/src/utils/timeParser.test.ts +10 -0
  563. package/src/utils/timeParser.ts +5 -2
  564. package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts +0 -57
  565. package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts.map +0 -1
  566. package/dist/Calendar/hooks/useCalendarRovingTabindex.js +0 -96
  567. package/src/Calendar/hooks/useCalendarRovingTabindex.ts +0 -118
@@ -205,6 +205,7 @@ function TableRowInner<T extends Record<string, unknown>>({
205
205
  <CellComponent
206
206
  key={col.key}
207
207
  {...cellRenderProps.htmlProps}
208
+ contextMenuActions={cellRenderProps.contextMenuActions}
208
209
  xstyle={cellRenderProps.styles}>
209
210
  {content}
210
211
  </CellComponent>
@@ -409,29 +410,32 @@ function BaseTableInner<T extends Record<string, unknown>>({
409
410
  const hasSlots =
410
411
  before != null || after != null || overlay != null || below != null;
411
412
 
413
+ const headerInner = hasSlots ? (
414
+ <>
415
+ {before}
416
+ {after != null ? (
417
+ <div {...stylex.props(styles.headerLabelRow)}>
418
+ {resolvedContent}
419
+ {after}
420
+ </div>
421
+ ) : (
422
+ resolvedContent
423
+ )}
424
+ {overlay}
425
+ {below}
426
+ </>
427
+ ) : (
428
+ resolvedContent
429
+ );
430
+
412
431
  return (
413
432
  <HeaderCellComponent
414
433
  key={col.key}
415
434
  {...mergedHtmlProps}
416
435
  {...headerTitleProp}
436
+ contextMenuActions={cellRenderProps.contextMenuActions}
417
437
  xstyle={cellRenderProps.styles}>
418
- {hasSlots ? (
419
- <>
420
- {before}
421
- {after != null ? (
422
- <div {...stylex.props(styles.headerLabelRow)}>
423
- {resolvedContent}
424
- {after}
425
- </div>
426
- ) : (
427
- resolvedContent
428
- )}
429
- {overlay}
430
- {below}
431
- </>
432
- ) : (
433
- resolvedContent
434
- )}
438
+ {headerInner}
435
439
  </HeaderCellComponent>
436
440
  );
437
441
  });
@@ -118,6 +118,7 @@ export const docs = {
118
118
  { guidance: true, description: 'Use density and divider variants to match the information density and scanning needs of your data.' },
119
119
  { guidance: true, description: 'Compose rich cell content with Astryx components like Badge, StatusDot, and Avatar via renderCell.' },
120
120
  { guidance: true, description: 'Set explicit width on every column using proportional() or pixel(). proportional(1) gives equal flex distribution with a 120px minimum that prevents columns from collapsing on narrow viewports. Omitting width skips the minimum.' },
121
+ { guidance: true, description: 'Use the data-driven API from React Server Components: proportional(), pixel(), and column definitions without function props are server-safe. Columns using renderCell (or any function prop) need the table wrapped in a "use client" component, since functions cannot cross the server-client boundary.' },
121
122
  { guidance: false, description: 'Use a table for data without consistent columns. Use a list or card layout for heterogeneous content.' },
122
123
  { guidance: false, description: 'Enable every plugin at once. Add only the features your use case requires to keep the interface focused.' },
123
124
  { guidance: false, description: 'Omit width on text-heavy columns; without an explicit proportional() width they have no minimum and can squish to near-zero on mobile.' },
@@ -165,6 +166,7 @@ export const docsDense = {
165
166
  { guidance: true, description: 'Use density and divider variants to match the information density and scanning needs of your data.' },
166
167
  { guidance: true, description: 'Compose rich cell content with Astryx components like Badge, StatusDot, and Avatar via renderCell.' },
167
168
  { guidance: true, description: 'Set explicit width on every column via proportional() or pixel(). proportional(1) = equal flex w/ 120px min preventing collapse on narrow viewports. Omitting width skips the minimum.' },
169
+ { guidance: true, description: 'Data-driven API is RSC-safe: proportional(), pixel(), column defs w/o function props work in Server Components. renderCell (any function prop) requires a "use client" wrapper.' },
168
170
  { guidance: false, description: 'Use a table for data without consistent columns. Use a list or card layout for heterogeneous content.' },
169
171
  { guidance: false, description: 'Enable every plugin at once. Add only the features your use case requires to keep the interface focused.' },
170
172
  { guidance: false, description: 'Omit width on text-heavy columns; w/o explicit proportional() width they have no minimum and can squish to near-zero on mobile.' },
@@ -633,6 +633,16 @@ describe('Table', () => {
633
633
  expect(wrapper!.className).toContain('astryx-table-scroll-wrapper');
634
634
  });
635
635
 
636
+ it('makes the scroll container keyboard-focusable', () => {
637
+ render(<Table data={users} columns={columns} />);
638
+ const table = screen.getByRole('table');
639
+ const wrapper = table.parentElement;
640
+ expect(wrapper).toBeTruthy();
641
+ expect(wrapper!).toHaveAttribute('tabindex', '0');
642
+ expect(wrapper!).toHaveAttribute('role', 'group');
643
+ expect(wrapper!).toHaveAttribute('aria-label', 'Table');
644
+ });
645
+
636
646
  it('uses table-layout: auto in children mode', () => {
637
647
  const {container} = render(
638
648
  <Table dividers="rows">
@@ -151,6 +151,14 @@ function TableScrollWrapper({
151
151
  return (
152
152
  <div
153
153
  ref={ref}
154
+ // Keyboard-focusable so keyboard users can scroll a horizontally
155
+ // overflowing table. Uses role="group" (not "region") so multiple
156
+ // tables on a page don't create duplicate same-named landmarks
157
+ // (axe: landmark-unique). Callers may override role/aria-label via
158
+ // htmlProps.
159
+ tabIndex={0}
160
+ role="group"
161
+ aria-label="Table"
154
162
  {...restHtmlProps}
155
163
  {...mergeProps(
156
164
  themeProps('table-scroll-wrapper'),
@@ -24,6 +24,8 @@ import {
24
24
  typeScaleVars,
25
25
  } from '../theme/tokens.stylex';
26
26
  import type {StyleXStyles} from '../theme/types';
27
+ import type {TableContextActions} from './types';
28
+ import {wrapInTableContextMenu} from './tableContextMenu';
27
29
  import {
28
30
  overflowStyles,
29
31
  wrapStyles,
@@ -56,6 +58,12 @@ export interface TableCellProps extends BaseProps<HTMLTableCellElement> {
56
58
  * Must be a `stylex.create()` value — not an inline style object.
57
59
  */
58
60
  xstyle?: StyleXStyles | StyleXStyles[];
61
+ /**
62
+ * Right-click actions rendered as a context menu around the cell content.
63
+ * The cell owns the wrapper so it controls how the menu interacts with its
64
+ * padding / content. Empty or undefined renders no menu.
65
+ */
66
+ contextMenuActions?: TableContextActions;
59
67
  }
60
68
 
61
69
  const densityStyles = stylex.create({
@@ -138,33 +146,27 @@ export function TableCell({
138
146
  ref,
139
147
  className: incomingClassName,
140
148
  style: incomingStyle,
149
+ contextMenuActions,
141
150
  ...props
142
151
  }: TableCellProps) {
143
152
  const ctx = useTableContext();
144
153
 
145
- if (!ctx) {
146
- return (
147
- <td
148
- ref={ref}
149
- {...props}
150
- {...mergeProps(
151
- themeProps('table-cell'),
152
- stylex.props(xstyle),
153
- incomingClassName,
154
- incomingStyle,
155
- )}>
156
- {children}
157
- </td>
158
- );
159
- }
154
+ // Standalone (no table context) renders plain, with no density/divider styles.
155
+ const cellStyles: StyleXStyles[] = ctx
156
+ ? [
157
+ densityStyles[ctx.density],
158
+ ctx.textOverflow === 'truncate'
159
+ ? overflowStyles.cell
160
+ : wrapStyles.cell,
161
+ containerEdgeStyles[ctx.density],
162
+ verticalAlignStyles[ctx.verticalAlign],
163
+ ...buildDividerStyles(ctx, dividerRowStyles.cell, dividerColumnStyles.cell),
164
+ ]
165
+ : [];
160
166
 
161
- const cellStyles: StyleXStyles[] = [
162
- densityStyles[ctx.density],
163
- ctx.textOverflow === 'truncate' ? overflowStyles.cell : wrapStyles.cell,
164
- containerEdgeStyles[ctx.density],
165
- verticalAlignStyles[ctx.verticalAlign],
166
- ...buildDividerStyles(ctx, dividerRowStyles.cell, dividerColumnStyles.cell),
167
- ];
167
+ // The cell owns the context-menu wrapper so it controls how the menu
168
+ // interacts with its padding / content. No-op when no actions.
169
+ const content = wrapInTableContextMenu(children, contextMenuActions);
168
170
 
169
171
  return (
170
172
  <td
@@ -176,7 +178,7 @@ export function TableCell({
176
178
  incomingClassName,
177
179
  incomingStyle,
178
180
  )}>
179
- {children}
181
+ {content}
180
182
  </td>
181
183
  );
182
184
  }
@@ -25,8 +25,10 @@ import {
25
25
  borderVars,
26
26
  } from '../theme/tokens.stylex';
27
27
  import type {StyleXStyles} from '../theme/types';
28
+ import type {TableContextActions} from './types';
28
29
  import {overflowStyles, containerEdgeStyles} from './table.stylex';
29
30
  import {useTableContext, mergeXStyle} from './useTableCellStyles';
31
+ import {wrapInTableContextMenu} from './tableContextMenu';
30
32
  import {mergeProps} from '../utils';
31
33
  import {themeProps} from '../utils/themeProps';
32
34
 
@@ -42,6 +44,12 @@ export interface TableHeaderCellProps extends BaseProps<HTMLTableCellElement> {
42
44
  * Must be a `stylex.create()` value — not an inline style object.
43
45
  */
44
46
  xstyle?: StyleXStyles | StyleXStyles[];
47
+ /**
48
+ * Right-click actions rendered as a context menu around the cell content.
49
+ * The cell owns the wrapper so it controls how the menu interacts with its
50
+ * padding / content. Empty or undefined renders no menu.
51
+ */
52
+ contextMenuActions?: TableContextActions;
45
53
  }
46
54
 
47
55
  const densityStyles = stylex.create({
@@ -117,41 +125,32 @@ export function TableHeaderCell({
117
125
  ref,
118
126
  className: incomingClassName,
119
127
  style: incomingStyle,
128
+ contextMenuActions,
120
129
  ...props
121
130
  }: TableHeaderCellProps) {
122
131
  const ctx = useTableContext();
123
132
 
124
- if (!ctx) {
125
- return (
126
- <th
127
- ref={ref}
128
- {...props}
129
- {...mergeProps(
130
- themeProps('table-header-cell'),
131
- stylex.props(xstyle),
132
- incomingClassName,
133
- incomingStyle,
134
- )}>
135
- {children}
136
- </th>
133
+ // Header cells always get the bottom divider (separates header from body).
134
+ // When used standalone (no table context) the cell renders plain, with no
135
+ // density/divider styles.
136
+ const cellStyles: StyleXStyles[] = [];
137
+ if (ctx) {
138
+ cellStyles.push(
139
+ headerStyles.cell,
140
+ densityStyles[ctx.density],
141
+ headerDividerStyles.cell,
142
+ overflowStyles.cell,
143
+ containerEdgeStyles[ctx.density],
137
144
  );
145
+ // Column dividers come from the shared builder (column axis only).
146
+ if (ctx.dividers === 'columns' || ctx.dividers === 'grid') {
147
+ cellStyles.push(dividerColumnStyles.cell);
148
+ }
138
149
  }
139
150
 
140
- // Header cells always get the bottom divider (separates header from body).
141
- // Column dividers use the shared buildDividerStyles but only for
142
- // the column axis, since the row divider is the headerDividerStyles.
143
- const cellStyles: StyleXStyles[] = [
144
- headerStyles.cell,
145
- densityStyles[ctx.density],
146
- headerDividerStyles.cell,
147
- overflowStyles.cell,
148
- containerEdgeStyles[ctx.density],
149
- ];
150
-
151
- // Only add column dividers from the shared builder
152
- if (ctx.dividers === 'columns' || ctx.dividers === 'grid') {
153
- cellStyles.push(dividerColumnStyles.cell);
154
- }
151
+ // The cell owns the context-menu wrapper so it controls how the menu
152
+ // interacts with its padding / content. No-op when no actions.
153
+ const content = wrapInTableContextMenu(children, contextMenuActions);
155
154
 
156
155
  return (
157
156
  <th
@@ -163,7 +162,7 @@ export function TableHeaderCell({
163
162
  incomingClassName,
164
163
  incomingStyle,
165
164
  )}>
166
- {children}
165
+ {content}
167
166
  </th>
168
167
  );
169
168
  }
@@ -1,7 +1,5 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
- 'use client';
4
-
5
3
  /**
6
4
  * @file index.ts
7
5
  * @input Imports from Table component files
@@ -28,6 +26,7 @@ export {useTableColumnSettings} from './plugins/columnSettings';
28
26
  export {useTableColumnSettingsState} from './plugins/columnSettings';
29
27
  export {useTableColumnResize} from './plugins/columnResize';
30
28
  export {useTableStickyColumns} from './plugins/stickyColumns';
29
+ export {resolveContextActions} from './tableContextMenu';
31
30
  export {
32
31
  useTableFiltering,
33
32
  useTableFilterState,
@@ -49,6 +48,8 @@ export type {
49
48
  ProportionalWidth,
50
49
  PixelWidth,
51
50
  TablePlugin,
51
+ TableContextAction,
52
+ TableContextActions,
52
53
  TableRenderProps,
53
54
  HeaderRowRenderProps,
54
55
  HeaderCellRenderProps,
@@ -15,7 +15,8 @@
15
15
  *
16
16
  * @param data - Full data array
17
17
  * @param page - Current page number (1-based)
18
- * @param pageSize - Number of items per page
18
+ * @param pageSize - Number of items per page; coerced to a positive integer,
19
+ * non-finite values fall back to 10
19
20
  * @returns Slice of data for the current page
20
21
  *
21
22
  * @example
@@ -31,6 +32,12 @@ export function paginateData<T>(
31
32
  page: number,
32
33
  pageSize: number,
33
34
  ): T[] {
34
- const start = (page - 1) * pageSize;
35
- return data.slice(start, start + pageSize);
35
+ // Same coercion as Pagination and useTablePagination: a 0/NaN/negative
36
+ // pageSize would slice every page empty while the pagination chrome still
37
+ // renders page buttons.
38
+ const size = Number.isFinite(pageSize)
39
+ ? Math.max(1, Math.floor(pageSize))
40
+ : 10;
41
+ const start = (page - 1) * size;
42
+ return data.slice(start, start + size);
36
43
  }
@@ -184,6 +184,22 @@ describe('useTablePagination', () => {
184
184
  ).toBeTruthy();
185
185
  });
186
186
 
187
+ it('guards pageSize 0 against Infinity page counts', () => {
188
+ render(<PaginatedTable data={generateItems(5)} pageSize={0} />);
189
+ expect(
190
+ screen.getByRole('navigation', {name: 'Table pagination'}),
191
+ ).toBeInTheDocument();
192
+ // pageSize is coerced to 1, so 5 items produce 5 pages, not Infinity,
193
+ // and page 1 shows the first item instead of an empty slice
194
+ expect(
195
+ screen.queryByRole('button', {name: 'Go to page Infinity'}),
196
+ ).toBeNull();
197
+ expect(
198
+ screen.getByRole('button', {name: 'Go to page 5'}),
199
+ ).toBeInTheDocument();
200
+ expect(screen.getByText('Item 1')).toBeInTheDocument();
201
+ });
202
+
187
203
  it('transformTableContext renders Pagination above table', () => {
188
204
  render(
189
205
  <PaginatedTable
@@ -199,7 +199,7 @@ export function useTablePagination<T extends Record<string, unknown>>(
199
199
  totalItems,
200
200
  totalPages: totalPagesProp,
201
201
  hasMore,
202
- pageSize = 10,
202
+ pageSize: pageSizeConfig = 10,
203
203
  onPageSizeChange,
204
204
  pageSizeOptions,
205
205
  variant = 'pages',
@@ -209,6 +209,13 @@ export function useTablePagination<T extends Record<string, unknown>>(
209
209
  label = 'Table pagination',
210
210
  } = config;
211
211
 
212
+ // Same guard as Pagination itself: 0/NaN/negative pageSize would produce an
213
+ // Infinity/NaN totalPages here, which bypasses Pagination's own coercion
214
+ // because it is passed down as the explicit totalPages prop.
215
+ const pageSize = Number.isFinite(pageSizeConfig)
216
+ ? Math.max(1, Math.floor(pageSizeConfig))
217
+ : 10;
218
+
212
219
  const computedTotalPages =
213
220
  totalPagesProp ??
214
221
  (totalItems != null ? Math.ceil(totalItems / pageSize) : undefined);
@@ -7,8 +7,8 @@
7
7
  * @position Testing; validates sortable plugin implementation
8
8
  */
9
9
 
10
- import {describe, it, expect, vi} from 'vitest';
11
- import {render, screen} from '@testing-library/react';
10
+ import {describe, it, expect, vi, beforeEach} from 'vitest';
11
+ import {render, screen, fireEvent} from '@testing-library/react';
12
12
  import userEvent from '@testing-library/user-event';
13
13
  import {useState} from 'react';
14
14
  import {Table} from '../../Table';
@@ -620,3 +620,92 @@ describe('useTableSortable', () => {
620
620
  });
621
621
  });
622
622
  });
623
+
624
+ // =============================================================================
625
+ // Context-menu actions (colocated with the sortable plugin)
626
+ // =============================================================================
627
+
628
+ describe('useTableSortable — context menu actions', () => {
629
+ // jsdom doesn't implement the Popover API; mock it so the menu can "open"
630
+ // and its items become queryable (as hidden).
631
+ beforeEach(() => {
632
+ HTMLElement.prototype.showPopover = vi.fn(function (this: HTMLElement) {
633
+ this.setAttribute('popover-open', '');
634
+ const event = new Event('toggle', {bubbles: false});
635
+ Object.defineProperty(event, 'newState', {value: 'open'});
636
+ this.dispatchEvent(event);
637
+ });
638
+ HTMLElement.prototype.hidePopover = vi.fn(function (this: HTMLElement) {
639
+ this.removeAttribute('popover-open');
640
+ const event = new Event('toggle', {bubbles: false});
641
+ Object.defineProperty(event, 'newState', {value: 'closed'});
642
+ this.dispatchEvent(event);
643
+ });
644
+ const originalMatches = HTMLElement.prototype.matches;
645
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
646
+ (HTMLElement.prototype as any).matches = function (
647
+ selector: string,
648
+ ): boolean {
649
+ if (selector === ':popover-open') {
650
+ return this.hasAttribute('popover-open');
651
+ }
652
+ return originalMatches.call(this, selector);
653
+ };
654
+ });
655
+
656
+ it('offers Sort ascending/descending on a sortable header, and Clear sort once sorted', () => {
657
+ render(<SortableTable allowUnsortedState />);
658
+
659
+ // Unsorted: asc + desc, no "Clear sort".
660
+ fireEvent.contextMenu(screen.getByText('Name'));
661
+ expect(
662
+ screen.getAllByRole('menuitem', {name: 'Sort ascending', hidden: true})
663
+ .length,
664
+ ).toBeGreaterThan(0);
665
+ expect(
666
+ screen.getAllByRole('menuitem', {name: 'Sort descending', hidden: true})
667
+ .length,
668
+ ).toBeGreaterThan(0);
669
+ expect(
670
+ screen.queryByRole('menuitem', {name: 'Clear sort', hidden: true}),
671
+ ).not.toBeInTheDocument();
672
+
673
+ // Apply ascending → "Clear sort" now appears.
674
+ fireEvent.click(
675
+ screen.getAllByRole('menuitem', {name: 'Sort ascending', hidden: true})[0],
676
+ );
677
+ fireEvent.contextMenu(screen.getByText('Name'));
678
+ expect(
679
+ screen.getAllByRole('menuitem', {name: 'Clear sort', hidden: true}).length,
680
+ ).toBeGreaterThan(0);
681
+ });
682
+
683
+ it('resolves fresh actions on each open as sort state changes (lazy getter)', () => {
684
+ const onSortChange = vi.fn();
685
+ render(<SortableTable allowUnsortedState onSortChange={onSortChange} />);
686
+
687
+ // Open (unsorted) and pick descending.
688
+ fireEvent.contextMenu(screen.getByText('Name'));
689
+ fireEvent.click(
690
+ screen.getAllByRole('menuitem', {
691
+ name: 'Sort descending',
692
+ hidden: true,
693
+ })[0],
694
+ );
695
+ expect(onSortChange).toHaveBeenLastCalledWith([
696
+ {sortKey: 'name', direction: 'descending'},
697
+ ]);
698
+
699
+ // Re-open: the getter recomputes against the now-descending state, so
700
+ // "Clear sort" is present and clicking it clears — proving the actions are
701
+ // freshly derived on each open, not memoized from the first render.
702
+ fireEvent.contextMenu(screen.getByText('Name'));
703
+ const clear = screen.getAllByRole('menuitem', {
704
+ name: 'Clear sort',
705
+ hidden: true,
706
+ });
707
+ expect(clear.length).toBeGreaterThan(0);
708
+ fireEvent.click(clear[0]);
709
+ expect(onSortChange).toHaveBeenLastCalledWith([]);
710
+ });
711
+ });
@@ -17,10 +17,12 @@ import {useRef, useMemo, type ReactNode} from 'react';
17
17
  import * as stylex from '@stylexjs/stylex';
18
18
  import {colorVars, spacingVars, radiusVars} from '../../../theme/tokens.stylex';
19
19
  import {Icon} from '../../../Icon';
20
+ import {resolveContextActions} from '../../tableContextMenu';
20
21
  import type {
21
22
  TablePlugin,
22
23
  HeaderCellRenderProps,
23
24
  TableColumn,
25
+ TableContextAction,
24
26
  } from '../../types';
25
27
 
26
28
  // =============================================================================
@@ -356,10 +358,56 @@ export function useTableSortable<
356
358
  return props;
357
359
  }
358
360
 
359
- // Find sort entry for this column
360
361
  const cfg = configRef.current;
361
362
  const entry = cfg.sort.find(e => e.sortKey === sortKey);
362
363
 
364
+ // Context-menu actions are built lazily (only when the menu opens) via
365
+ // a getter, reading the current sort state at call time — so we don't
366
+ // build an action array for every header on every render, and the
367
+ // checked/clear state always reflects the latest sort.
368
+ const getSortActions = (): TableContextAction[] => {
369
+ const c = configRef.current;
370
+ const dir = c.sort.find(e => e.sortKey === sortKey)?.direction ?? null;
371
+ const actions: TableContextAction[] = [
372
+ {
373
+ id: 'sort-asc',
374
+ group: 'sort',
375
+ label: 'Sort ascending',
376
+ icon: <Icon icon="arrowUp" size="xsm" aria-hidden />,
377
+ checked: dir === 'ascending',
378
+ onSelect: () =>
379
+ c.onSortChange([
380
+ {sortKey: sortKey as TSortKey, direction: 'ascending'},
381
+ ]),
382
+ },
383
+ {
384
+ id: 'sort-desc',
385
+ group: 'sort',
386
+ label: 'Sort descending',
387
+ icon: <Icon icon="arrowDown" size="xsm" aria-hidden />,
388
+ checked: dir === 'descending',
389
+ onSelect: () =>
390
+ c.onSortChange([
391
+ {sortKey: sortKey as TSortKey, direction: 'descending'},
392
+ ]),
393
+ },
394
+ ];
395
+ if (dir != null) {
396
+ actions.push({
397
+ id: 'sort-clear',
398
+ group: 'sort-clear',
399
+ label: 'Clear sort',
400
+ icon: <Icon icon="close" size="xsm" aria-hidden />,
401
+ onSelect: () =>
402
+ c.onSortChange(c.sort.filter(e => e.sortKey !== sortKey)),
403
+ });
404
+ }
405
+ return actions;
406
+ };
407
+
408
+ // Merge with any actions a prior plugin contributed (array or getter),
409
+ // resolving both lazily at open time.
410
+ const priorActions = props.contextMenuActions;
363
411
  return {
364
412
  ...props,
365
413
  htmlProps: {
@@ -375,6 +423,10 @@ export function useTableSortable<
375
423
  {props.content}
376
424
  </SortHeaderButton>
377
425
  ),
426
+ contextMenuActions: () => [
427
+ ...resolveContextActions(priorActions),
428
+ ...getSortActions(),
429
+ ],
378
430
  };
379
431
  },
380
432
  }),