@astryxdesign/core 0.4.7 → 0.5.0-canary.055e75f

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 (597) hide show
  1. package/CHANGELOG.md +161 -1
  2. package/dist/AlertDialog/AlertDialog.d.ts +1 -1
  3. package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
  4. package/dist/AlertDialog/AlertDialog.js +45 -20
  5. package/dist/AppShell/AppShell.d.ts.map +1 -1
  6. package/dist/AppShell/AppShell.js +3 -2
  7. package/dist/AspectRatio/AspectRatio.d.ts +24 -0
  8. package/dist/AspectRatio/AspectRatio.d.ts.map +1 -1
  9. package/dist/AspectRatio/AspectRatio.js +23 -4
  10. package/dist/Avatar/Avatar.d.ts +25 -1
  11. package/dist/Avatar/Avatar.d.ts.map +1 -1
  12. package/dist/Avatar/Avatar.js +58 -19
  13. package/dist/Avatar/index.d.ts +2 -2
  14. package/dist/Avatar/index.d.ts.map +1 -1
  15. package/dist/Avatar/index.js +1 -1
  16. package/dist/AvatarGroup/AvatarGroup.d.ts +9 -2
  17. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  18. package/dist/AvatarGroup/AvatarGroup.js +8 -4
  19. package/dist/AvatarGroup/AvatarGroupContext.d.ts +2 -1
  20. package/dist/AvatarGroup/AvatarGroupContext.d.ts.map +1 -1
  21. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  22. package/dist/AvatarGroup/AvatarGroupOverflow.js +10 -6
  23. package/dist/Banner/Banner.d.ts +40 -15
  24. package/dist/Banner/Banner.d.ts.map +1 -1
  25. package/dist/Banner/Banner.js +51 -18
  26. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  27. package/dist/BottomSheet/BottomSheet.js +17 -4
  28. package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
  29. package/dist/BottomSheet/BottomSheetSwitcher.js +3 -2
  30. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  31. package/dist/Breadcrumbs/BreadcrumbItem.js +11 -10
  32. package/dist/Button/Button.d.ts.map +1 -1
  33. package/dist/Button/Button.js +11 -6
  34. package/dist/ButtonGroup/ButtonGroup.d.ts +5 -1
  35. package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
  36. package/dist/ButtonGroup/ButtonGroup.js +26 -7
  37. package/dist/Calendar/Calendar.d.ts +3 -1
  38. package/dist/Calendar/Calendar.d.ts.map +1 -1
  39. package/dist/Calendar/Calendar.js +14 -15
  40. package/dist/Calendar/getInitialFocusDate.d.ts +46 -0
  41. package/dist/Calendar/getInitialFocusDate.d.ts.map +1 -0
  42. package/dist/Calendar/getInitialFocusDate.js +62 -0
  43. package/dist/Calendar/styles.d.ts +5 -14
  44. package/dist/Calendar/styles.d.ts.map +1 -1
  45. package/dist/Calendar/styles.js +15 -15
  46. package/dist/Card/Card.d.ts +6 -9
  47. package/dist/Card/Card.d.ts.map +1 -1
  48. package/dist/Card/Card.js +6 -6
  49. package/dist/Carousel/Carousel.d.ts.map +1 -1
  50. package/dist/Carousel/Carousel.js +3 -3
  51. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  52. package/dist/Chat/ChatComposerInput.js +2 -3
  53. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  54. package/dist/Chat/ChatLayout.js +3 -3
  55. package/dist/Chat/ChatMessageList.d.ts +22 -3
  56. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  57. package/dist/Chat/ChatMessageList.js +6 -3
  58. package/dist/Chat/ChatTokenizedText.d.ts +2 -0
  59. package/dist/Chat/ChatTokenizedText.d.ts.map +1 -1
  60. package/dist/Chat/ChatTokenizedText.js +11 -6
  61. package/dist/Chat/useChatComposerTokens.js +1 -1
  62. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  63. package/dist/CheckboxInput/CheckboxInput.js +10 -3
  64. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  65. package/dist/ClickableCard/ClickableCard.js +3 -3
  66. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  67. package/dist/CodeBlock/CodeBlock.js +15 -4
  68. package/dist/CodeBlock/highlightRanges.js +1 -1
  69. package/dist/CodeBlock/highlightStyles.js +13 -13
  70. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  71. package/dist/CommandPalette/CommandPaletteInput.js +3 -2
  72. package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
  73. package/dist/CommandPalette/CommandPaletteItem.js +3 -2
  74. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  75. package/dist/ContextMenu/ContextMenu.js +4 -3
  76. package/dist/DateInput/DateInput.d.ts +43 -0
  77. package/dist/DateInput/DateInput.d.ts.map +1 -1
  78. package/dist/DateInput/DateInput.js +22 -2
  79. package/dist/DateInput/NativeDateField.d.ts +10 -0
  80. package/dist/DateInput/NativeDateField.d.ts.map +1 -0
  81. package/dist/DateInput/NativeDateField.js +494 -0
  82. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  83. package/dist/DateInput/TouchDateField.js +82 -23
  84. package/dist/DateInput/index.d.ts +1 -1
  85. package/dist/DateInput/index.d.ts.map +1 -1
  86. package/dist/DateInput/nativeDateSegments.d.ts +22 -0
  87. package/dist/DateInput/nativeDateSegments.d.ts.map +1 -0
  88. package/dist/DateInput/nativeDateSegments.js +111 -0
  89. package/dist/DateTimeInput/DateTimeInput.d.ts +21 -1
  90. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  91. package/dist/DateTimeInput/DateTimeInput.js +406 -12
  92. package/dist/DateTimeInput/index.d.ts +1 -1
  93. package/dist/DateTimeInput/index.d.ts.map +1 -1
  94. package/dist/Dialog/Dialog.d.ts +21 -1
  95. package/dist/Dialog/Dialog.d.ts.map +1 -1
  96. package/dist/Dialog/Dialog.js +110 -58
  97. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  98. package/dist/DropdownMenu/DropdownMenuSubMenu.js +6 -5
  99. package/dist/Field/FieldLabel.d.ts.map +1 -1
  100. package/dist/Field/FieldLabel.js +9 -1
  101. package/dist/FileInput/FileInput.d.ts.map +1 -1
  102. package/dist/FileInput/FileInput.js +3 -2
  103. package/dist/Heading/Heading.d.ts.map +1 -1
  104. package/dist/Heading/Heading.js +6 -2
  105. package/dist/HoverCard/HoverCard.d.ts +6 -0
  106. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  107. package/dist/HoverCard/HoverCard.js +104 -3
  108. package/dist/HoverCard/useHoverCard.d.ts +19 -2
  109. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  110. package/dist/HoverCard/useHoverCard.js +74 -26
  111. package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -1
  112. package/dist/Indicator/CheckboxIndicator.js +6 -2
  113. package/dist/Item/Item.d.ts.map +1 -1
  114. package/dist/Item/Item.js +4 -2
  115. package/dist/Kbd/Kbd.d.ts.map +1 -1
  116. package/dist/Kbd/Kbd.js +2 -19
  117. package/dist/Layer/LayerDepthContext.d.ts +52 -0
  118. package/dist/Layer/LayerDepthContext.d.ts.map +1 -0
  119. package/dist/Layer/LayerDepthContext.js +66 -0
  120. package/dist/Layer/index.d.ts +3 -0
  121. package/dist/Layer/index.d.ts.map +1 -1
  122. package/dist/Layer/index.js +4 -0
  123. package/dist/Layer/layerStack.d.ts +98 -0
  124. package/dist/Layer/layerStack.d.ts.map +1 -0
  125. package/dist/Layer/layerStack.js +306 -0
  126. package/dist/Layer/useLayerDismissal.d.ts +93 -0
  127. package/dist/Layer/useLayerDismissal.d.ts.map +1 -0
  128. package/dist/Layer/useLayerDismissal.js +91 -0
  129. package/dist/Lightbox/Lightbox.d.ts +1 -0
  130. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  131. package/dist/Lightbox/Lightbox.js +103 -81
  132. package/dist/Markdown/Markdown.d.ts.map +1 -1
  133. package/dist/Markdown/Markdown.js +9 -4
  134. package/dist/Markdown/index.d.ts +1 -1
  135. package/dist/Markdown/index.d.ts.map +1 -1
  136. package/dist/Markdown/parser.d.ts +38 -1
  137. package/dist/Markdown/parser.d.ts.map +1 -1
  138. package/dist/Markdown/parser.js +182 -32
  139. package/dist/MobileNav/MobileNav.d.ts +6 -1
  140. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  141. package/dist/MobileNav/MobileNav.js +61 -36
  142. package/dist/MultiSelector/MultiSelector.d.ts +32 -1
  143. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  144. package/dist/MultiSelector/MultiSelector.js +63 -11
  145. package/dist/MultiSelector/index.d.ts +1 -1
  146. package/dist/MultiSelector/index.d.ts.map +1 -1
  147. package/dist/NavIcon/NavIcon.d.ts.map +1 -1
  148. package/dist/NavIcon/NavIcon.js +5 -1
  149. package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
  150. package/dist/NavMenu/NavHeadingMenu.js +3 -2
  151. package/dist/NumberInput/NumberInput.d.ts +6 -1
  152. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  153. package/dist/NumberInput/NumberInput.js +54 -104
  154. package/dist/NumberInput/numberInputCommit.d.ts +34 -0
  155. package/dist/NumberInput/numberInputCommit.d.ts.map +1 -0
  156. package/dist/NumberInput/numberInputCommit.js +71 -0
  157. package/dist/NumberInput/numberParser.d.ts +64 -0
  158. package/dist/NumberInput/numberParser.d.ts.map +1 -0
  159. package/dist/NumberInput/numberParser.js +350 -0
  160. package/dist/Outline/Outline.d.ts.map +1 -1
  161. package/dist/Outline/Outline.js +3 -2
  162. package/dist/OverflowList/OverflowList.d.ts.map +1 -1
  163. package/dist/OverflowList/OverflowList.js +3 -2
  164. package/dist/Overlay/Overlay.d.ts.map +1 -1
  165. package/dist/Overlay/Overlay.js +3 -2
  166. package/dist/Popover/usePopover.d.ts.map +1 -1
  167. package/dist/Popover/usePopover.js +20 -17
  168. package/dist/PowerSearch/PowerSearch.d.ts +8 -2
  169. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  170. package/dist/PowerSearch/PowerSearch.js +19 -6
  171. package/dist/PowerSearch/PowerSearchEditPopover.d.ts +3 -1
  172. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  173. package/dist/PowerSearch/PowerSearchEditPopover.js +28 -6
  174. package/dist/PowerSearch/PowerSearchValueEditor.d.ts +3 -1
  175. package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
  176. package/dist/PowerSearch/PowerSearchValueEditor.js +110 -27
  177. package/dist/PowerSearch/types.d.ts +2 -0
  178. package/dist/PowerSearch/types.d.ts.map +1 -1
  179. package/dist/PowerSearch/usePowerSearchSource.d.ts +6 -1
  180. package/dist/PowerSearch/usePowerSearchSource.d.ts.map +1 -1
  181. package/dist/PowerSearch/usePowerSearchSource.js +14 -5
  182. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  183. package/dist/ProgressBar/ProgressBar.js +18 -5
  184. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  185. package/dist/Resizable/ResizeHandle.js +3 -2
  186. package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  187. package/dist/SegmentedControl/SegmentedControl.js +3 -2
  188. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  189. package/dist/SelectableCard/SelectableCard.js +3 -3
  190. package/dist/Selector/Selector.d.ts +17 -0
  191. package/dist/Selector/Selector.d.ts.map +1 -1
  192. package/dist/Selector/Selector.js +81 -14
  193. package/dist/SideNav/SideNav.d.ts.map +1 -1
  194. package/dist/SideNav/SideNav.js +4 -3
  195. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  196. package/dist/SideNav/SideNavHeading.js +8 -7
  197. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  198. package/dist/SideNav/SideNavItem.js +4 -3
  199. package/dist/Slider/Slider.d.ts.map +1 -1
  200. package/dist/Slider/Slider.js +37 -5
  201. package/dist/Spinner/Spinner.d.ts +3 -3
  202. package/dist/Spinner/Spinner.d.ts.map +1 -1
  203. package/dist/Spinner/Spinner.js +130 -78
  204. package/dist/StatusDot/StatusDot.d.ts.map +1 -1
  205. package/dist/StatusDot/StatusDot.js +6 -1
  206. package/dist/Stepper/Step.d.ts +140 -0
  207. package/dist/Stepper/Step.d.ts.map +1 -0
  208. package/dist/Stepper/Step.js +1045 -0
  209. package/dist/Stepper/StepStatus.d.ts +24 -0
  210. package/dist/Stepper/StepStatus.d.ts.map +1 -0
  211. package/dist/Stepper/StepStatus.js +1 -0
  212. package/dist/Stepper/Stepper.d.ts +93 -0
  213. package/dist/Stepper/Stepper.d.ts.map +1 -0
  214. package/dist/Stepper/Stepper.js +184 -0
  215. package/dist/Stepper/StepperContext.d.ts +41 -0
  216. package/dist/Stepper/StepperContext.d.ts.map +1 -0
  217. package/dist/Stepper/StepperContext.js +34 -0
  218. package/dist/Stepper/index.d.ts +8 -0
  219. package/dist/Stepper/index.d.ts.map +1 -0
  220. package/dist/Stepper/index.js +7 -0
  221. package/dist/Stepper/stepper.stylex.d.ts +15 -0
  222. package/dist/Stepper/stepper.stylex.d.ts.map +1 -0
  223. package/dist/Stepper/stepper.stylex.js +20 -0
  224. package/dist/Switch/Switch.d.ts.map +1 -1
  225. package/dist/Switch/Switch.js +8 -3
  226. package/dist/TabList/Tab.d.ts +15 -2
  227. package/dist/TabList/Tab.d.ts.map +1 -1
  228. package/dist/TabList/Tab.js +32 -7
  229. package/dist/TabList/TabList.d.ts +46 -7
  230. package/dist/TabList/TabList.d.ts.map +1 -1
  231. package/dist/TabList/TabList.js +353 -23
  232. package/dist/TabList/TabListContext.d.ts +11 -1
  233. package/dist/TabList/TabListContext.d.ts.map +1 -1
  234. package/dist/TabList/TabListContext.js +11 -2
  235. package/dist/TabList/TabMenu.d.ts.map +1 -1
  236. package/dist/TabList/TabMenu.js +3 -2
  237. package/dist/TabList/index.d.ts +2 -2
  238. package/dist/TabList/index.d.ts.map +1 -1
  239. package/dist/Table/BaseTable.d.ts.map +1 -1
  240. package/dist/Table/BaseTable.js +10 -2
  241. package/dist/Table/Table.d.ts.map +1 -1
  242. package/dist/Table/Table.js +3 -6
  243. package/dist/Table/TableRow.d.ts +16 -5
  244. package/dist/Table/TableRow.d.ts.map +1 -1
  245. package/dist/Table/TableRow.js +16 -5
  246. package/dist/Table/plugins/filtering/useTableFiltering.d.ts.map +1 -1
  247. package/dist/Table/plugins/filtering/useTableFiltering.js +73 -4
  248. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  249. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +20 -8
  250. package/dist/Table/plugins/pagination/useTablePagination.d.ts +3 -0
  251. package/dist/Table/plugins/pagination/useTablePagination.d.ts.map +1 -1
  252. package/dist/Table/plugins/pagination/useTablePagination.js +21 -4
  253. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  254. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +7 -2
  255. package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts.map +1 -1
  256. package/dist/Table/plugins/rowStatus/useTableRowStatus.js +10 -3
  257. package/dist/Table/plugins/selection/useTableSelection.d.ts +16 -0
  258. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  259. package/dist/Table/plugins/selection/useTableSelection.js +19 -5
  260. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
  261. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +3 -4
  262. package/dist/Table/types.d.ts +22 -4
  263. package/dist/Table/types.d.ts.map +1 -1
  264. package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
  265. package/dist/Table/useBaseTablePlugins.js +5 -0
  266. package/dist/Text/Text.d.ts.map +1 -1
  267. package/dist/Text/Text.js +6 -2
  268. package/dist/TextArea/TextArea.d.ts.map +1 -1
  269. package/dist/TextArea/TextArea.js +9 -3
  270. package/dist/TextInput/TextInput.d.ts.map +1 -1
  271. package/dist/TextInput/TextInput.js +3 -2
  272. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  273. package/dist/TimeInput/TimeInput.js +3 -2
  274. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  275. package/dist/Timestamp/Timestamp.js +5 -3
  276. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  277. package/dist/Toast/ToastViewport.js +27 -8
  278. package/dist/Token/TokenLink.d.ts.map +1 -1
  279. package/dist/Token/TokenLink.js +2 -2
  280. package/dist/Tokenizer/Tokenizer.d.ts +3 -1
  281. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  282. package/dist/Tokenizer/Tokenizer.js +2 -0
  283. package/dist/Tooltip/Tooltip.d.ts +5 -0
  284. package/dist/Tooltip/Tooltip.d.ts.map +1 -1
  285. package/dist/Tooltip/useTooltip.d.ts +5 -0
  286. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  287. package/dist/Tooltip/useTooltip.js +39 -24
  288. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  289. package/dist/TopNav/TopNavHeading.js +5 -4
  290. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  291. package/dist/TopNav/TopNavMegaMenu.js +3 -3
  292. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  293. package/dist/TopNav/TopNavMenu.js +4 -3
  294. package/dist/Typeahead/BaseTypeahead.d.ts +2 -0
  295. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  296. package/dist/Typeahead/BaseTypeahead.js +68 -29
  297. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  298. package/dist/Typeahead/Typeahead.js +3 -2
  299. package/dist/astryx.css +98 -7
  300. package/dist/hooks/index.d.ts +1 -0
  301. package/dist/hooks/index.d.ts.map +1 -1
  302. package/dist/hooks/index.js +1 -0
  303. package/dist/hooks/useFocusTrap.d.ts +7 -4
  304. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  305. package/dist/hooks/useFocusTrap.js +60 -95
  306. package/dist/hooks/useHotkeys.d.ts.map +1 -1
  307. package/dist/hooks/useHotkeys.js +3 -18
  308. package/dist/hooks/useMergedRefs.d.ts +18 -0
  309. package/dist/hooks/useMergedRefs.d.ts.map +1 -0
  310. package/dist/hooks/useMergedRefs.js +25 -0
  311. package/dist/index.d.ts +1 -0
  312. package/dist/index.d.ts.map +1 -1
  313. package/dist/index.js +1 -0
  314. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  315. package/dist/theme/derivedVarRegistry.js +24 -4
  316. package/dist/theme/syntax/tokens.d.ts +1 -1
  317. package/dist/theme/syntax/tokens.d.ts.map +1 -1
  318. package/dist/theme/syntax/tokens.js +5 -2
  319. package/dist/utils/groupItems.d.ts +5 -1
  320. package/dist/utils/groupItems.d.ts.map +1 -1
  321. package/dist/utils/groupItems.js +9 -9
  322. package/dist/utils/index.d.ts +1 -1
  323. package/dist/utils/index.d.ts.map +1 -1
  324. package/dist/utils/isApplePlatform.d.ts +18 -0
  325. package/dist/utils/isApplePlatform.d.ts.map +1 -0
  326. package/dist/utils/isApplePlatform.js +37 -0
  327. package/dist/utils/sharedResizeObserver.d.ts.map +1 -1
  328. package/dist/utils/sharedResizeObserver.js +10 -1
  329. package/dist/utils/timeParser.d.ts +1 -1
  330. package/dist/utils/timeParser.d.ts.map +1 -1
  331. package/dist/utils/timeParser.js +26 -12
  332. package/locales/en.json +154 -10
  333. package/locales/pseudo.json +108 -0
  334. package/package.json +8 -3
  335. package/src/AlertDialog/AlertDialog.doc.mjs +114 -30
  336. package/src/AlertDialog/AlertDialog.test.tsx +211 -2
  337. package/src/AlertDialog/AlertDialog.tsx +62 -20
  338. package/src/AppShell/AppShell.tsx +3 -2
  339. package/src/AspectRatio/AspectRatio.doc.mjs +6 -3
  340. package/src/AspectRatio/AspectRatio.test.tsx +57 -10
  341. package/src/AspectRatio/AspectRatio.tsx +40 -1
  342. package/src/Avatar/Avatar.doc.mjs +14 -3
  343. package/src/Avatar/Avatar.test.tsx +97 -0
  344. package/src/Avatar/Avatar.tsx +125 -52
  345. package/src/Avatar/index.ts +2 -2
  346. package/src/AvatarGroup/AvatarGroup.doc.mjs +8 -2
  347. package/src/AvatarGroup/AvatarGroup.test.tsx +24 -0
  348. package/src/AvatarGroup/AvatarGroup.tsx +15 -6
  349. package/src/AvatarGroup/AvatarGroupContext.ts +5 -3
  350. package/src/AvatarGroup/AvatarGroupOverflow.tsx +10 -4
  351. package/src/Banner/Banner.doc.mjs +13 -11
  352. package/src/Banner/Banner.test.tsx +102 -15
  353. package/src/Banner/Banner.tsx +72 -25
  354. package/src/BottomSheet/BottomSheet.test.tsx +123 -0
  355. package/src/BottomSheet/BottomSheet.tsx +17 -4
  356. package/src/BottomSheet/BottomSheetSwitcher.tsx +3 -2
  357. package/src/Breadcrumbs/BreadcrumbItem.tsx +9 -5
  358. package/src/Button/Button.doc.mjs +24 -1
  359. package/src/Button/Button.test.tsx +32 -4
  360. package/src/Button/Button.tsx +12 -5
  361. package/src/ButtonGroup/ButtonGroup.doc.mjs +10 -1
  362. package/src/ButtonGroup/ButtonGroup.test.tsx +404 -1
  363. package/src/ButtonGroup/ButtonGroup.tsx +23 -5
  364. package/src/Calendar/Calendar.doc.mjs +4 -3
  365. package/src/Calendar/Calendar.test.tsx +103 -0
  366. package/src/Calendar/Calendar.tsx +19 -16
  367. package/src/Calendar/getInitialFocusDate.test.ts +94 -0
  368. package/src/Calendar/getInitialFocusDate.ts +93 -0
  369. package/src/Calendar/styles.ts +49 -31
  370. package/src/Card/Card.doc.mjs +10 -7
  371. package/src/Card/Card.test.tsx +44 -19
  372. package/src/Card/Card.tsx +12 -32
  373. package/src/Carousel/Carousel.tsx +3 -2
  374. package/src/Chat/ChatComposerInput.tsx +5 -1
  375. package/src/Chat/ChatLayout.tsx +3 -2
  376. package/src/Chat/ChatMessageList.doc.mjs +9 -1
  377. package/src/Chat/ChatMessageList.test.tsx +46 -0
  378. package/src/Chat/ChatMessageList.tsx +28 -4
  379. package/src/Chat/ChatTokenizedText.tsx +17 -10
  380. package/src/Chat/useChatComposerTokens.ts +1 -1
  381. package/src/CheckboxInput/CheckboxInput.doc.mjs +2 -0
  382. package/src/CheckboxInput/CheckboxInput.test.tsx +15 -0
  383. package/src/CheckboxInput/CheckboxInput.tsx +8 -2
  384. package/src/ClickableCard/ClickableCard.tsx +3 -2
  385. package/src/CodeBlock/CodeBlock.doc.mjs +16 -4
  386. package/src/CodeBlock/CodeBlock.test.tsx +37 -0
  387. package/src/CodeBlock/CodeBlock.tsx +20 -4
  388. package/src/CodeBlock/highlightRanges.ts +1 -1
  389. package/src/CodeBlock/highlightStyles.ts +13 -13
  390. package/src/CommandPalette/CommandPaletteInput.tsx +3 -2
  391. package/src/CommandPalette/CommandPaletteItem.tsx +3 -2
  392. package/src/ContextMenu/ContextMenu.doc.mjs +5 -0
  393. package/src/ContextMenu/ContextMenu.tsx +4 -3
  394. package/src/DateInput/DateInput.doc.mjs +16 -0
  395. package/src/DateInput/DateInput.tsx +55 -2
  396. package/src/DateInput/DateInputTouch.test.tsx +146 -32
  397. package/src/DateInput/NativeDateField.test.tsx +635 -0
  398. package/src/DateInput/NativeDateField.tsx +641 -0
  399. package/src/DateInput/TouchDateField.tsx +108 -24
  400. package/src/DateInput/index.ts +1 -0
  401. package/src/DateInput/nativeDateSegments.ts +127 -0
  402. package/src/DateTimeInput/DateTimeInput.doc.mjs +18 -0
  403. package/src/DateTimeInput/DateTimeInput.test.tsx +1088 -0
  404. package/src/DateTimeInput/DateTimeInput.tsx +556 -24
  405. package/src/DateTimeInput/index.ts +1 -0
  406. package/src/Dialog/Dialog.doc.mjs +8 -3
  407. package/src/Dialog/Dialog.test.tsx +429 -2
  408. package/src/Dialog/Dialog.tsx +133 -58
  409. package/src/DropdownMenu/DropdownMenu.doc.mjs +6 -0
  410. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +8 -5
  411. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +8 -11
  412. package/src/Field/Field.doc.mjs +13 -2
  413. package/src/Field/FieldLabel.test.tsx +29 -0
  414. package/src/Field/FieldLabel.tsx +7 -0
  415. package/src/FileInput/FileInput.tsx +3 -2
  416. package/src/Heading/Heading.test.tsx +23 -1
  417. package/src/Heading/Heading.tsx +6 -2
  418. package/src/HoverCard/HoverCard.doc.mjs +13 -2
  419. package/src/HoverCard/HoverCard.test.tsx +154 -4
  420. package/src/HoverCard/HoverCard.tsx +143 -3
  421. package/src/HoverCard/useHoverCard.tsx +104 -33
  422. package/src/Indicator/CheckboxIndicator.tsx +14 -8
  423. package/src/Indicator/Indicator.doc.mjs +2 -0
  424. package/src/Item/Item.tsx +5 -4
  425. package/src/Kbd/Kbd.tsx +2 -19
  426. package/src/Layer/LayerDepthContext.tsx +62 -0
  427. package/src/Layer/index.ts +9 -0
  428. package/src/Layer/layerDismissalFamilies.test.tsx +359 -0
  429. package/src/Layer/layerDismissalInvariants.test.tsx +417 -0
  430. package/src/Layer/layerStack.ts +362 -0
  431. package/src/Layer/useLayer.test.tsx +62 -14
  432. package/src/Layer/useLayerDismissal.test.tsx +469 -0
  433. package/src/Layer/useLayerDismissal.ts +173 -0
  434. package/src/Layout/Layout.doc.mjs +2 -2
  435. package/src/Lightbox/Lightbox.doc.mjs +12 -0
  436. package/src/Lightbox/Lightbox.tsx +124 -102
  437. package/src/Link/Link.doc.mjs +39 -0
  438. package/src/Markdown/Markdown.doc.mjs +5 -0
  439. package/src/Markdown/Markdown.tsx +9 -4
  440. package/src/Markdown/incremental.test.ts +16 -2
  441. package/src/Markdown/index.ts +1 -0
  442. package/src/Markdown/parser.perf.test.ts +96 -1
  443. package/src/Markdown/parser.test.ts +178 -2
  444. package/src/Markdown/parser.ts +253 -32
  445. package/src/MobileNav/MobileNav.tsx +62 -36
  446. package/src/MoreMenu/MoreMenu.doc.mjs +7 -1
  447. package/src/MultiSelector/MultiSelector.doc.mjs +49 -1
  448. package/src/MultiSelector/MultiSelector.test.tsx +277 -0
  449. package/src/MultiSelector/MultiSelector.tsx +142 -11
  450. package/src/MultiSelector/index.ts +1 -0
  451. package/src/NavIcon/NavIcon.doc.mjs +8 -2
  452. package/src/NavIcon/NavIcon.test.tsx +9 -0
  453. package/src/NavIcon/NavIcon.tsx +5 -1
  454. package/src/NavMenu/NavHeadingMenu.tsx +3 -2
  455. package/src/NumberInput/NumberInput.doc.mjs +31 -7
  456. package/src/NumberInput/NumberInput.test.tsx +436 -8
  457. package/src/NumberInput/NumberInput.tsx +62 -114
  458. package/src/NumberInput/numberInputCommit.test.ts +72 -0
  459. package/src/NumberInput/numberInputCommit.ts +103 -0
  460. package/src/NumberInput/numberParser.docblock.test.ts +234 -0
  461. package/src/NumberInput/numberParser.test.ts +222 -0
  462. package/src/NumberInput/numberParser.ts +403 -0
  463. package/src/Outline/Outline.tsx +3 -2
  464. package/src/OverflowList/OverflowList.tsx +3 -2
  465. package/src/Overlay/Overlay.tsx +3 -2
  466. package/src/Pagination/Pagination.test.tsx +3 -2
  467. package/src/Popover/usePopover.tsx +31 -28
  468. package/src/PowerSearch/PowerSearch.doc.mjs +160 -28
  469. package/src/PowerSearch/PowerSearch.test.tsx +240 -1
  470. package/src/PowerSearch/PowerSearch.tsx +34 -5
  471. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +288 -0
  472. package/src/PowerSearch/PowerSearchEditPopover.tsx +29 -2
  473. package/src/PowerSearch/PowerSearchValueEditor.test.tsx +111 -1
  474. package/src/PowerSearch/PowerSearchValueEditor.tsx +124 -10
  475. package/src/PowerSearch/types.ts +2 -0
  476. package/src/PowerSearch/usePowerSearchSource.test.ts +82 -2
  477. package/src/PowerSearch/usePowerSearchSource.ts +13 -3
  478. package/src/ProgressBar/ProgressBar.doc.mjs +42 -6
  479. package/src/ProgressBar/ProgressBar.test.tsx +24 -0
  480. package/src/ProgressBar/ProgressBar.tsx +28 -8
  481. package/src/Resizable/ResizeHandle.tsx +3 -2
  482. package/src/SegmentedControl/SegmentedControl.tsx +3 -2
  483. package/src/SelectableCard/SelectableCard.tsx +3 -2
  484. package/src/Selector/Selector.doc.mjs +26 -1
  485. package/src/Selector/Selector.test.tsx +311 -1
  486. package/src/Selector/Selector.tsx +139 -16
  487. package/src/SideNav/SideNav.doc.mjs +6 -6
  488. package/src/SideNav/SideNav.tsx +4 -2
  489. package/src/SideNav/SideNavHeading.tsx +12 -12
  490. package/src/SideNav/SideNavItem.tsx +4 -2
  491. package/src/Slider/Slider.test.tsx +106 -1
  492. package/src/Slider/Slider.tsx +55 -3
  493. package/src/Spinner/Spinner.test.tsx +147 -1
  494. package/src/Spinner/Spinner.tsx +120 -101
  495. package/src/StatusDot/StatusDot.doc.mjs +8 -2
  496. package/src/StatusDot/StatusDot.test.tsx +9 -0
  497. package/src/StatusDot/StatusDot.tsx +7 -1
  498. package/src/Stepper/Step.doc.mjs +98 -0
  499. package/src/Stepper/Step.tsx +1638 -0
  500. package/src/Stepper/StepStatus.ts +26 -0
  501. package/src/Stepper/Stepper.doc.mjs +370 -0
  502. package/src/Stepper/Stepper.test.tsx +1024 -0
  503. package/src/Stepper/Stepper.tsx +258 -0
  504. package/src/Stepper/StepperContext.ts +71 -0
  505. package/src/Stepper/index.ts +18 -0
  506. package/src/Stepper/stepper.stylex.ts +19 -0
  507. package/src/Switch/Switch.doc.mjs +2 -0
  508. package/src/Switch/Switch.test.tsx +10 -0
  509. package/src/Switch/Switch.tsx +6 -2
  510. package/src/TabList/Tab.doc.mjs +13 -1
  511. package/src/TabList/Tab.tsx +67 -7
  512. package/src/TabList/TabList.doc.mjs +22 -6
  513. package/src/TabList/TabList.test.tsx +559 -0
  514. package/src/TabList/TabList.tsx +490 -22
  515. package/src/TabList/TabListContext.ts +13 -2
  516. package/src/TabList/TabMenu.tsx +3 -2
  517. package/src/TabList/index.ts +6 -2
  518. package/src/Table/BaseTable.tsx +12 -4
  519. package/src/Table/Table.doc.mjs +9 -2
  520. package/src/Table/Table.test.tsx +132 -14
  521. package/src/Table/Table.tsx +3 -8
  522. package/src/Table/TableBody.doc.mjs +40 -0
  523. package/src/Table/TableFooter.doc.mjs +40 -0
  524. package/src/Table/TableHeader.doc.mjs +40 -0
  525. package/src/Table/TableRow.tsx +16 -5
  526. package/src/Table/plugins/filtering/useTableFiltering.test.tsx +44 -6
  527. package/src/Table/plugins/filtering/useTableFiltering.tsx +100 -4
  528. package/src/Table/plugins/groupedRows/useTableGroupedRows-perf.test.tsx +112 -0
  529. package/src/Table/plugins/groupedRows/useTableGroupedRows.test.tsx +100 -0
  530. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +17 -8
  531. package/src/Table/plugins/pagination/useTablePagination.test.tsx +34 -4
  532. package/src/Table/plugins/pagination/useTablePagination.tsx +35 -3
  533. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +9 -2
  534. package/src/Table/plugins/rowStatus/useTableRowStatus.test.tsx +13 -7
  535. package/src/Table/plugins/rowStatus/useTableRowStatus.tsx +12 -3
  536. package/src/Table/plugins/selection/useTableSelection.test.tsx +76 -0
  537. package/src/Table/plugins/selection/useTableSelection.tsx +40 -7
  538. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +1 -2
  539. package/src/Table/types.ts +22 -4
  540. package/src/Table/useBaseTablePlugins.ts +5 -0
  541. package/src/Table/useTableGroupedRows.doc.mjs +5 -4
  542. package/src/Table/useTablePagination.doc.mjs +7 -0
  543. package/src/Table/useTableRowStatus.doc.mjs +1 -1
  544. package/src/Table/useTableSelection.doc.mjs +31 -0
  545. package/src/Text/Text.test.tsx +23 -1
  546. package/src/Text/Text.tsx +6 -2
  547. package/src/TextArea/TextArea.doc.mjs +8 -2
  548. package/src/TextArea/TextArea.test.tsx +11 -0
  549. package/src/TextArea/TextArea.tsx +15 -8
  550. package/src/TextInput/TextInput.doc.mjs +10 -0
  551. package/src/TextInput/TextInput.tsx +3 -2
  552. package/src/Thumbnail/Thumbnail.doc.mjs +1 -1
  553. package/src/TimeInput/TimeInput.tsx +2 -2
  554. package/src/Timestamp/Timestamp.test.tsx +18 -0
  555. package/src/Timestamp/Timestamp.tsx +4 -2
  556. package/src/Toast/Toast.doc.mjs +6 -0
  557. package/src/Toast/ToastViewport.tsx +17 -1
  558. package/src/Token/TokenLink.tsx +2 -2
  559. package/src/Tokenizer/Tokenizer.doc.mjs +27 -0
  560. package/src/Tokenizer/Tokenizer.tsx +4 -0
  561. package/src/Toolbar/Toolbar.doc.mjs +5 -0
  562. package/src/Tooltip/Tooltip.doc.mjs +5 -0
  563. package/src/Tooltip/Tooltip.test.tsx +32 -0
  564. package/src/Tooltip/Tooltip.tsx +5 -0
  565. package/src/Tooltip/useTooltip.tsx +47 -24
  566. package/src/TopNav/TopNavHeading.tsx +5 -4
  567. package/src/TopNav/TopNavMegaMenu.tsx +3 -2
  568. package/src/TopNav/TopNavMenu.tsx +4 -3
  569. package/src/Typeahead/BaseTypeahead.doc.mjs +11 -0
  570. package/src/Typeahead/BaseTypeahead.tsx +85 -33
  571. package/src/Typeahead/Typeahead.doc.mjs +5 -0
  572. package/src/Typeahead/Typeahead.test.tsx +49 -0
  573. package/src/Typeahead/Typeahead.tsx +3 -2
  574. package/src/hooks/index.ts +2 -0
  575. package/src/hooks/useContainerReveal.doc.mjs +2 -2
  576. package/src/hooks/useFocusTrap.test.tsx +14 -0
  577. package/src/hooks/useFocusTrap.ts +62 -111
  578. package/src/hooks/useFocusTrapEscapeShim.test.tsx +165 -0
  579. package/src/hooks/useHotkeys.ts +3 -18
  580. package/src/hooks/useMergedRefs.doc.mjs +79 -0
  581. package/src/hooks/useMergedRefs.test.tsx +62 -0
  582. package/src/hooks/useMergedRefs.ts +36 -0
  583. package/src/index.ts +1 -0
  584. package/src/raw-import.d.ts +14 -0
  585. package/src/theme/MediaTheme.doc.mjs +5 -5
  586. package/src/theme/derivedVarRegistry.test.ts +19 -3
  587. package/src/theme/derivedVarRegistry.ts +23 -4
  588. package/src/theme/generateThemeRules.test.ts +37 -0
  589. package/src/theme/syntax/tokens.ts +5 -2
  590. package/src/utils/groupItems.ts +12 -6
  591. package/src/utils/index.ts +1 -1
  592. package/src/utils/isApplePlatform.test.ts +61 -0
  593. package/src/utils/isApplePlatform.ts +37 -0
  594. package/src/utils/sharedResizeObserver.ts +10 -2
  595. package/src/utils/timeParser.test.ts +6 -1
  596. package/src/utils/timeParser.ts +35 -13
  597. package/src/__tests__/inputWidthContract.test.tsx +0 -69
@@ -13,6 +13,7 @@ import {act, render, renderHook, screen, within} from '@testing-library/react';
13
13
  import userEvent from '@testing-library/user-event';
14
14
  import {Table} from '../../Table';
15
15
  import {useTableSelection} from './useTableSelection';
16
+ import {colorVars} from '../../../theme/tokens.stylex';
16
17
  import type {BodyRowRenderProps, TableColumn} from '../../types';
17
18
 
18
19
  // =============================================================================
@@ -41,10 +42,12 @@ function SelectionTable({
41
42
  getIsItemSelectable,
42
43
  getIsItemEnabled,
43
44
  getRowLabel,
45
+ hasRowHighlight,
44
46
  }: {
45
47
  getIsItemSelectable?: (item: SelectableUser) => boolean;
46
48
  getIsItemEnabled?: (item: SelectableUser) => boolean;
47
49
  getRowLabel?: (item: SelectableUser) => string;
50
+ hasRowHighlight?: boolean;
48
51
  }) {
49
52
  const [selectedKeys, setSelectedKeys] = useState<Set<string>>(new Set());
50
53
 
@@ -78,6 +81,7 @@ function SelectionTable({
78
81
  getIsItemSelectable,
79
82
  getIsItemEnabled,
80
83
  getRowLabel,
84
+ hasRowHighlight,
81
85
  });
82
86
 
83
87
  return (
@@ -211,6 +215,78 @@ describe('useTableSelection', () => {
211
215
  expect(headers).toHaveLength(3);
212
216
  });
213
217
 
218
+ describe('hasRowHighlight', () => {
219
+ const selectedBgColor = colorVars['--color-accent-muted'];
220
+
221
+ it('paints a checked row with the accent wash by default', async () => {
222
+ const user = userEvent.setup();
223
+ render(<SelectionTable />);
224
+
225
+ await user.click(screen.getAllByLabelText('Select row')[0]);
226
+
227
+ const row = screen.getAllByRole('row')[1];
228
+ expect(row.style.backgroundColor).toBe(selectedBgColor);
229
+ expect(row).toHaveAttribute('aria-selected', 'true');
230
+ });
231
+
232
+ it('leaves the row background alone when hasRowHighlight is false', async () => {
233
+ const user = userEvent.setup();
234
+ render(<SelectionTable hasRowHighlight={false} />);
235
+
236
+ await user.click(screen.getAllByLabelText('Select row')[0]);
237
+
238
+ const row = screen.getAllByRole('row')[1];
239
+ expect(row.style.backgroundColor).toBe('');
240
+ // The wash is opt-out; the semantics are not.
241
+ expect(row).toHaveAttribute('aria-selected', 'true');
242
+ });
243
+
244
+ it('clears an already-painted row when the flag flips to false', async () => {
245
+ const user = userEvent.setup();
246
+ const {rerender} = render(<SelectionTable />);
247
+
248
+ await user.click(screen.getAllByLabelText('Select row')[0]);
249
+ expect(screen.getAllByRole('row')[1].style.backgroundColor).toBe(
250
+ selectedBgColor,
251
+ );
252
+
253
+ rerender(<SelectionTable hasRowHighlight={false} />);
254
+
255
+ const row = screen.getAllByRole('row')[1];
256
+ expect(row.style.backgroundColor).toBe('');
257
+ expect(row).toHaveAttribute('aria-selected', 'true');
258
+ });
259
+
260
+ it('repaints an already-checked row when the flag flips back to true', async () => {
261
+ const user = userEvent.setup();
262
+ const {rerender} = render(<SelectionTable hasRowHighlight={false} />);
263
+
264
+ await user.click(screen.getAllByLabelText('Select row')[0]);
265
+ rerender(<SelectionTable hasRowHighlight />);
266
+
267
+ expect(screen.getAllByRole('row')[1].style.backgroundColor).toBe(
268
+ selectedBgColor,
269
+ );
270
+ });
271
+
272
+ it('never paints unchecked rows in either mode', async () => {
273
+ const user = userEvent.setup();
274
+ const {rerender} = render(<SelectionTable />);
275
+
276
+ await user.click(screen.getAllByLabelText('Select row')[0]);
277
+ expect(screen.getAllByRole('row')[2].style.backgroundColor).toBe('');
278
+ expect(screen.getAllByRole('row')[2]).not.toHaveAttribute(
279
+ 'aria-selected',
280
+ );
281
+
282
+ rerender(<SelectionTable hasRowHighlight={false} />);
283
+ expect(screen.getAllByRole('row')[2].style.backgroundColor).toBe('');
284
+ expect(screen.getAllByRole('row')[2]).not.toHaveAttribute(
285
+ 'aria-selected',
286
+ );
287
+ });
288
+ });
289
+
214
290
  it('unsubscribes detached row refs instead of accumulating listeners', () => {
215
291
  const getIsItemSelected = vi.fn(() => false);
216
292
  const {result, rerender} = renderHook(() =>
@@ -26,7 +26,13 @@
26
26
  * DOM elements and no central element tracking. Each subscription
27
27
  * self-cleans when the row disconnects.
28
28
  *
29
+ * Because the background is an inline style, it outranks anything
30
+ * userland can layer on with StyleX. `hasRowHighlight: false` is the
31
+ * supported way to reclaim the row background; `aria-selected` is
32
+ * unaffected by it.
33
+ *
29
34
  * SYNC: When modified, update these files to stay in sync:
35
+ * - /packages/core/src/Table/useTableSelection.doc.mjs (config prop table)
30
36
  * - /packages/core/src/Table/Table.doc.mjs (selection documentation)
31
37
  * - /packages/core/src/Table/index.ts (exports)
32
38
  */
@@ -81,6 +87,22 @@ export interface UseTableSelectionConfig<T extends Record<string, unknown>> {
81
87
  * ```
82
88
  */
83
89
  getRowLabel?: (item: T) => string;
90
+ /**
91
+ * Paint checked rows with the accent wash. Set false when the surrounding
92
+ * UI already uses row background to mean something else — a row that is
93
+ * open in a detail panel, for instance. The wash is an inline style, so
94
+ * it cannot be overridden from userland; this flag is the way off it.
95
+ *
96
+ * Only the background is dropped. `aria-selected` is still set on checked
97
+ * rows either way, so the selection stays legible to screen readers.
98
+ *
99
+ * @default true
100
+ * @example
101
+ * ```
102
+ * useTableSelection({...config, hasRowHighlight: false})
103
+ * ```
104
+ */
105
+ hasRowHighlight?: boolean;
84
106
  }
85
107
 
86
108
  // =============================================================================
@@ -121,18 +143,24 @@ function createSelectionStore<T extends Record<string, unknown>>(
121
143
 
122
144
  /**
123
145
  * Apply or remove selection styling on a <tr> element.
146
+ *
147
+ * `aria-selected` tracks selection on its own: it is the semantic half of
148
+ * the state and stays correct whether or not the row is painted.
124
149
  */
125
150
  function applyRowSelectionStyle(
126
151
  el: HTMLTableRowElement,
127
152
  isSelected: boolean,
153
+ hasRowHighlight: boolean,
128
154
  ): void {
129
155
  if (isSelected) {
130
156
  el.setAttribute('aria-selected', 'true');
131
- el.style.backgroundColor = selectedBgColor;
132
157
  } else {
133
158
  el.removeAttribute('aria-selected');
134
- el.style.backgroundColor = '';
135
159
  }
160
+ // Written on every pass, not just when painting: the flag can flip while a
161
+ // row is already selected, and the wash has to come back off.
162
+ el.style.backgroundColor =
163
+ isSelected && hasRowHighlight ? selectedBgColor : '';
136
164
  }
137
165
 
138
166
  // =============================================================================
@@ -358,18 +386,23 @@ export function useTableSelection<T extends Record<string, unknown>>(
358
386
  if (!el) {
359
387
  return;
360
388
  }
389
+ const applyStyle = () => {
390
+ const config = store.getConfig();
391
+ applyRowSelectionStyle(
392
+ el,
393
+ config.getIsItemSelected(item),
394
+ config.hasRowHighlight ?? true,
395
+ );
396
+ };
361
397
  // Apply initial style
362
- applyRowSelectionStyle(el, store.getConfig().getIsItemSelected(item));
398
+ applyStyle();
363
399
  // Subscribe for future changes
364
400
  const unsub = store.subscribe(() => {
365
401
  if (!el.isConnected) {
366
402
  unsub();
367
403
  return;
368
404
  }
369
- applyRowSelectionStyle(
370
- el,
371
- store.getConfig().getIsItemSelected(item),
372
- );
405
+ applyStyle();
373
406
  });
374
407
  return () => {
375
408
  unsub();
@@ -210,8 +210,7 @@ const stickyStyles = stylex.create({
210
210
  // ::after gradient strip just past the pinned edge (visible thanks to the cell's
211
211
  // overflow: visible). Opacity is gated by the scroll-state variable above.
212
212
  const SHADOW_WIDTH = '6px';
213
- // --color-shadow is only ~10% alpha (too faint here); use a slightly stronger soft tint.
214
- const SHADOW_TINT = 'light-dark(rgba(0, 0, 0, 0.12), rgba(0, 0, 0, 0.32))';
213
+ const SHADOW_TINT = colorVars['--color-shadow'];
215
214
  const shadowStyles = stylex.create({
216
215
  // start-pinned: shadow falls toward inline-end (over scrolled content).
217
216
  // insetInlineEnd anchors the strip to the column's inline-end edge; the strip
@@ -322,6 +322,19 @@ export interface BodyCellRenderProps {
322
322
  * sticky offsets. Optional for backward compatibility.
323
323
  */
324
324
  columns?: ReadonlyArray<TableColumn<Record<string, unknown>>>;
325
+ /**
326
+ * When true, the cell renders empty: BaseTable calls neither the column's
327
+ * `renderCell` nor the default renderer. Set it for a row whose cells a
328
+ * plugin is going to replace wholesale in `transformBodyRow` (a grouped-rows
329
+ * section header, a summary row) — the row is not one the consumer supplied,
330
+ * so their renderer can only misread it or throw, and its output is
331
+ * discarded moments later anyway.
332
+ *
333
+ * Applies to this cell only, and is decided per render against the final
334
+ * column list, so it covers columns other plugins contributed regardless of
335
+ * where in the pipeline this plugin sits.
336
+ */
337
+ isContentSuppressed?: boolean;
325
338
  }
326
339
 
327
340
  /**
@@ -414,13 +427,18 @@ export type TableContextActions =
414
427
  *
415
428
  * 1. `transformColumns` — filter, reorder, or inject columns before rendering
416
429
  * 2. `transformTable` — transform the root `<table>` element props
417
- * 3. `transformHeaderRow` — transform the header `<tr>` props
418
- * 4. `transformHeaderCell` — transform each `<th>` props
419
- * 5. `transformBodyRow` — transform each body `<tr>` props
420
- * 6. `transformBodyCell` — transform each body `<td>` props
430
+ * 3. `transformHeaderCell` — transform each `<th>` props
431
+ * 4. `transformHeaderRow` — transform the header `<tr>` props
432
+ * 5. `transformBodyCell` — transform each body `<td>` props
433
+ * 6. `transformBodyRow` — transform each body `<tr>` props
421
434
  * 7. `transformScrollWrapper` — transform the scroll-container wrapper around the table
422
435
  * 8. `transformTableContext` — wrap the table output in context providers
423
436
  *
437
+ * A row's cells are built before its row transform runs, and reach it as
438
+ * `children`: the cell hook is the earliest per-cell interception point, and a
439
+ * row transform can discard cells but cannot stop them being built (see
440
+ * `isContentSuppressed` on `BodyCellRenderProps` for that).
441
+ *
424
442
  * Plugins may also contribute right-click menu actions by appending to
425
443
  * `contextMenuActions` in `transformHeaderCell` / `transformBodyCell`
426
444
  * (aggregated into one menu per header cell / row).
@@ -46,6 +46,11 @@ import {devWarn} from '../utils/devWarning';
46
46
  * Canonical ordering for first-party plugin names.
47
47
  * Plugins are sorted by their position in this array.
48
48
  * Unknown names are appended after the known set.
49
+ *
50
+ * This decides LAYOUT — which column lands left of which, who wraps whom. It
51
+ * must never decide whether the table works: a plugin that renders in one
52
+ * order and crashes in the other is broken, and adding it here buys a lucky
53
+ * order rather than a fix.
49
54
  */
50
55
  const PLUGIN_ORDER: ReadonlyArray<string> = [
51
56
  'columnSettings',
@@ -7,7 +7,7 @@ export const docs = {
7
7
  subComponentOf: 'Table',
8
8
  displayName: 'useTableGroupedRows',
9
9
  description:
10
- 'Hook that groups a flat data array into collapsible section rows. Each distinct groupBy value becomes a full-width section-header row with a chevron toggle, the group label, and a member count; collapsing hides that group\'s data rows while keeping the header visible. Mirrors useTableTreeState: the consumer owns the collapsedGroups set and the hook returns {data, plugin, idKey}: pass all three to Table (data, plugins, and idKey respectively).',
10
+ "Hook that groups a flat data array into collapsible section rows. Each distinct groupBy value becomes a full-width section-header row with a chevron toggle, the group label, and a member count; collapsing hides that group's data rows while keeping the header visible. Mirrors useTableTreeState: the consumer owns the collapsedGroups set and the hook returns {data, plugin, idKey}: pass them to Table as data, plugins, and idKey respectively.",
11
11
  props: [
12
12
  {
13
13
  name: 'data',
@@ -58,13 +58,14 @@ export const docs = {
58
58
  /** @type {import('@astryxdesign/cli/authoring').ComponentTranslationDoc} */
59
59
  export const docsDense = {
60
60
  description:
61
- 'Groups a flat data array into collapsible section rows. Each groupBy value becomes a full-width header (chevron + label + count); collapsing hides its rows. Returns {data, plugin, idKey}: pass to Table data / plugins / idKey. Consumer owns the collapsedGroups set.',
61
+ 'Groups a flat data array into collapsible section rows. Each groupBy value becomes a full-width header (chevron + label + count); collapsing hides its rows. Returns {data, plugin, idKey}: pass them to Table data / plugins / idKey. Consumer owns the collapsedGroups set.',
62
62
  propDescriptions: {
63
63
  data: 'The flat data to group.',
64
- groupBy: 'Derive a row\'s group key. Same key = same section.',
64
+ groupBy: "Derive a row's group key. Same key = same section.",
65
65
  collapsedGroups: 'Set of currently-collapsed group keys.',
66
66
  onToggleGroup: 'Called with the group key when a header is toggled.',
67
- renderGroupHeader: "Custom header content (right of chevron). Default '<key> (<count>)'.",
67
+ renderGroupHeader:
68
+ "Custom header content (right of chevron). Default '<key> (<count>)'.",
68
69
  getRowKey: 'Stable key for a real row; positional fallback when omitted.',
69
70
  groupOrder: 'Pin these group keys first; others keep first-seen order.',
70
71
  },
@@ -72,6 +72,12 @@ export const docs = {
72
72
  description: 'Horizontal alignment of the pagination controls.',
73
73
  default: "'center'",
74
74
  },
75
+ {
76
+ name: 'label',
77
+ type: 'string',
78
+ description: "Accessible name for the pagination nav landmark. With position='both' the two navs get distinct names (the label suffixed as '(top)' and '(bottom)') so same-type landmarks stay unique (axe landmark-unique).",
79
+ default: "'Table pagination'",
80
+ },
75
81
  ],
76
82
  };
77
83
 
@@ -129,5 +135,6 @@ export const docsDense = {
129
135
  pageSize: 'Items per page. Default 10.',
130
136
  variant: "Pagination variant: 'pages'|'count'|'compact'|'dots'|'none'.",
131
137
  position: "Render position: 'below'|'above'|'both'|'none'.",
138
+ label: "Accessible name for the nav landmark; position='both' emits '<label> (top)' / '<label> (bottom)'.",
132
139
  },
133
140
  };
@@ -7,7 +7,7 @@ export const docs = {
7
7
  subComponentOf: 'Table',
8
8
  displayName: 'useTableRowStatus',
9
9
  description:
10
- 'Hook that returns a TablePlugin which prepends a narrow column signaling per-row status: a colored status dot by default, or an icon when provided (shape + color is more accessible than color alone). getStatus maps a row to a semantic color (mapped to a theme token) or raw CSS color, an optional icon, and a required accessible label (shown in a tooltip on hover and announced to assistive technology, so status is never color-only); return null for no indicator. Memoize getStatus with useCallback for a stable plugin identity.',
10
+ 'Hook that returns a TablePlugin which prepends a narrow column signaling per-row status: a colored status dot by default, or an icon when provided (shape + color is more accessible than color alone). getStatus maps a row to a semantic color (mapped to a theme token) or raw CSS color, an optional icon, and a required accessible label (shown in a tooltip on hover and announced to assistive technology, so status is never color-only); return null for no indicator. The column header is visually blank but carries a screen-reader-only localized name ("Row status", i18n key @astryx.table.rowStatus.columnHeader). Memoize getStatus with useCallback for a stable plugin identity.',
11
11
  props: [
12
12
  {
13
13
  name: 'getStatus',
@@ -61,6 +61,13 @@ export const docs = {
61
61
  description:
62
62
  'Derives a human-readable identity for a row; the row checkbox\'s hidden label becomes `Select ${getRowLabel(item)}` so screen readers announce which row each checkbox selects. Falls back to "Select row" when omitted.',
63
63
  },
64
+ {
65
+ name: 'hasRowHighlight',
66
+ type: 'boolean',
67
+ description:
68
+ 'Paints checked rows with the accent wash. Set false when the surrounding UI already uses row background to mean something else (a row open in a detail panel, say) — the wash is an inline style, so it cannot be overridden from userland. Only the background is dropped: aria-selected is still set on checked rows either way.',
69
+ default: 'true',
70
+ },
64
71
  ],
65
72
  examples: [
66
73
  {
@@ -82,6 +89,21 @@ const selectionPlugin = useTableSelection({
82
89
  idKey="id"
83
90
  plugins={{selection: selectionPlugin}}
84
91
  />;
92
+ `,
93
+ },
94
+ {
95
+ label: 'Opt out of the checked-row wash',
96
+ code: `
97
+ // This table already uses row background to mean "open in the detail
98
+ // panel". Turning the selection wash off keeps that meaning unambiguous;
99
+ // the checkbox and aria-selected still carry the selection.
100
+ const selectionPlugin = useTableSelection({
101
+ getIsItemSelected: item => selectedIds.has(item.id),
102
+ onSelectItem: ({item, isSelected}) => toggle(item.id, isSelected),
103
+ onSelectAll: ({isAllSelected}) => selectAll(isAllSelected),
104
+ getIsAllSelected: () => selectedIds.size === users.length,
105
+ hasRowHighlight: false,
106
+ });
85
107
  `,
86
108
  },
87
109
  ],
@@ -142,6 +164,13 @@ export const docsZh = {
142
164
  description:
143
165
  '为行派生人类可读的标识;行复选框的隐藏标签变为 `Select ${getRowLabel(item)}`,让屏幕阅读器播报每个复选框选择的是哪一行。省略时回退为 "Select row"。',
144
166
  },
167
+ {
168
+ name: 'hasRowHighlight',
169
+ type: 'boolean',
170
+ description:
171
+ '为选中的行绘制强调色背景。当周围的界面已用行背景表达其他含义(例如该行已在详情面板中打开)时设为 false —— 该背景是内联样式,无法从业务代码覆盖。仅去掉背景:无论如何选中的行仍会设置 aria-selected。',
172
+ default: 'true',
173
+ },
145
174
  ],
146
175
  };
147
176
 
@@ -164,5 +193,7 @@ export const docsDense = {
164
193
  'Returns whether row checkbox is interactive; disabled rows show disabled checkbox.',
165
194
  getRowLabel:
166
195
  'Derives row identity for the checkbox\'s hidden label: `Select ${getRowLabel(item)}`. Falls back to "Select row" when omitted.',
196
+ hasRowHighlight:
197
+ 'false => skip the accent wash on checked rows (inline style, not overridable from userland). aria-selected is unaffected. Defaults to true.',
167
198
  },
168
199
  };
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import {render, screen} from '@testing-library/react';
9
- import {describe, it, expect} from 'vitest';
9
+ import {describe, it, expect, vi} from 'vitest';
10
10
  import {Text} from './Text';
11
11
  import type {TextType} from './Text';
12
12
  import type {TextColor} from '../theme/types';
@@ -23,6 +23,28 @@ describe('Text', () => {
23
23
  expect(screen.getByText('Hello World')).toBeInTheDocument();
24
24
  });
25
25
 
26
+ it('keeps a forwarded ref attached across rerenders', () => {
27
+ const ref = vi.fn();
28
+ const {rerender} = render(
29
+ <Text ref={ref} type="body">
30
+ Before
31
+ </Text>,
32
+ );
33
+
34
+ const element = screen.getByText('Before');
35
+ expect(ref).toHaveBeenLastCalledWith(element);
36
+ ref.mockClear();
37
+
38
+ rerender(
39
+ <Text ref={ref} type="body">
40
+ After
41
+ </Text>,
42
+ );
43
+
44
+ expect(ref).not.toHaveBeenCalled();
45
+ expect(screen.getByText('After')).toBe(element);
46
+ });
47
+
26
48
  it('renders as span by default', () => {
27
49
  render(<Text type="body">Text</Text>);
28
50
  const element = screen.getByText('Text');
package/src/Text/Text.tsx CHANGED
@@ -48,7 +48,8 @@ import {
48
48
  } from './text.stylex';
49
49
  import {useTruncation} from './useTruncation';
50
50
  import type {LayerPlacement} from '../Layer';
51
- import {mergeProps, mergeRefs} from '../utils';
51
+ import {mergeProps} from '../utils';
52
+ import {useMergedRefs} from '../hooks/useMergedRefs';
52
53
  import type {BaseProps} from '../BaseProps';
53
54
  import {themeProps} from '../utils/themeProps';
54
55
 
@@ -271,13 +272,16 @@ export function Text({
271
272
  // Ref for the text element (used as tooltip anchor)
272
273
  const textRef = useRef<HTMLElement>(null);
273
274
 
275
+ // Keep the merged ref stable across rerenders.
276
+ const mergedRef = useMergedRefs(ref, truncation.ref, textRef);
277
+
274
278
  // Build inline style for -webkit-line-clamp (dynamic value)
275
279
  const inlineStyle = maxLines > 1 ? {WebkitLineClamp: maxLines} : undefined;
276
280
 
277
281
  return (
278
282
  <>
279
283
  <Component
280
- ref={mergeRefs(ref, truncation.ref, textRef)}
284
+ ref={mergedRef}
281
285
  {...mergeProps(
282
286
  themeProps('text', {type, size, color: resolvedColor}),
283
287
  stylex.props(
@@ -186,7 +186,10 @@ export const docs = {
186
186
  ],
187
187
  theming: {
188
188
  targets: [
189
- {className: 'astryx-textarea', visualProps: ['size', 'status'], states: ['disabled', 'readonly']},
189
+ {className: 'astryx-text-area', visualProps: ['size', 'status'], states: ['disabled', 'readonly']},
190
+ // Still emitted beside the names above, so themes written against
191
+ // them keep working. Drop in the next major.
192
+ {className: 'astryx-textarea', visualProps: ['size', 'status'], states: ['disabled', 'readonly'], deprecatedFor: 'text-area'},
190
193
  ],
191
194
  vars: [
192
195
  {
@@ -381,7 +384,10 @@ export const docsZh = {
381
384
  ],
382
385
  theming: {
383
386
  targets: [
384
- {className: 'astryx-textarea', visualProps: ['size', 'status'], states: ['disabled', 'readonly']},
387
+ {className: 'astryx-text-area', visualProps: ['size', 'status'], states: ['disabled', 'readonly']},
388
+ // Still emitted beside the names above, so themes written against
389
+ // them keep working. Drop in the next major.
390
+ {className: 'astryx-textarea', visualProps: ['size', 'status'], states: ['disabled', 'readonly'], deprecatedFor: 'text-area'},
385
391
  ],
386
392
  vars: [
387
393
  {
@@ -1155,3 +1155,14 @@ describe('TextArea readonly theme state', () => {
1155
1155
  expect(root).not.toHaveAttribute('data-readonly');
1156
1156
  });
1157
1157
  });
1158
+
1159
+ describe('TextArea theme target names', () => {
1160
+ it('renders the deprecated class beside the current one', () => {
1161
+ const {container} = render(
1162
+ <TextArea label="Notes" value="" onChange={() => {}} />,
1163
+ );
1164
+ const root = container.querySelector('.astryx-text-area');
1165
+ expect(root).not.toBeNull();
1166
+ expect(root).toHaveClass('astryx-textarea');
1167
+ });
1168
+ });
@@ -46,7 +46,7 @@ import {
46
46
  import {Icon, renderIconSlot, type IconType} from '../Icon';
47
47
  import {Spinner} from '../Spinner';
48
48
  import {useTooltip} from '../Tooltip';
49
- import {mergeProps, mergeRefs} from '../utils';
49
+ import {mergeProps} from '../utils';
50
50
  import type {BaseProps} from '../BaseProps';
51
51
  import type {SizeValue} from '../utils/types';
52
52
  import {useInputContainer} from '../hooks/useInputContainer';
@@ -58,6 +58,7 @@ import {themeProps} from '../utils/themeProps';
58
58
  import {characterCount} from '../utils/characters';
59
59
  import {useTranslator} from '../i18n';
60
60
 
61
+ import {useMergedRefs} from '../hooks/useMergedRefs';
61
62
  const COUNTER_WARNING_THRESHOLD = 0.8;
62
63
 
63
64
  const styles = stylex.create({
@@ -555,12 +556,18 @@ export function TextArea({
555
556
  onClick={handleWrapperClick}
556
557
  onMouseUp={handleWrapperMouseUp}
557
558
  {...mergeProps(
558
- themeProps('textarea', {
559
- size,
560
- status: status?.type ?? null,
561
- disabled: isDisabled ? 'disabled' : null,
562
- readonly: isReadOnly ? 'readonly' : null,
563
- }),
559
+ themeProps(
560
+ 'text-area',
561
+ {
562
+ size,
563
+ status: status?.type ?? null,
564
+ disabled: isDisabled ? 'disabled' : null,
565
+ readonly: isReadOnly ? 'readonly' : null,
566
+ },
567
+ // `textarea` ran the compound name together; themes styling it
568
+ // keep working until the next major.
569
+ {legacyNames: ['textarea']},
570
+ ),
564
571
  stylex.props(
565
572
  inputWrapperStyles.base,
566
573
  styles.wrapper,
@@ -580,7 +587,7 @@ export function TextArea({
580
587
  )}
581
588
  <textarea
582
589
  {...rest}
583
- ref={mergeRefs(ref, textareaRef)}
590
+ ref={useMergedRefs(ref, textareaRef)}
584
591
  id={id}
585
592
  name={isDisabled ? undefined : htmlName}
586
593
  value={optimisticValue}
@@ -71,6 +71,16 @@ export const docs = {
71
71
  'Displays a "Required" indicator next to the label and sets aria-required. Mutually exclusive with isOptional.',
72
72
  default: 'false',
73
73
  },
74
+ {
75
+ name: 'onEnter',
76
+ type: '() => void',
77
+ description: 'Callback fired when the user presses the Enter key.',
78
+ },
79
+ {
80
+ name: 'onKeyDown',
81
+ type: '(e: KeyboardEvent<HTMLInputElement>) => void',
82
+ description: 'Callback fired on keydown events on the input.',
83
+ },
74
84
  {
75
85
  name: 'isDisabled',
76
86
  type: 'boolean',
@@ -97,7 +97,7 @@ export type {
97
97
  InputStatus as TextInputStatus,
98
98
  InputStatusType as TextInputStatusType,
99
99
  } from '../Field';
100
- import {mergeProps, mergeRefs} from '../utils';
100
+ import {mergeProps} from '../utils';
101
101
  import {useSize} from '../SizeContext/SizeContext';
102
102
  import {useInputContainer} from '../hooks/useInputContainer';
103
103
  import {useInputStatusIcon} from '../hooks/useInputStatusIcon';
@@ -108,6 +108,7 @@ import type {SizeValue} from '../utils/types';
108
108
  import {themeProps} from '../utils/themeProps';
109
109
  import {useTranslator} from '../i18n';
110
110
 
111
+ import {useMergedRefs} from '../hooks/useMergedRefs';
111
112
  export type TextInputType = 'text' | 'password' | 'email';
112
113
 
113
114
  export interface TextInputProps extends Omit<
@@ -421,7 +422,7 @@ export function TextInput({
421
422
  {inputGroup && <VisuallyHidden id={inputLabelID}>{label}</VisuallyHidden>}
422
423
  <input
423
424
  {...rest}
424
- ref={mergeRefs(ref, inputRef)}
425
+ ref={useMergedRefs(ref, inputRef)}
425
426
  id={id}
426
427
  name={isDisabled ? undefined : htmlName}
427
428
  type={type}
@@ -78,7 +78,7 @@ export const docs = {
78
78
  {className: 'astryx-thumbnail'},
79
79
  ],
80
80
  vars: [
81
- {name: '--_thumbnail-hit-inset', description: 'Outset of the remove button\u2019s invisible hit area, applied to a ::after overlay. 0 on a fine pointer; negative on a coarse one, which grows the 20px button to the 24px touch target without changing what is drawn.', default: '0px', private: true},
81
+ {name: '--_thumbnail-hit-inset', description: 'Outset of the remove button\'s invisible hit area, applied to a ::after overlay. 0 on a fine pointer; negative on a coarse one, which grows the 20px button to the 24px touch target without changing what is drawn.', default: '0px', private: true},
82
82
  ],
83
83
  },
84
84
  usage: {
@@ -58,7 +58,6 @@ import {
58
58
  isImeKeyEvent,
59
59
  isTimeInRange,
60
60
  mergeProps,
61
- mergeRefs,
62
61
  getInputARIA,
63
62
  } from '../utils';
64
63
  import type {BaseProps} from '../BaseProps';
@@ -74,6 +73,7 @@ import {useTooltip} from '../Tooltip';
74
73
  import {themeProps} from '../utils/themeProps';
75
74
  import {useTranslator} from '../i18n';
76
75
 
76
+ import {useMergedRefs} from '../hooks/useMergedRefs';
77
77
  const styles = stylex.create({
78
78
  icon: {
79
79
  display: 'flex',
@@ -648,7 +648,7 @@ export function TimeInput({
648
648
  </VisuallyHidden>
649
649
  )}
650
650
  <input
651
- ref={mergeRefs(ref, inputRef)}
651
+ ref={useMergedRefs(ref, inputRef)}
652
652
  id={id}
653
653
  type="text"
654
654
  value={displayValue}
@@ -673,6 +673,24 @@ describe('Timestamp', () => {
673
673
  expect(screen.getByTestId('ts')).toHaveAttribute('tabindex', '0');
674
674
  });
675
675
 
676
+ it('does not put aria-expanded on the role-less hover-card trigger', async () => {
677
+ render(
678
+ <Timestamp
679
+ value={Date.now() / 1000 - 3600}
680
+ format="relative"
681
+ data-testid="ts"
682
+ />,
683
+ );
684
+ const trigger = screen.getByTestId('ts').parentElement;
685
+ // The trigger is Text's <span>, which has no role, so aria-expanded is
686
+ // invalid on it (axe aria-allowed-attr, critical). aria-haspopup is
687
+ // global and still advertises the dialog.
688
+ await waitFor(() => {
689
+ expect(trigger).toHaveAttribute('aria-haspopup', 'dialog');
690
+ });
691
+ expect(trigger).not.toHaveAttribute('aria-expanded');
692
+ });
693
+
676
694
  it('shows the hover card when the timestamp receives keyboard focus', async () => {
677
695
  const user = userEvent.setup();
678
696
  render(