@astryxdesign/core 0.1.8 → 0.1.9-canary.1887ee2

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 (610) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/dist/AppShell/AppShell.d.ts.map +1 -1
  3. package/dist/AppShell/AppShell.js +6 -2
  4. package/dist/AppShell/AppShellMobileContext.d.ts +8 -0
  5. package/dist/AppShell/AppShellMobileContext.d.ts.map +1 -1
  6. package/dist/Avatar/Avatar.d.ts +53 -3
  7. package/dist/Avatar/Avatar.d.ts.map +1 -1
  8. package/dist/Avatar/Avatar.js +203 -49
  9. package/dist/Avatar/AvatarStatusDot.d.ts +33 -5
  10. package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
  11. package/dist/Avatar/AvatarStatusDot.js +144 -19
  12. package/dist/AvatarGroup/AvatarGroup.d.ts +7 -1
  13. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  14. package/dist/AvatarGroup/AvatarGroup.js +58 -6
  15. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  16. package/dist/AvatarGroup/AvatarGroupOverflow.js +1 -0
  17. package/dist/Banner/Banner.d.ts +9 -1
  18. package/dist/Banner/Banner.d.ts.map +1 -1
  19. package/dist/Banner/Banner.js +33 -4
  20. package/dist/Breadcrumbs/BreadcrumbItem.d.ts +31 -2
  21. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  22. package/dist/Breadcrumbs/BreadcrumbItem.js +208 -6
  23. package/dist/Breadcrumbs/index.d.ts +5 -0
  24. package/dist/Breadcrumbs/index.d.ts.map +1 -1
  25. package/dist/Breadcrumbs/index.js +9 -1
  26. package/dist/Button/Button.d.ts +8 -2
  27. package/dist/Button/Button.d.ts.map +1 -1
  28. package/dist/Button/Button.js +33 -4
  29. package/dist/ButtonGroup/ButtonGroup.d.ts +9 -1
  30. package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
  31. package/dist/ButtonGroup/ButtonGroup.js +30 -1
  32. package/dist/Calendar/Calendar.d.ts.map +1 -1
  33. package/dist/Calendar/Calendar.js +30 -2
  34. package/dist/Calendar/dayCellUtils.js +1 -1
  35. package/dist/Card/Card.d.ts +8 -2
  36. package/dist/Card/Card.d.ts.map +1 -1
  37. package/dist/Card/Card.js +28 -2
  38. package/dist/Carousel/Carousel.d.ts +4 -1
  39. package/dist/Carousel/Carousel.d.ts.map +1 -1
  40. package/dist/Carousel/Carousel.js +24 -4
  41. package/dist/Chat/ChatComposer.d.ts +8 -0
  42. package/dist/Chat/ChatComposer.d.ts.map +1 -1
  43. package/dist/Chat/ChatComposer.js +46 -7
  44. package/dist/Chat/ChatComposerDrawer.d.ts +2 -0
  45. package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
  46. package/dist/Chat/ChatComposerDrawer.js +11 -1
  47. package/dist/Chat/ChatComposerInput.d.ts +20 -3
  48. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  49. package/dist/Chat/ChatComposerInput.js +36 -4
  50. package/dist/Chat/ChatContext.d.ts +33 -0
  51. package/dist/Chat/ChatContext.d.ts.map +1 -1
  52. package/dist/Chat/ChatContext.js +16 -2
  53. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  54. package/dist/Chat/ChatDictationButton.js +1 -1
  55. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  56. package/dist/Chat/ChatLayout.js +4 -4
  57. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  58. package/dist/Chat/ChatLayoutScrollButton.js +4 -4
  59. package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
  60. package/dist/Chat/ChatSendButton.d.ts.map +1 -1
  61. package/dist/Chat/ChatSendButton.js +7 -1
  62. package/dist/Chat/ChatToolCalls.d.ts +5 -1
  63. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  64. package/dist/Chat/ChatToolCalls.js +18 -9
  65. package/dist/Chat/index.d.ts +2 -1
  66. package/dist/Chat/index.d.ts.map +1 -1
  67. package/dist/Chat/index.js +1 -1
  68. package/dist/Chat/useChatStreamScroll.d.ts +2 -1
  69. package/dist/Chat/useChatStreamScroll.d.ts.map +1 -1
  70. package/dist/Chat/useChatStreamScroll.js +22 -8
  71. package/dist/Chat/useSpeechRecognition.d.ts +0 -1
  72. package/dist/Chat/useSpeechRecognition.d.ts.map +1 -1
  73. package/dist/Chat/useSpeechRecognition.js +1 -1
  74. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  75. package/dist/Chat/useTriggerMenu.js +2 -2
  76. package/dist/CheckboxInput/CheckboxInput.js +1 -1
  77. package/dist/CheckboxList/CheckboxListItem.d.ts +20 -1
  78. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  79. package/dist/CheckboxList/CheckboxListItem.js +11 -1
  80. package/dist/Citation/Citation.d.ts +22 -1
  81. package/dist/Citation/Citation.d.ts.map +1 -1
  82. package/dist/Citation/Citation.js +20 -6
  83. package/dist/ClickableCard/ClickableCard.d.ts +9 -2
  84. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  85. package/dist/ClickableCard/ClickableCard.js +5 -2
  86. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  87. package/dist/CodeBlock/CodeBlock.js +9 -2
  88. package/dist/CommandPalette/CommandPalette.d.ts +1 -1
  89. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  90. package/dist/CommandPalette/CommandPalette.js +3 -1
  91. package/dist/CommandPalette/CommandPaletteGroup.d.ts.map +1 -1
  92. package/dist/CommandPalette/CommandPaletteGroup.js +9 -2
  93. package/dist/CommandPalette/CommandPaletteInput.d.ts +7 -1
  94. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  95. package/dist/CommandPalette/CommandPaletteInput.js +6 -1
  96. package/dist/CommandPalette/CommandPaletteItem.js +1 -1
  97. package/dist/DateInput/DateInput.d.ts +55 -2
  98. package/dist/DateInput/DateInput.d.ts.map +1 -1
  99. package/dist/DateInput/DateInput.js +28 -2
  100. package/dist/DateInput/index.d.ts +1 -1
  101. package/dist/DateInput/index.d.ts.map +1 -1
  102. package/dist/DateRangeInput/DateRangeInput.d.ts +9 -2
  103. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  104. package/dist/DateRangeInput/DateRangeInput.js +3 -1
  105. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  106. package/dist/DateTimeInput/DateTimeInput.js +18 -3
  107. package/dist/Dialog/Dialog.d.ts +3 -0
  108. package/dist/Dialog/Dialog.d.ts.map +1 -1
  109. package/dist/Dialog/Dialog.js +57 -6
  110. package/dist/Dialog/DialogContext.d.ts +7 -0
  111. package/dist/Dialog/DialogContext.d.ts.map +1 -1
  112. package/dist/Dialog/DialogContext.js +2 -2
  113. package/dist/Dialog/DialogHeader.d.ts +5 -2
  114. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  115. package/dist/Dialog/DialogHeader.js +6 -1
  116. package/dist/Divider/Divider.js +1 -1
  117. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +1 -2
  118. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  119. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +1 -2
  120. package/dist/DropdownMenu/DropdownMenuItem.js +1 -1
  121. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +1 -2
  122. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -1
  123. package/dist/DropdownMenu/DropdownMenuRadioGroup.js +1 -2
  124. package/dist/Field/Field.d.ts.map +1 -1
  125. package/dist/Field/Field.js +2 -3
  126. package/dist/Field/FieldLabel.d.ts +1 -1
  127. package/dist/Field/FieldLabel.d.ts.map +1 -1
  128. package/dist/Field/FieldLabel.js +43 -16
  129. package/dist/FieldStatus/FieldStatus.d.ts +15 -0
  130. package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
  131. package/dist/FieldStatus/FieldStatus.js +58 -6
  132. package/dist/FileInput/FileInput.d.ts +9 -2
  133. package/dist/FileInput/FileInput.d.ts.map +1 -1
  134. package/dist/FileInput/FileInput.js +42 -20
  135. package/dist/HoverCard/HoverCard.d.ts +9 -1
  136. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  137. package/dist/HoverCard/HoverCard.js +2 -0
  138. package/dist/HoverCard/useHoverCard.d.ts +8 -0
  139. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  140. package/dist/HoverCard/useHoverCard.js +7 -2
  141. package/dist/Icon/Icon.d.ts +7 -2
  142. package/dist/Icon/Icon.d.ts.map +1 -1
  143. package/dist/Item/Item.d.ts +6 -1
  144. package/dist/Item/Item.d.ts.map +1 -1
  145. package/dist/Item/Item.js +22 -1
  146. package/dist/Layer/useLayer.d.ts +6 -0
  147. package/dist/Layer/useLayer.d.ts.map +1 -1
  148. package/dist/Layer/useLayer.js +2 -0
  149. package/dist/Lightbox/Lightbox.js +4 -4
  150. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  151. package/dist/MobileNav/MobileNav.js +6 -1
  152. package/dist/MobileNav/MobileNavToggle.d.ts.map +1 -1
  153. package/dist/MobileNav/MobileNavToggle.js +4 -0
  154. package/dist/MultiSelector/MultiSelector.d.ts +9 -1
  155. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  156. package/dist/MultiSelector/MultiSelector.js +41 -12
  157. package/dist/MultiSelector/hooks.d.ts.map +1 -1
  158. package/dist/MultiSelector/hooks.js +16 -0
  159. package/dist/NavMenu/NavHeadingMenuItem.js +1 -1
  160. package/dist/NumberInput/NumberInput.d.ts +9 -2
  161. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  162. package/dist/NumberInput/NumberInput.js +8 -1
  163. package/dist/Outline/Outline.d.ts +0 -1
  164. package/dist/Outline/Outline.d.ts.map +1 -1
  165. package/dist/Outline/Outline.js +0 -1
  166. package/dist/OverflowList/OverflowList.d.ts +20 -3
  167. package/dist/OverflowList/OverflowList.d.ts.map +1 -1
  168. package/dist/OverflowList/OverflowList.js +29 -4
  169. package/dist/Pagination/Pagination.d.ts.map +1 -1
  170. package/dist/Pagination/Pagination.js +11 -3
  171. package/dist/Popover/Popover.d.ts.map +1 -1
  172. package/dist/Popover/Popover.js +3 -2
  173. package/dist/Popover/usePopover.d.ts.map +1 -1
  174. package/dist/Popover/usePopover.js +3 -9
  175. package/dist/PowerSearch/PowerSearch.d.ts +9 -2
  176. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  177. package/dist/PowerSearch/PowerSearch.js +2 -0
  178. package/dist/PowerSearch/PowerSearchEditPopover.js +1 -1
  179. package/dist/PowerSearch/usePowerSearchSource.d.ts.map +1 -1
  180. package/dist/SelectableCard/SelectableCard.d.ts +9 -2
  181. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  182. package/dist/SelectableCard/SelectableCard.js +16 -13
  183. package/dist/Selector/Selector.d.ts +8 -0
  184. package/dist/Selector/Selector.d.ts.map +1 -1
  185. package/dist/Selector/Selector.js +7 -3
  186. package/dist/Selector/hooks.d.ts.map +1 -1
  187. package/dist/Selector/hooks.js +16 -0
  188. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  189. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  190. package/dist/SideNav/SideNavHeading.js +21 -8
  191. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  192. package/dist/Slider/Slider.d.ts.map +1 -1
  193. package/dist/Slider/Slider.js +19 -2
  194. package/dist/Stack/stack.stylex.d.ts +9 -9
  195. package/dist/TabList/Tab.js +2 -2
  196. package/dist/TabList/TabMenu.js +1 -1
  197. package/dist/Table/BaseTable.d.ts.map +1 -1
  198. package/dist/Table/BaseTable.js +3 -2
  199. package/dist/Table/TableCell.js +3 -3
  200. package/dist/Table/TableHeaderCell.js +3 -3
  201. package/dist/Table/index.d.ts +2 -0
  202. package/dist/Table/index.d.ts.map +1 -1
  203. package/dist/Table/index.js +1 -0
  204. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  205. package/dist/Table/plugins/rowStatus/index.d.ts +3 -0
  206. package/dist/Table/plugins/rowStatus/index.d.ts.map +1 -0
  207. package/dist/Table/plugins/rowStatus/index.js +3 -0
  208. package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts +60 -0
  209. package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts.map +1 -0
  210. package/dist/Table/plugins/rowStatus/useTableRowStatus.js +145 -0
  211. package/dist/Table/plugins/selection/useTableSelection.d.ts +13 -0
  212. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  213. package/dist/Table/plugins/selection/useTableSelection.js +4 -1
  214. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +1 -1
  215. package/dist/Table/plugins/tree/useTableTreeData.d.ts +16 -0
  216. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
  217. package/dist/Table/plugins/tree/useTableTreeData.js +87 -0
  218. package/dist/Table/plugins/tree/useTableTreeState.d.ts +6 -0
  219. package/dist/Table/plugins/tree/useTableTreeState.d.ts.map +1 -1
  220. package/dist/Table/plugins/tree/useTableTreeState.js +22 -1
  221. package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
  222. package/dist/Table/useBaseTablePlugins.js +5 -3
  223. package/dist/TextArea/TextArea.d.ts +9 -1
  224. package/dist/TextArea/TextArea.d.ts.map +1 -1
  225. package/dist/TextArea/TextArea.js +2 -0
  226. package/dist/TextInput/TextInput.d.ts +9 -2
  227. package/dist/TextInput/TextInput.d.ts.map +1 -1
  228. package/dist/TextInput/TextInput.js +6 -1
  229. package/dist/Thumbnail/Thumbnail.d.ts +26 -5
  230. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  231. package/dist/Thumbnail/Thumbnail.js +97 -54
  232. package/dist/Thumbnail/thumbnail.markers.stylex.d.ts +9 -0
  233. package/dist/Thumbnail/thumbnail.markers.stylex.d.ts.map +1 -0
  234. package/dist/Thumbnail/thumbnail.markers.stylex.js +14 -0
  235. package/dist/TimeInput/TimeInput.d.ts +9 -2
  236. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  237. package/dist/TimeInput/TimeInput.js +17 -4
  238. package/dist/Timestamp/Timestamp.d.ts +3 -1
  239. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  240. package/dist/Timestamp/Timestamp.js +8 -6
  241. package/dist/Toast/useToast.d.ts.map +1 -1
  242. package/dist/Toast/useToast.js +2 -5
  243. package/dist/ToggleButton/ToggleButtonGroup.d.ts +0 -1
  244. package/dist/ToggleButton/ToggleButtonGroup.d.ts.map +1 -1
  245. package/dist/ToggleButton/ToggleButtonGroup.js +1 -1
  246. package/dist/Tokenizer/Tokenizer.d.ts +10 -3
  247. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  248. package/dist/Tokenizer/Tokenizer.js +18 -4
  249. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  250. package/dist/TopNav/TopNavHeading.js +18 -8
  251. package/dist/TopNav/TopNavMegaMenu.js +10 -4
  252. package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts +9 -1
  253. package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts.map +1 -1
  254. package/dist/TopNav/TopNavMegaMenuFeaturedCard.js +8 -1
  255. package/dist/TopNav/TopNavMenu.d.ts +2 -1
  256. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  257. package/dist/TopNav/TopNavMenu.js +68 -6
  258. package/dist/TreeList/TreeList.d.ts +12 -3
  259. package/dist/TreeList/TreeList.d.ts.map +1 -1
  260. package/dist/TreeList/TreeList.js +2 -0
  261. package/dist/TreeList/TreeListBranches.d.ts +5 -0
  262. package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
  263. package/dist/TreeList/TreeListBranches.js +10 -4
  264. package/dist/TreeList/TreeListItem.d.ts +8 -2
  265. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  266. package/dist/TreeList/TreeListItem.js +28 -8
  267. package/dist/TreeList/TreeListTypes.d.ts +25 -1
  268. package/dist/TreeList/TreeListTypes.d.ts.map +1 -1
  269. package/dist/TreeList/index.d.ts +2 -2
  270. package/dist/TreeList/index.d.ts.map +1 -1
  271. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  272. package/dist/Typeahead/BaseTypeahead.js +20 -11
  273. package/dist/Typeahead/Typeahead.d.ts +9 -2
  274. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  275. package/dist/Typeahead/Typeahead.js +2 -0
  276. package/dist/astryx.css +41 -31
  277. package/dist/astryx.umd.js +51 -51
  278. package/dist/astryx.umd.js.map +4 -4
  279. package/dist/authoring/doc.d.ts.map +1 -1
  280. package/dist/docs-types.d.ts +8 -0
  281. package/dist/docs-types.d.ts.map +1 -1
  282. package/dist/hooks/computeOverflow.d.ts +47 -0
  283. package/dist/hooks/computeOverflow.d.ts.map +1 -0
  284. package/dist/hooks/computeOverflow.js +213 -0
  285. package/dist/hooks/index.d.ts +1 -0
  286. package/dist/hooks/index.d.ts.map +1 -1
  287. package/dist/hooks/index.js +2 -1
  288. package/dist/hooks/isRtlElement.d.ts +18 -0
  289. package/dist/hooks/isRtlElement.d.ts.map +1 -0
  290. package/dist/hooks/isRtlElement.js +27 -0
  291. package/dist/hooks/useDevWarning.d.ts +18 -0
  292. package/dist/hooks/useDevWarning.d.ts.map +1 -0
  293. package/dist/hooks/useDevWarning.js +49 -0
  294. package/dist/hooks/useGridFocus.d.ts +6 -1
  295. package/dist/hooks/useGridFocus.d.ts.map +1 -1
  296. package/dist/hooks/useGridFocus.js +12 -9
  297. package/dist/hooks/useListFocus.d.ts +6 -1
  298. package/dist/hooks/useListFocus.d.ts.map +1 -1
  299. package/dist/hooks/useListFocus.js +12 -4
  300. package/dist/hooks/useOverflow.d.ts +19 -0
  301. package/dist/hooks/useOverflow.d.ts.map +1 -1
  302. package/dist/hooks/useOverflow.js +36 -25
  303. package/dist/i18n/InternationalizationContext.d.ts +1 -0
  304. package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
  305. package/dist/i18n/InternationalizationContext.js +3 -0
  306. package/dist/i18n/InternationalizationProvider.d.ts +8 -1
  307. package/dist/i18n/InternationalizationProvider.d.ts.map +1 -1
  308. package/dist/i18n/InternationalizationProvider.js +5 -1
  309. package/dist/i18n/getLocaleDirection.d.ts +18 -0
  310. package/dist/i18n/getLocaleDirection.d.ts.map +1 -0
  311. package/dist/i18n/getLocaleDirection.js +29 -0
  312. package/dist/i18n/index.d.ts +6 -0
  313. package/dist/i18n/index.d.ts.map +1 -1
  314. package/dist/i18n/index.js +7 -1
  315. package/dist/i18n/resolve.d.ts.map +1 -1
  316. package/dist/i18n/resolve.js +7 -18
  317. package/dist/i18n/useDirection.d.ts +2 -0
  318. package/dist/i18n/useDirection.d.ts.map +1 -0
  319. package/dist/i18n/useDirection.js +27 -0
  320. package/dist/theme/Theme.d.ts.map +1 -1
  321. package/dist/theme/Theme.js +2 -7
  322. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  323. package/dist/theme/derivedVarRegistry.js +13 -0
  324. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  325. package/dist/theme/generateThemeRules.js +51 -0
  326. package/dist/theme/hct.d.ts +0 -1
  327. package/dist/theme/hct.d.ts.map +1 -1
  328. package/dist/theme/hct.js +1 -1
  329. package/dist/theme/syntax/defineSyntaxTheme.d.ts.map +1 -1
  330. package/dist/theme/syntax/defineSyntaxTheme.js +2 -1
  331. package/dist/utils/devWarning.d.ts +42 -0
  332. package/dist/utils/devWarning.d.ts.map +1 -0
  333. package/dist/utils/devWarning.js +88 -0
  334. package/dist/utils/index.d.ts +3 -1
  335. package/dist/utils/index.d.ts.map +1 -1
  336. package/dist/utils/index.js +3 -2
  337. package/dist/utils/plainDate.d.ts +30 -0
  338. package/dist/utils/plainDate.d.ts.map +1 -1
  339. package/dist/utils/plainDate.js +53 -0
  340. package/dist/utils/types.d.ts +13 -0
  341. package/dist/utils/types.d.ts.map +1 -1
  342. package/locales/en.json +32 -0
  343. package/locales/fr-FR.json +14 -0
  344. package/locales/pseudo.json +24 -0
  345. package/package.json +1 -1
  346. package/src/AppShell/AppShell.tsx +6 -0
  347. package/src/AppShell/AppShellMobileContext.tsx +8 -0
  348. package/src/AppShell/useAppShellMobile.doc.mjs +8 -0
  349. package/src/Avatar/Avatar.doc.mjs +60 -3
  350. package/src/Avatar/Avatar.test.tsx +281 -1
  351. package/src/Avatar/Avatar.tsx +324 -64
  352. package/src/Avatar/AvatarStatusDot.doc.mjs +23 -12
  353. package/src/Avatar/AvatarStatusDot.test.tsx +284 -0
  354. package/src/Avatar/AvatarStatusDot.tsx +178 -21
  355. package/src/AvatarGroup/AvatarGroup.doc.mjs +2 -0
  356. package/src/AvatarGroup/AvatarGroup.test.tsx +125 -0
  357. package/src/AvatarGroup/AvatarGroup.tsx +58 -3
  358. package/src/AvatarGroup/AvatarGroupOverflow.tsx +1 -0
  359. package/src/Banner/Banner.doc.mjs +9 -0
  360. package/src/Banner/Banner.test.tsx +30 -0
  361. package/src/Banner/Banner.tsx +53 -9
  362. package/src/Breadcrumbs/BreadcrumbItem.doc.mjs +26 -0
  363. package/src/Breadcrumbs/BreadcrumbItem.tsx +333 -14
  364. package/src/Breadcrumbs/Breadcrumbs.doc.mjs +2 -0
  365. package/src/Breadcrumbs/Breadcrumbs.test.tsx +284 -2
  366. package/src/Breadcrumbs/index.ts +27 -0
  367. package/src/Button/Button.doc.mjs +9 -0
  368. package/src/Button/Button.test.tsx +49 -0
  369. package/src/Button/Button.tsx +27 -3
  370. package/src/ButtonGroup/ButtonGroup.doc.mjs +3 -0
  371. package/src/ButtonGroup/ButtonGroup.test.tsx +37 -0
  372. package/src/ButtonGroup/ButtonGroup.tsx +32 -0
  373. package/src/Calendar/Calendar.doc.mjs +12 -1
  374. package/src/Calendar/Calendar.test.tsx +193 -0
  375. package/src/Calendar/Calendar.tsx +38 -16
  376. package/src/Calendar/dayCellUtils.test.ts +5 -0
  377. package/src/Calendar/dayCellUtils.ts +1 -1
  378. package/src/Card/Card.doc.mjs +9 -0
  379. package/src/Card/Card.test.tsx +21 -3
  380. package/src/Card/Card.tsx +35 -2
  381. package/src/Carousel/Carousel.doc.mjs +1 -0
  382. package/src/Carousel/Carousel.test.tsx +53 -0
  383. package/src/Carousel/Carousel.tsx +34 -4
  384. package/src/Chat/ChatComposer.doc.mjs +12 -3
  385. package/src/Chat/ChatComposer.test.tsx +115 -0
  386. package/src/Chat/ChatComposer.tsx +73 -9
  387. package/src/Chat/ChatComposerDrawer.test.tsx +61 -0
  388. package/src/Chat/ChatComposerDrawer.tsx +11 -1
  389. package/src/Chat/ChatComposerInput.doc.mjs +7 -0
  390. package/src/Chat/ChatComposerInput.test.tsx +103 -0
  391. package/src/Chat/ChatComposerInput.tsx +51 -5
  392. package/src/Chat/ChatContext.tsx +37 -10
  393. package/src/Chat/ChatDictationButton.tsx +4 -1
  394. package/src/Chat/ChatLayout.tsx +7 -5
  395. package/src/Chat/ChatLayoutScrollButton.tsx +7 -2
  396. package/src/Chat/ChatMessageMetadata.tsx +1 -2
  397. package/src/Chat/ChatSendButton.tsx +11 -1
  398. package/src/Chat/ChatToolCalls.test.tsx +64 -0
  399. package/src/Chat/ChatToolCalls.tsx +25 -4
  400. package/src/Chat/index.ts +5 -1
  401. package/src/Chat/useChatStreamScroll.test.tsx +49 -0
  402. package/src/Chat/useChatStreamScroll.ts +27 -10
  403. package/src/Chat/useSpeechRecognition.ts +1 -1
  404. package/src/Chat/useTriggerMenu.tsx +4 -2
  405. package/src/CheckboxInput/CheckboxInput.test.tsx +32 -1
  406. package/src/CheckboxInput/CheckboxInput.tsx +1 -1
  407. package/src/CheckboxList/CheckboxList.test.tsx +81 -3
  408. package/src/CheckboxList/CheckboxListItem.doc.mjs +33 -5
  409. package/src/CheckboxList/CheckboxListItem.tsx +41 -5
  410. package/src/Citation/Citation.doc.mjs +4 -3
  411. package/src/Citation/Citation.test.tsx +97 -0
  412. package/src/Citation/Citation.tsx +43 -11
  413. package/src/ClickableCard/ClickableCard.doc.mjs +2 -0
  414. package/src/ClickableCard/ClickableCard.test.tsx +34 -0
  415. package/src/ClickableCard/ClickableCard.tsx +13 -3
  416. package/src/CodeBlock/CodeBlock.test.tsx +56 -0
  417. package/src/CodeBlock/CodeBlock.tsx +10 -2
  418. package/src/CommandPalette/CommandPalette.doc.mjs +1 -0
  419. package/src/CommandPalette/CommandPalette.tsx +3 -1
  420. package/src/CommandPalette/CommandPaletteGroup.test.tsx +71 -0
  421. package/src/CommandPalette/CommandPaletteGroup.tsx +12 -1
  422. package/src/CommandPalette/CommandPaletteInput.doc.mjs +26 -9
  423. package/src/CommandPalette/CommandPaletteInput.test.tsx +34 -0
  424. package/src/CommandPalette/CommandPaletteInput.tsx +11 -0
  425. package/src/CommandPalette/CommandPaletteItem.tsx +1 -1
  426. package/src/ContextMenu/ContextMenu.test.tsx +193 -0
  427. package/src/DateInput/DateInput.doc.mjs +31 -0
  428. package/src/DateInput/DateInput.test.tsx +131 -0
  429. package/src/DateInput/DateInput.tsx +78 -3
  430. package/src/DateInput/index.ts +1 -0
  431. package/src/DateRangeInput/DateRangeInput.doc.mjs +8 -0
  432. package/src/DateRangeInput/DateRangeInput.test.tsx +23 -0
  433. package/src/DateRangeInput/DateRangeInput.tsx +13 -3
  434. package/src/DateTimeInput/DateTimeInput.doc.mjs +16 -1
  435. package/src/DateTimeInput/DateTimeInput.test.tsx +147 -0
  436. package/src/DateTimeInput/DateTimeInput.tsx +42 -18
  437. package/src/Dialog/Dialog.doc.mjs +2 -2
  438. package/src/Dialog/Dialog.test.tsx +77 -4
  439. package/src/Dialog/Dialog.tsx +89 -5
  440. package/src/Dialog/DialogContext.ts +9 -2
  441. package/src/Dialog/DialogHeader.doc.mjs +2 -2
  442. package/src/Dialog/DialogHeader.tsx +9 -2
  443. package/src/Divider/Divider.tsx +2 -2
  444. package/src/DropdownMenu/DropdownMenu.test.tsx +169 -0
  445. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +1 -2
  446. package/src/DropdownMenu/DropdownMenuItem.tsx +1 -1
  447. package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +1 -2
  448. package/src/Field/Field.test.tsx +57 -12
  449. package/src/Field/Field.tsx +6 -5
  450. package/src/Field/FieldLabel.tsx +9 -1
  451. package/src/FieldStatus/FieldStatus.doc.mjs +17 -5
  452. package/src/FieldStatus/FieldStatus.test.tsx +150 -40
  453. package/src/FieldStatus/FieldStatus.tsx +63 -5
  454. package/src/FileInput/FileInput.doc.mjs +17 -2
  455. package/src/FileInput/FileInput.test.tsx +135 -12
  456. package/src/FileInput/FileInput.tsx +53 -28
  457. package/src/HoverCard/HoverCard.doc.mjs +13 -0
  458. package/src/HoverCard/HoverCard.test.tsx +21 -2
  459. package/src/HoverCard/HoverCard.tsx +11 -0
  460. package/src/HoverCard/useHoverCard.doc.mjs +2 -0
  461. package/src/HoverCard/useHoverCard.tsx +24 -2
  462. package/src/Icon/Icon.doc.mjs +3 -2
  463. package/src/Icon/Icon.tsx +7 -2
  464. package/src/IconButton/IconButton.doc.mjs +8 -0
  465. package/src/IconButton/IconButton.test.tsx +15 -18
  466. package/src/Item/Item.test.tsx +40 -18
  467. package/src/Item/Item.tsx +38 -2
  468. package/src/Layer/useLayer.tsx +8 -0
  469. package/src/Lightbox/Lightbox.tsx +4 -4
  470. package/src/List/List.test.tsx +9 -8
  471. package/src/MobileNav/MobileNav.tsx +12 -1
  472. package/src/MobileNav/MobileNavToggle.test.tsx +116 -0
  473. package/src/MobileNav/MobileNavToggle.tsx +9 -1
  474. package/src/MultiSelector/MultiSelector.doc.mjs +13 -2
  475. package/src/MultiSelector/MultiSelector.test.tsx +195 -3
  476. package/src/MultiSelector/MultiSelector.tsx +65 -12
  477. package/src/MultiSelector/hooks.ts +17 -0
  478. package/src/NavMenu/NavHeadingMenuItem.tsx +1 -1
  479. package/src/NumberInput/NumberInput.doc.mjs +15 -0
  480. package/src/NumberInput/NumberInput.test.tsx +82 -7
  481. package/src/NumberInput/NumberInput.tsx +21 -4
  482. package/src/Outline/Outline.tsx +0 -1
  483. package/src/OverflowList/OverflowList.doc.mjs +39 -6
  484. package/src/OverflowList/OverflowList.test.tsx +111 -0
  485. package/src/OverflowList/OverflowList.tsx +48 -8
  486. package/src/Pagination/Pagination.tsx +11 -3
  487. package/src/Popover/Popover.tsx +7 -4
  488. package/src/Popover/usePopover.tsx +9 -13
  489. package/src/PowerSearch/PowerSearch.doc.mjs +29 -0
  490. package/src/PowerSearch/PowerSearch.test.tsx +43 -0
  491. package/src/PowerSearch/PowerSearch.tsx +10 -1
  492. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +67 -0
  493. package/src/PowerSearch/PowerSearchEditPopover.tsx +1 -1
  494. package/src/PowerSearch/usePowerSearchSource.ts +1 -2
  495. package/src/SelectableCard/SelectableCard.doc.mjs +2 -0
  496. package/src/SelectableCard/SelectableCard.test.tsx +46 -4
  497. package/src/SelectableCard/SelectableCard.tsx +29 -16
  498. package/src/Selector/Selector.doc.mjs +7 -0
  499. package/src/Selector/Selector.test.tsx +92 -0
  500. package/src/Selector/Selector.tsx +16 -2
  501. package/src/Selector/hooks.ts +17 -0
  502. package/src/SideNav/SideNav.test.tsx +119 -3
  503. package/src/SideNav/SideNavCollapseButton.tsx +6 -1
  504. package/src/SideNav/SideNavHeading.tsx +24 -8
  505. package/src/SideNav/SideNavItem.tsx +5 -1
  506. package/src/Slider/Slider.test.tsx +75 -2
  507. package/src/Slider/Slider.tsx +21 -5
  508. package/src/Switch/Switch.test.tsx +32 -1
  509. package/src/TabList/Tab.tsx +2 -2
  510. package/src/TabList/TabMenu.tsx +2 -2
  511. package/src/Table/BaseTable.tsx +3 -5
  512. package/src/Table/TableCell.tsx +3 -3
  513. package/src/Table/TableHeaderCell.tsx +3 -3
  514. package/src/Table/index.ts +5 -0
  515. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +6 -2
  516. package/src/Table/plugins/rowStatus/index.ts +7 -0
  517. package/src/Table/plugins/rowStatus/useTableRowStatus.test.tsx +138 -0
  518. package/src/Table/plugins/rowStatus/useTableRowStatus.tsx +189 -0
  519. package/src/Table/plugins/selection/useTableSelection.test.tsx +16 -0
  520. package/src/Table/plugins/selection/useTableSelection.tsx +19 -1
  521. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +1 -1
  522. package/src/Table/plugins/tree/useTableTreeData.test.tsx +135 -3
  523. package/src/Table/plugins/tree/useTableTreeData.tsx +128 -1
  524. package/src/Table/plugins/tree/useTableTreeState.test.tsx +104 -0
  525. package/src/Table/plugins/tree/useTableTreeState.tsx +46 -2
  526. package/src/Table/useBaseTablePlugins.ts +10 -6
  527. package/src/Table/useTableRowStatus.doc.mjs +30 -0
  528. package/src/Table/useTableSelection.doc.mjs +65 -14
  529. package/src/Table/useTableTreeData.doc.mjs +29 -0
  530. package/src/Table/useTableTreeState.doc.mjs +2 -2
  531. package/src/TextArea/TextArea.doc.mjs +15 -0
  532. package/src/TextArea/TextArea.test.tsx +32 -1
  533. package/src/TextArea/TextArea.tsx +10 -0
  534. package/src/TextInput/TextInput.doc.mjs +15 -0
  535. package/src/TextInput/TextInput.test.tsx +44 -0
  536. package/src/TextInput/TextInput.tsx +13 -1
  537. package/src/Thumbnail/Thumbnail.doc.mjs +19 -10
  538. package/src/Thumbnail/Thumbnail.test.tsx +98 -7
  539. package/src/Thumbnail/Thumbnail.tsx +142 -42
  540. package/src/Thumbnail/thumbnail.markers.stylex.ts +12 -0
  541. package/src/TimeInput/TimeInput.doc.mjs +15 -0
  542. package/src/TimeInput/TimeInput.test.tsx +99 -1
  543. package/src/TimeInput/TimeInput.tsx +29 -6
  544. package/src/Timestamp/Timestamp.doc.mjs +4 -4
  545. package/src/Timestamp/Timestamp.test.tsx +32 -0
  546. package/src/Timestamp/Timestamp.tsx +28 -8
  547. package/src/Toast/useToast.tsx +7 -8
  548. package/src/ToggleButton/ToggleButtonGroup.tsx +1 -1
  549. package/src/Tokenizer/Tokenizer.doc.mjs +30 -1
  550. package/src/Tokenizer/Tokenizer.test.tsx +206 -2
  551. package/src/Tokenizer/Tokenizer.tsx +26 -4
  552. package/src/TopNav/TopNav.test.tsx +125 -1
  553. package/src/TopNav/TopNavHeading.tsx +24 -8
  554. package/src/TopNav/TopNavMegaMenu.test.tsx +149 -1
  555. package/src/TopNav/TopNavMegaMenu.tsx +10 -4
  556. package/src/TopNav/TopNavMegaMenuFeaturedCard.doc.mjs +3 -3
  557. package/src/TopNav/TopNavMegaMenuFeaturedCard.tsx +19 -2
  558. package/src/TopNav/TopNavMenu.test.tsx +118 -4
  559. package/src/TopNav/TopNavMenu.tsx +83 -5
  560. package/src/TreeList/TreeList.doc.mjs +22 -0
  561. package/src/TreeList/TreeList.test.tsx +232 -0
  562. package/src/TreeList/TreeList.tsx +18 -2
  563. package/src/TreeList/TreeListBranches.tsx +16 -2
  564. package/src/TreeList/TreeListItem.tsx +52 -12
  565. package/src/TreeList/TreeListTypes.ts +27 -1
  566. package/src/TreeList/index.ts +2 -2
  567. package/src/Typeahead/BaseTypeahead.tsx +30 -15
  568. package/src/Typeahead/Typeahead.doc.mjs +7 -0
  569. package/src/Typeahead/Typeahead.test.tsx +50 -0
  570. package/src/Typeahead/Typeahead.tsx +10 -0
  571. package/src/authoring/doc.ts +1 -3
  572. package/src/docs-types.ts +5 -0
  573. package/src/hooks/computeOverflow.test.ts +422 -0
  574. package/src/hooks/computeOverflow.ts +290 -0
  575. package/src/hooks/index.ts +2 -0
  576. package/src/hooks/isRtlElement.ts +27 -0
  577. package/src/hooks/useDevWarning.test.tsx +45 -0
  578. package/src/hooks/useDevWarning.ts +54 -0
  579. package/src/hooks/useGridFocus.doc.mjs +3 -3
  580. package/src/hooks/useGridFocus.test.tsx +41 -0
  581. package/src/hooks/useGridFocus.ts +21 -10
  582. package/src/hooks/useListFocus.doc.mjs +3 -3
  583. package/src/hooks/useListFocus.test.tsx +67 -1
  584. package/src/hooks/useListFocus.ts +21 -5
  585. package/src/hooks/useOverflow.test.ts +96 -4
  586. package/src/hooks/useOverflow.ts +74 -33
  587. package/src/i18n/InternationalizationContext.ts +4 -0
  588. package/src/i18n/InternationalizationProvider.doc.mjs +99 -2
  589. package/src/i18n/InternationalizationProvider.tsx +12 -2
  590. package/src/i18n/__tests__/getLocaleDirection.test.ts +40 -0
  591. package/src/i18n/__tests__/useDirection.test.tsx +66 -0
  592. package/src/i18n/getLocaleDirection.ts +29 -0
  593. package/src/i18n/index.ts +6 -0
  594. package/src/i18n/resolve.ts +9 -21
  595. package/src/i18n/useDirection.ts +29 -0
  596. package/src/reset.css +0 -26
  597. package/src/reset.test.ts +60 -0
  598. package/src/theme/Theme.tsx +11 -14
  599. package/src/theme/derivedVarRegistry.test.ts +1 -0
  600. package/src/theme/derivedVarRegistry.ts +6 -0
  601. package/src/theme/generateThemeRules.test.ts +107 -0
  602. package/src/theme/generateThemeRules.ts +56 -0
  603. package/src/theme/hct.ts +1 -1
  604. package/src/theme/syntax/defineSyntaxTheme.ts +5 -6
  605. package/src/utils/devWarning.test.ts +56 -0
  606. package/src/utils/devWarning.ts +102 -0
  607. package/src/utils/index.ts +6 -0
  608. package/src/utils/plainDate.test.ts +22 -0
  609. package/src/utils/plainDate.ts +61 -0
  610. package/src/utils/types.ts +14 -0
@@ -0,0 +1,290 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file computeOverflow.ts
5
+ * @input Plain measurements (item widths, gap, available width, indicator width, limits)
6
+ * @output Pure overflow computation: how many items are visible and their row layout
7
+ * @position Pure helper consumed by useOverflow; contains no DOM or React code so the
8
+ * fit/clamp math and the multi-row packing can be unit-tested in isolation.
9
+ *
10
+ * There is a single source of truth for `visibleCount`:
11
+ * visibleCount = clamp(fitCount, minVisibleItems, maxVisibleItems ?? itemCount)
12
+ *
13
+ * SYNC: When modified, update:
14
+ * - /packages/core/src/hooks/useOverflow.ts (the only caller)
15
+ */
16
+
17
+ export interface ComputeOverflowInput {
18
+ /** Measured widths of each item, in original DOM order. */
19
+ widths: number[];
20
+ /** Gap between items, in pixels. */
21
+ gap: number;
22
+ /** Width available to lay items out, in pixels. */
23
+ availableWidth: number;
24
+ /** Measured width of the overflow indicator (0 if none). */
25
+ indicatorWidth: number;
26
+ /** Floor — always show at least this many items. */
27
+ minVisibleItems: number;
28
+ /** Ceiling — never show more than this many items. `undefined` = no cap. */
29
+ maxVisibleItems?: number;
30
+ /**
31
+ * Bounded multi-row: wrap items across up to this many rows, then collapse
32
+ * the rest into the overflow indicator. `undefined` (or `1`) = single line.
33
+ */
34
+ maxRows?: number;
35
+ /** Which end items collapse from. */
36
+ collapseFrom: 'start' | 'end';
37
+ }
38
+
39
+ export interface ComputeOverflowResult {
40
+ /** Number of items that should be rendered in the visible container. */
41
+ visibleCount: number;
42
+ /** Number of rows the visible items occupy (always 1 for the single-line path). */
43
+ rows: number;
44
+ }
45
+
46
+ function clamp(value: number, min: number, max: number): number {
47
+ return Math.max(Math.min(value, max), min);
48
+ }
49
+
50
+ /**
51
+ * Resolve the ceiling and floor into a single [floor, ceiling] pair.
52
+ *
53
+ * `maxVisibleItems` is clamped to `itemCount` (a cap larger than the list is a
54
+ * no-op). When `maxVisibleItems < minVisibleItems`, the floor wins (D1) via the
55
+ * final clamp — the hook is responsible for the dev-only warning.
56
+ */
57
+ function resolveBounds(
58
+ itemCount: number,
59
+ minVisibleItems: number,
60
+ maxVisibleItems: number | undefined,
61
+ ): {floor: number; ceiling: number} {
62
+ const floor = Math.max(0, Math.min(minVisibleItems, itemCount));
63
+ const rawCeiling = maxVisibleItems == null ? itemCount : maxVisibleItems;
64
+ const ceiling = Math.max(0, Math.min(rawCeiling, itemCount));
65
+ return {floor, ceiling};
66
+ }
67
+
68
+ /**
69
+ * Single-line greedy fit: how many items fit in one row of `availableWidth`,
70
+ * reserving indicator space for every non-final admitted item. Mirrors the
71
+ * original in-hook loop so single-line behavior is unchanged.
72
+ */
73
+ function computeSingleLineFit(
74
+ orderedWidths: number[],
75
+ gap: number,
76
+ availableWidth: number,
77
+ indicatorWidth: number,
78
+ floor: number,
79
+ ceiling: number,
80
+ ): number {
81
+ let totalWidth = 0;
82
+ let count = 0;
83
+
84
+ for (let i = 0; i < orderedWidths.length; i++) {
85
+ if (count >= ceiling) {
86
+ break;
87
+ }
88
+
89
+ const itemWidth = orderedWidths[i];
90
+ const gapWidth = i > 0 ? gap : 0;
91
+ const candidateWidth = totalWidth + itemWidth + gapWidth;
92
+
93
+ const isLastItem = i === orderedWidths.length - 1;
94
+ const reservedWidth = isLastItem
95
+ ? 0
96
+ : indicatorWidth + (count > 0 || indicatorWidth > 0 ? gap : 0);
97
+
98
+ if (candidateWidth + reservedWidth > availableWidth && count >= floor) {
99
+ break;
100
+ }
101
+
102
+ totalWidth = candidateWidth;
103
+ count++;
104
+ }
105
+
106
+ return count;
107
+ }
108
+
109
+ /**
110
+ * Pack items into rows, wrapping when the next item would exceed
111
+ * `availableWidth`. On the last allowed row, keep `indicatorReserve` px free so
112
+ * the overflow indicator fits. Stops admitting once no further item can be
113
+ * placed within `maxRows`.
114
+ */
115
+ function packRows(
116
+ orderedWidths: number[],
117
+ gap: number,
118
+ availableWidth: number,
119
+ indicatorReserve: number,
120
+ maxRows: number,
121
+ ): {placed: number; rows: number} {
122
+ let placed = 0;
123
+ let row = 1;
124
+ let rowWidth = 0;
125
+
126
+ for (let i = 0; i < orderedWidths.length; i++) {
127
+ const w = orderedWidths[i];
128
+ const isFirstInRow = rowWidth === 0;
129
+ const candidate = isFirstInRow ? w : rowWidth + gap + w;
130
+
131
+ const onLastRow = row === maxRows;
132
+ const reserve =
133
+ onLastRow && indicatorReserve > 0 ? indicatorReserve + gap : 0;
134
+
135
+ if (candidate + reserve <= availableWidth) {
136
+ rowWidth = candidate;
137
+ placed++;
138
+ continue;
139
+ }
140
+
141
+ if (isFirstInRow) {
142
+ // A single item wider than the row occupies this row alone (it will be
143
+ // clipped visually). But if it can't coexist with the reserved indicator
144
+ // on the last row, stop here.
145
+ if (onLastRow && reserve > 0) {
146
+ break;
147
+ }
148
+ rowWidth = candidate;
149
+ placed++;
150
+ continue;
151
+ }
152
+
153
+ if (row >= maxRows) {
154
+ break;
155
+ }
156
+ row++;
157
+ rowWidth = 0;
158
+ i--; // re-attempt this item as the first on the new row
159
+ }
160
+
161
+ return {placed, rows: row};
162
+ }
163
+
164
+ /** Count how many rows a set of items occupies when wrapped at availableWidth. */
165
+ function countRows(
166
+ orderedWidths: number[],
167
+ gap: number,
168
+ availableWidth: number,
169
+ ): number {
170
+ if (orderedWidths.length === 0) {
171
+ return 0;
172
+ }
173
+ let rows = 1;
174
+ let rowWidth = 0;
175
+ for (let i = 0; i < orderedWidths.length; i++) {
176
+ const w = orderedWidths[i];
177
+ const isFirstInRow = rowWidth === 0;
178
+ const candidate = isFirstInRow ? w : rowWidth + gap + w;
179
+ if (candidate <= availableWidth || isFirstInRow) {
180
+ rowWidth = candidate;
181
+ } else {
182
+ rows++;
183
+ rowWidth = w;
184
+ }
185
+ }
186
+ return rows;
187
+ }
188
+
189
+ /**
190
+ * Multi-row packing (Strategy A): simulate wrapping items into rows of
191
+ * `availableWidth`, admitting items until a new item would require a row beyond
192
+ * `maxRows`, reserving indicator space on the final row when items overflow.
193
+ * Returns the admitted count and how many rows those items occupy. Assumes
194
+ * uniform row height.
195
+ */
196
+ function computeMultiRowFit(
197
+ orderedWidths: number[],
198
+ gap: number,
199
+ availableWidth: number,
200
+ indicatorWidth: number,
201
+ maxRows: number,
202
+ ): {count: number; rows: number} {
203
+ const n = orderedWidths.length;
204
+ if (n === 0) {
205
+ return {count: 0, rows: 0};
206
+ }
207
+
208
+ // If everything fits within maxRows without reserving indicator space, there
209
+ // is no overflow and no indicator is needed.
210
+ const packAll = packRows(orderedWidths, gap, availableWidth, 0, maxRows);
211
+ if (packAll.placed === n) {
212
+ return {count: n, rows: packAll.rows};
213
+ }
214
+
215
+ // Overflow → reserve indicator space on the final row and re-pack.
216
+ const packWithIndicator = packRows(
217
+ orderedWidths,
218
+ gap,
219
+ availableWidth,
220
+ indicatorWidth,
221
+ maxRows,
222
+ );
223
+
224
+ const count = packWithIndicator.placed;
225
+ const rows = countRows(orderedWidths.slice(0, count), gap, availableWidth);
226
+
227
+ return {count, rows: Math.max(count > 0 ? 1 : 0, rows)};
228
+ }
229
+
230
+ /**
231
+ * Pure overflow computation. Given plain measurements and the configured
232
+ * limits, return how many items should be visible and how many rows they
233
+ * occupy. No DOM, no React — safe to unit-test directly.
234
+ */
235
+ export function computeOverflow(
236
+ input: ComputeOverflowInput,
237
+ ): ComputeOverflowResult {
238
+ const {
239
+ widths,
240
+ gap,
241
+ availableWidth,
242
+ indicatorWidth,
243
+ minVisibleItems,
244
+ maxVisibleItems,
245
+ maxRows,
246
+ collapseFrom,
247
+ } = input;
248
+
249
+ const itemCount = widths.length;
250
+ if (itemCount === 0) {
251
+ return {visibleCount: 0, rows: 0};
252
+ }
253
+
254
+ const {floor, ceiling} = resolveBounds(
255
+ itemCount,
256
+ minVisibleItems,
257
+ maxVisibleItems,
258
+ );
259
+
260
+ const orderedWidths = collapseFrom === 'end' ? widths : [...widths].reverse();
261
+
262
+ const multiRow = maxRows != null && maxRows > 1;
263
+
264
+ if (!multiRow) {
265
+ const fitCount = computeSingleLineFit(
266
+ orderedWidths,
267
+ gap,
268
+ availableWidth,
269
+ indicatorWidth,
270
+ floor,
271
+ ceiling,
272
+ );
273
+ const visibleCount = clamp(fitCount, floor, ceiling);
274
+ return {visibleCount, rows: visibleCount > 0 ? 1 : 0};
275
+ }
276
+
277
+ const {count, rows} = computeMultiRowFit(
278
+ orderedWidths,
279
+ gap,
280
+ availableWidth,
281
+ indicatorWidth,
282
+ maxRows,
283
+ );
284
+ const visibleCount = clamp(count, floor, ceiling);
285
+ const resolvedRows =
286
+ visibleCount === count
287
+ ? rows
288
+ : countRows(orderedWidths.slice(0, visibleCount), gap, availableWidth);
289
+ return {visibleCount, rows: visibleCount > 0 ? Math.max(1, resolvedRows) : 0};
290
+ }
@@ -84,3 +84,5 @@ export type {
84
84
 
85
85
  export {useLongPress} from './useLongPress';
86
86
  export type {UseLongPressOptions, UseLongPressHandlers} from './useLongPress';
87
+
88
+ export {useDevWarning} from './useDevWarning';
@@ -0,0 +1,27 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file isRtlElement.ts
7
+ * @input DOM element (nullable)
8
+ * @output Exports isRtlElement helper resolving an element's computed text
9
+ * direction
10
+ * @position Internal hook utility; used by useListFocus and useGridFocus to
11
+ * auto-detect RTL for arrow-key navigation (same getComputedStyle precedent
12
+ * as Resizable's ResizeHandle drag deltas).
13
+ */
14
+
15
+ /**
16
+ * Whether `el` renders right-to-left, per its computed `direction`.
17
+ *
18
+ * SSR-safe: returns false when `el` is null or no DOM is available. Callers
19
+ * should invoke this lazily (on keydown, not on render) so getComputedStyle
20
+ * runs only when a horizontal arrow key is actually handled.
21
+ */
22
+ export function isRtlElement(el: HTMLElement | null): boolean {
23
+ if (!el || typeof window === 'undefined') {
24
+ return false;
25
+ }
26
+ return window.getComputedStyle(el).direction === 'rtl';
27
+ }
@@ -0,0 +1,45 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ import {afterEach, describe, expect, it, vi} from 'vitest';
4
+ import {render} from '@testing-library/react';
5
+ import {useDevWarning} from './useDevWarning';
6
+
7
+ afterEach(() => {
8
+ vi.restoreAllMocks();
9
+ });
10
+
11
+ function Probe({
12
+ condition,
13
+ message = 'boom',
14
+ }: {
15
+ condition: boolean;
16
+ message?: string;
17
+ }) {
18
+ useDevWarning('TestComponent', message, condition);
19
+ return null;
20
+ }
21
+
22
+ describe('useDevWarning', () => {
23
+ it('warns once, in the standardized format, when the condition is true', () => {
24
+ const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
25
+ const {rerender} = render(<Probe condition={true} />);
26
+ rerender(<Probe condition={true} />);
27
+ rerender(<Probe condition={true} />);
28
+ expect(warn).toHaveBeenCalledTimes(1);
29
+ expect(warn).toHaveBeenCalledWith('TestComponent: boom');
30
+ });
31
+
32
+ it('does not warn when the condition is false', () => {
33
+ const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
34
+ render(<Probe condition={false} />);
35
+ expect(warn).not.toHaveBeenCalled();
36
+ });
37
+
38
+ it('warns after the condition flips from false to true', () => {
39
+ const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
40
+ const {rerender} = render(<Probe condition={false} />);
41
+ expect(warn).not.toHaveBeenCalled();
42
+ rerender(<Probe condition={true} />);
43
+ expect(warn).toHaveBeenCalledTimes(1);
44
+ });
45
+ });
@@ -0,0 +1,54 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file useDevWarning.ts
7
+ * @input A component name, a message, and a boolean condition
8
+ * @output Fires a dev-only `Component: message` warning once per mount
9
+ * @position Core hook; the render-safe way to warn the builder from a component
10
+ *
11
+ * The right way to surface a dev guardrail from inside a component. A naive
12
+ * `if (condition) console.warn(...)` in the render body repeats on every
13
+ * render, and reaching for `useState` to gate it adds needless state and
14
+ * re-renders. This hook uses a ref + effect: the warning fires once per mount
15
+ * when the condition holds, never during render, and never triggers a
16
+ * re-render. Messages use the standardized `Component: message` format.
17
+ *
18
+ * SYNC: When modified, update:
19
+ * - /packages/core/src/hooks/index.ts
20
+ * - /packages/core/src/utils/devWarning.ts (the imperative counterpart)
21
+ */
22
+
23
+ import {useEffect, useRef} from 'react';
24
+ import {devWarn} from '../utils/devWarning';
25
+
26
+ /**
27
+ * Fire a dev-only warning once per mount while `condition` is true.
28
+ *
29
+ * @param component - Component or hook name (message prefix)
30
+ * @param message - What went wrong and how to fix it
31
+ * @param condition - Whether to warn; defaults to `true`
32
+ *
33
+ * @example
34
+ * ```
35
+ * useDevWarning(
36
+ * 'Field',
37
+ * 'isOptional and isRequired are mutually exclusive. isOptional takes precedence.',
38
+ * isOptional && isRequired,
39
+ * );
40
+ * ```
41
+ */
42
+ export function useDevWarning(
43
+ component: string,
44
+ message: string,
45
+ condition: boolean = true,
46
+ ): void {
47
+ const hasWarnedRef = useRef(false);
48
+ useEffect(() => {
49
+ if (condition && !hasWarnedRef.current) {
50
+ hasWarnedRef.current = true;
51
+ devWarn(component, message);
52
+ }
53
+ }, [component, message, condition]);
54
+ }
@@ -64,8 +64,8 @@ export const docs = {
64
64
  {
65
65
  name: 'options.isRtl',
66
66
  type: 'boolean',
67
- description: 'Swap ArrowLeft/ArrowRight so horizontal navigation follows visual direction in right-to-left contexts.',
68
- default: 'false',
67
+ description: 'Swap ArrowLeft/ArrowRight so horizontal navigation follows visual direction in right-to-left contexts. When omitted, auto-detected from the container computed direction on keydown.',
68
+ default: "undefined (auto-detect from the container's computed direction)",
69
69
  required: false,
70
70
  },
71
71
  {
@@ -138,7 +138,7 @@ export const docsDense = {
138
138
  'options.onNavigateAfter': 'callback when navigation would go after last cell. Receives column index + offset.',
139
139
  'options.onPageUp': 'callback for Page Up key (e.g. navigate to previous month in calendars).',
140
140
  'options.onPageDown': 'callback for Page Down key (e.g. navigate to next month in calendars).',
141
- 'options.isRtl': 'swap ArrowLeft/ArrowRight for RTL horizontal navigation. default false.',
141
+ 'options.isRtl': 'swap ArrowLeft/ArrowRight for RTL horizontal navigation. default: auto-detect from container computed direction; explicit boolean wins.',
142
142
  'options.hasRovingTabIndex': 'own a single roving tab stop across the grid (one focus target tabindex=0, rest -1); repaired on render + moved with arrows. Attach handleFocus to onFocus. default false.',
143
143
  },
144
144
  returnDescriptions: {
@@ -23,10 +23,12 @@ const NO_DISABLED: number[] = [];
23
23
  function Grid({
24
24
  disabled = NO_DISABLED,
25
25
  seed = 0,
26
+ dir,
26
27
  ...opts
27
28
  }: {
28
29
  disabled?: number[];
29
30
  seed?: number;
31
+ dir?: 'ltr' | 'rtl';
30
32
  } & Partial<Parameters<typeof useGridFocus>[0]>) {
31
33
  const {gridRef, handleKeyDown, handleFocus} = useGridFocus<HTMLDivElement>({
32
34
  columns: 3,
@@ -41,6 +43,7 @@ function Grid({
41
43
  <div
42
44
  ref={gridRef}
43
45
  role="grid"
46
+ dir={dir}
44
47
  onKeyDown={handleKeyDown}
45
48
  onFocus={handleFocus}>
46
49
  {Array.from({length: 9}, (_, i) => (
@@ -130,3 +133,41 @@ describe('useGridFocus roving tabindex (hasRovingTabIndex)', () => {
130
133
  expect(screen.getByTestId('cell-1')).toHaveAttribute('tabindex', '-1');
131
134
  });
132
135
  });
136
+
137
+ describe('useGridFocus RTL auto-detection (WCAG 1.3.2)', () => {
138
+ // jsdom reflects the `dir` attribute into computed style only on the element
139
+ // that carries it, so tests set dir="rtl" on the grid container itself — the
140
+ // element the hook reads via gridRef.
141
+
142
+ it('auto-detects dir="rtl": ArrowLeft moves forward (next cell)', () => {
143
+ render(<Grid seed={1} dir="rtl" />);
144
+ const grid = screen.getByRole('grid');
145
+ screen.getByTestId('cell-1').focus();
146
+ fireEvent.keyDown(grid, {key: 'ArrowLeft'});
147
+ expect(screen.getByTestId('cell-2')).toHaveFocus();
148
+ });
149
+
150
+ it('auto-detects dir="rtl": ArrowRight moves backward (previous cell)', () => {
151
+ render(<Grid seed={1} dir="rtl" />);
152
+ const grid = screen.getByRole('grid');
153
+ screen.getByTestId('cell-1').focus();
154
+ fireEvent.keyDown(grid, {key: 'ArrowRight'});
155
+ expect(screen.getByTestId('cell-0')).toHaveFocus();
156
+ });
157
+
158
+ it('leaves vertical navigation unaffected under dir="rtl"', () => {
159
+ render(<Grid seed={0} dir="rtl" />);
160
+ const grid = screen.getByRole('grid');
161
+ screen.getByTestId('cell-0').focus();
162
+ fireEvent.keyDown(grid, {key: 'ArrowDown'});
163
+ expect(screen.getByTestId('cell-3')).toHaveFocus();
164
+ });
165
+
166
+ it('explicit isRtl={false} overrides a dir="rtl" container', () => {
167
+ render(<Grid seed={1} dir="rtl" isRtl={false} />);
168
+ const grid = screen.getByRole('grid');
169
+ screen.getByTestId('cell-1').focus();
170
+ fireEvent.keyDown(grid, {key: 'ArrowRight'});
171
+ expect(screen.getByTestId('cell-2')).toHaveFocus();
172
+ });
173
+ });
@@ -4,9 +4,12 @@
4
4
 
5
5
  /**
6
6
  * @file useGridFocus.ts
7
- * @input Uses React useCallback, useRef, useIsomorphicLayoutEffect
7
+ * @input Uses React useCallback, useRef, useIsomorphicLayoutEffect,
8
+ * isRtlElement
8
9
  * @output Exports useGridFocus hook for grid keyboard navigation
9
- * @position Core hook; used by Calendar for date grid navigation
10
+ * @position Core hook; used by Calendar for date grid navigation. Auto-detects
11
+ * RTL from the container's computed direction so horizontal arrow keys
12
+ * follow visual direction (WCAG 1.3.2).
10
13
  *
11
14
  * SYNC: When modified, update:
12
15
  * - /packages/core/src/hooks/index.ts
@@ -14,6 +17,7 @@
14
17
  */
15
18
 
16
19
  import {useCallback, useRef} from 'react';
20
+ import {isRtlElement} from './isRtlElement';
17
21
  import {useIsomorphicLayoutEffect} from './useIsomorphicLayoutEffect';
18
22
 
19
23
  /**
@@ -88,7 +92,12 @@ export interface UseGridFocusOptions {
88
92
  /**
89
93
  * Whether the grid is in a right-to-left context. When true, ArrowLeft and
90
94
  * ArrowRight are swapped so horizontal navigation follows visual direction.
91
- * @default false
95
+ *
96
+ * When omitted, the direction is auto-detected from the container's computed
97
+ * `direction` (read lazily on keydown, only for horizontal arrow keys), so
98
+ * grids inside `dir="rtl"` subtrees flip automatically. Pass an explicit
99
+ * boolean to override detection.
100
+ * @default undefined (auto-detect from the container)
92
101
  */
93
102
  isRtl?: boolean;
94
103
 
@@ -217,7 +226,7 @@ export function useGridFocus<T extends HTMLElement = HTMLElement>(
217
226
  onNavigateAfter,
218
227
  onPageUp,
219
228
  onPageDown,
220
- isRtl = false,
229
+ isRtl,
221
230
  hasRovingTabIndex = false,
222
231
  } = options;
223
232
 
@@ -455,13 +464,15 @@ export function useGridFocus<T extends HTMLElement = HTMLElement>(
455
464
 
456
465
  // In RTL, ArrowLeft/ArrowRight are swapped so horizontal navigation
457
466
  // follows visual direction. Vertical keys (Up/Down) are unaffected.
467
+ // Direction is resolved lazily — getComputedStyle runs only when a
468
+ // horizontal arrow key is actually pressed (SSR-safe, no layout thrash
469
+ // on unrelated keys) — and an explicit `isRtl` always wins.
458
470
  let key = e.key;
459
- if (isRtl) {
460
- if (key === 'ArrowLeft') {
461
- key = 'ArrowRight';
462
- } else if (key === 'ArrowRight') {
463
- key = 'ArrowLeft';
464
- }
471
+ if (
472
+ (key === 'ArrowLeft' || key === 'ArrowRight') &&
473
+ (isRtl ?? isRtlElement(gridRef.current))
474
+ ) {
475
+ key = key === 'ArrowLeft' ? 'ArrowRight' : 'ArrowLeft';
465
476
  }
466
477
 
467
478
  switch (key) {
@@ -49,8 +49,8 @@ export const docs = {
49
49
  {
50
50
  name: 'options.isRtl',
51
51
  type: 'boolean',
52
- description: 'Whether the list is in a right-to-left context. When true, ArrowLeft/ArrowRight are swapped for horizontal navigation so it follows visual direction.',
53
- default: 'false',
52
+ description: 'Whether the list is in a right-to-left context. When true, ArrowLeft/ArrowRight are swapped for horizontal navigation so it follows visual direction. When omitted, auto-detected from the container computed direction on keydown.',
53
+ default: "undefined (auto-detect from the container's computed direction)",
54
54
  required: false,
55
55
  },
56
56
  {
@@ -127,7 +127,7 @@ export const docsDense = {
127
127
  'options.onEscape': 'callback when Escape key pressed (e.g. close menu).',
128
128
  'options.orientation': "navigation orientation. 'horizontal' uses ArrowLeft/ArrowRight, 'vertical' uses ArrowUp/ArrowDown, 'both' accepts all four arrows.",
129
129
  'options.hasHomeEnd': 'whether Home/End jump to first/last enabled item.',
130
- 'options.isRtl': 'when true, ArrowLeft/ArrowRight swap for horizontal nav (RTL).',
130
+ 'options.isRtl': 'ArrowLeft/ArrowRight swap for horizontal nav (RTL). default: auto-detect from container computed direction; explicit boolean wins.',
131
131
  'options.hasRovingTabIndex': 'opt into roving-tabindex ownership: hook stamps + repairs a single tab stop across items.',
132
132
  'options.hasCaretGuard': "when true, don't steal arrow keys from a nested text input/textarea mid-line or from a contenteditable.",
133
133
  },
@@ -3,7 +3,8 @@
3
3
  /**
4
4
  * @file useListFocus.test.tsx
5
5
  * @input Uses vitest, @testing-library/react, useListFocus hook
6
- * @output Unit tests for useListFocus disabled-item skipping + navigation
6
+ * @output Unit tests for useListFocus disabled-item skipping, navigation, and
7
+ * RTL auto-detection
7
8
  * @position Testing; validates useListFocus.ts keyboard navigation
8
9
  *
9
10
  * SYNC: When useListFocus.ts changes, update tests to match new behavior
@@ -373,3 +374,68 @@ describe('useListFocus shortcut passthrough', () => {
373
374
  expect(screen.getByTestId('A')).toHaveFocus();
374
375
  });
375
376
  });
377
+
378
+ /**
379
+ * A horizontal list (menubar-like) for RTL direction tests. jsdom reflects the
380
+ * `dir` attribute into computed style only on the element that carries it, so
381
+ * `dir` is set on the list container itself — the element the hook reads via
382
+ * listRef.
383
+ */
384
+ function HorizontalMenu({dir, isRtl}: {dir?: 'ltr' | 'rtl'; isRtl?: boolean}) {
385
+ const {listRef, handleKeyDown} = useListFocus<HTMLDivElement>({
386
+ orientation: 'horizontal',
387
+ isRtl,
388
+ });
389
+ const items = ['One', 'Two', 'Three'];
390
+ return (
391
+ <div ref={listRef} role="menu" dir={dir} onKeyDown={handleKeyDown}>
392
+ {items.map(label => (
393
+ <div key={label} role="menuitem" tabIndex={-1} data-testid={label}>
394
+ {label}
395
+ </div>
396
+ ))}
397
+ </div>
398
+ );
399
+ }
400
+
401
+ describe('useListFocus RTL auto-detection (WCAG 1.3.2)', () => {
402
+ it('auto-detects dir="rtl": ArrowLeft moves to the next item', () => {
403
+ render(<HorizontalMenu dir="rtl" />);
404
+ const menu = screen.getByRole('menu');
405
+ screen.getByTestId('One').focus();
406
+ fireEvent.keyDown(menu, {key: 'ArrowLeft'});
407
+ expect(screen.getByTestId('Two')).toHaveFocus();
408
+ });
409
+
410
+ it('auto-detects dir="rtl": ArrowRight moves to the previous item', () => {
411
+ render(<HorizontalMenu dir="rtl" />);
412
+ const menu = screen.getByRole('menu');
413
+ screen.getByTestId('Two').focus();
414
+ fireEvent.keyDown(menu, {key: 'ArrowRight'});
415
+ expect(screen.getByTestId('One')).toHaveFocus();
416
+ });
417
+
418
+ it('stays LTR without a direction: ArrowRight moves to the next item', () => {
419
+ render(<HorizontalMenu />);
420
+ const menu = screen.getByRole('menu');
421
+ screen.getByTestId('One').focus();
422
+ fireEvent.keyDown(menu, {key: 'ArrowRight'});
423
+ expect(screen.getByTestId('Two')).toHaveFocus();
424
+ });
425
+
426
+ it('explicit isRtl={false} overrides a dir="rtl" container', () => {
427
+ render(<HorizontalMenu dir="rtl" isRtl={false} />);
428
+ const menu = screen.getByRole('menu');
429
+ screen.getByTestId('One').focus();
430
+ fireEvent.keyDown(menu, {key: 'ArrowRight'});
431
+ expect(screen.getByTestId('Two')).toHaveFocus();
432
+ });
433
+
434
+ it('explicit isRtl={true} flips arrows without a dir attribute', () => {
435
+ render(<HorizontalMenu isRtl />);
436
+ const menu = screen.getByRole('menu');
437
+ screen.getByTestId('One').focus();
438
+ fireEvent.keyDown(menu, {key: 'ArrowLeft'});
439
+ expect(screen.getByTestId('Two')).toHaveFocus();
440
+ });
441
+ });