@astryxdesign/core 0.4.5 → 0.4.6-canary.cea9ecd

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 (538) hide show
  1. package/CHANGELOG.md +134 -0
  2. package/dist/Avatar/Avatar.d.ts +10 -5
  3. package/dist/Avatar/Avatar.d.ts.map +1 -1
  4. package/dist/Avatar/Avatar.js +139 -30
  5. package/dist/Avatar/AvatarStatusDot.d.ts +2 -1
  6. package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
  7. package/dist/Avatar/AvatarStatusDot.js +30 -4
  8. package/dist/Avatar/AvatarStatusLabelContext.d.ts +39 -0
  9. package/dist/Avatar/AvatarStatusLabelContext.d.ts.map +1 -0
  10. package/dist/Avatar/AvatarStatusLabelContext.js +41 -0
  11. package/dist/AvatarGroup/AvatarGroup.d.ts +3 -1
  12. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  13. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  14. package/dist/AvatarGroup/AvatarGroupOverflow.js +15 -9
  15. package/dist/Blockquote/Blockquote.d.ts +4 -3
  16. package/dist/Blockquote/Blockquote.d.ts.map +1 -1
  17. package/dist/Blockquote/Blockquote.js +9 -10
  18. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
  19. package/dist/BottomSheet/BottomSheetPanel.js +21 -5
  20. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  21. package/dist/Breadcrumbs/BreadcrumbItem.js +47 -34
  22. package/dist/Button/Button.d.ts.map +1 -1
  23. package/dist/Button/Button.js +7 -7
  24. package/dist/Calendar/Calendar.d.ts.map +1 -1
  25. package/dist/Calendar/Calendar.js +21 -12
  26. package/dist/Calendar/hooks/useCalendarNavigation.d.ts.map +1 -1
  27. package/dist/Calendar/hooks/useCalendarNavigation.js +8 -4
  28. package/dist/Calendar/styles.d.ts +2 -2
  29. package/dist/Calendar/styles.d.ts.map +1 -1
  30. package/dist/Calendar/styles.js +5 -5
  31. package/dist/Center/Center.d.ts +23 -1
  32. package/dist/Center/Center.d.ts.map +1 -1
  33. package/dist/Center/Center.js +12 -6
  34. package/dist/Chat/ChatComposer.d.ts.map +1 -1
  35. package/dist/Chat/ChatComposer.js +3 -3
  36. package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
  37. package/dist/Chat/ChatComposerDrawer.js +2 -2
  38. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  39. package/dist/Chat/ChatToolCalls.js +2 -2
  40. package/dist/Chat/useChatDictation.d.ts +1 -1
  41. package/dist/Chat/useChatDictation.d.ts.map +1 -1
  42. package/dist/Chat/useSpeechRecognition.d.ts +1 -1
  43. package/dist/Chat/useSpeechRecognition.d.ts.map +1 -1
  44. package/dist/Chat/useSpeechRecognition.js +4 -3
  45. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  46. package/dist/Chat/useTriggerMenu.js +2 -2
  47. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  48. package/dist/CheckboxInput/CheckboxInput.js +2 -2
  49. package/dist/Citation/Citation.d.ts.map +1 -1
  50. package/dist/Citation/Citation.js +5 -5
  51. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  52. package/dist/ClickableCard/ClickableCard.js +4 -4
  53. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  54. package/dist/CodeBlock/CodeBlock.js +1 -1
  55. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  56. package/dist/Collapsible/Collapsible.js +2 -2
  57. package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
  58. package/dist/CommandPalette/CommandPaletteItem.js +3 -3
  59. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  60. package/dist/ComplexSelector/ComplexSelector.js +6 -6
  61. package/dist/DateInput/DateInput.d.ts +31 -2
  62. package/dist/DateInput/DateInput.d.ts.map +1 -1
  63. package/dist/DateInput/DateInput.js +90 -22
  64. package/dist/DateInput/MonthScroller.d.ts +35 -0
  65. package/dist/DateInput/MonthScroller.d.ts.map +1 -0
  66. package/dist/DateInput/MonthScroller.js +658 -0
  67. package/dist/DateInput/MonthYearWheels.d.ts +24 -0
  68. package/dist/DateInput/MonthYearWheels.d.ts.map +1 -0
  69. package/dist/DateInput/MonthYearWheels.js +114 -0
  70. package/dist/DateInput/TouchDateField.d.ts +10 -0
  71. package/dist/DateInput/TouchDateField.d.ts.map +1 -0
  72. package/dist/DateInput/TouchDateField.js +810 -0
  73. package/dist/DateInput/Wheel.d.ts +41 -0
  74. package/dist/DateInput/Wheel.d.ts.map +1 -0
  75. package/dist/DateInput/Wheel.js +315 -0
  76. package/dist/DateInput/monthGeometry.d.ts +65 -0
  77. package/dist/DateInput/monthGeometry.d.ts.map +1 -0
  78. package/dist/DateInput/monthGeometry.js +98 -0
  79. package/dist/DateInput/tokens.stylex.d.ts +63 -0
  80. package/dist/DateInput/tokens.stylex.d.ts.map +1 -0
  81. package/dist/DateInput/tokens.stylex.js +74 -0
  82. package/dist/DateInput/useOwnScrollGesture.d.ts +41 -0
  83. package/dist/DateInput/useOwnScrollGesture.d.ts.map +1 -0
  84. package/dist/DateInput/useOwnScrollGesture.js +202 -0
  85. package/dist/DateInput/usePointerDragScroll.d.ts +15 -0
  86. package/dist/DateInput/usePointerDragScroll.d.ts.map +1 -0
  87. package/dist/DateInput/usePointerDragScroll.js +216 -0
  88. package/dist/DateInput/useScrollSettle.d.ts +26 -0
  89. package/dist/DateInput/useScrollSettle.d.ts.map +1 -0
  90. package/dist/DateInput/useScrollSettle.js +149 -0
  91. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  92. package/dist/DateRangeInput/DateRangeInput.js +17 -14
  93. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  94. package/dist/DateTimeInput/DateTimeInput.js +17 -14
  95. package/dist/Dialog/Dialog.d.ts.map +1 -1
  96. package/dist/Dialog/Dialog.js +3 -3
  97. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  98. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +2 -2
  99. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  100. package/dist/DropdownMenu/DropdownMenuItem.js +2 -2
  101. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
  102. package/dist/DropdownMenu/DropdownMenuRadioItem.js +2 -2
  103. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  104. package/dist/DropdownMenu/DropdownMenuSubMenu.js +2 -2
  105. package/dist/Field/FieldLabel.d.ts.map +1 -1
  106. package/dist/Field/FieldLabel.js +4 -4
  107. package/dist/Field/InputClearButton.d.ts.map +1 -1
  108. package/dist/Field/InputClearButton.js +6 -0
  109. package/dist/Field/inputStyles.stylex.d.ts +1 -1
  110. package/dist/Field/inputStyles.stylex.d.ts.map +1 -1
  111. package/dist/Field/inputStyles.stylex.js +5 -5
  112. package/dist/FileInput/FileInput.d.ts.map +1 -1
  113. package/dist/FileInput/FileInput.js +6 -6
  114. package/dist/HoverCard/HoverCard.d.ts +13 -3
  115. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  116. package/dist/HoverCard/HoverCard.js +2 -0
  117. package/dist/HoverCard/index.d.ts +1 -1
  118. package/dist/HoverCard/index.d.ts.map +1 -1
  119. package/dist/HoverCard/useHoverCard.d.ts +17 -2
  120. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  121. package/dist/HoverCard/useHoverCard.js +78 -9
  122. package/dist/InputGroup/InputGroup.js +1 -1
  123. package/dist/Item/Item.d.ts +9 -1
  124. package/dist/Item/Item.d.ts.map +1 -1
  125. package/dist/Item/Item.js +52 -14
  126. package/dist/Layer/index.d.ts +4 -2
  127. package/dist/Layer/index.d.ts.map +1 -1
  128. package/dist/Layer/index.js +2 -0
  129. package/dist/Layer/useLayer.d.ts.map +1 -1
  130. package/dist/Layer/useLayer.js +3 -2
  131. package/dist/Layer/useTouchTrigger.d.ts +113 -0
  132. package/dist/Layer/useTouchTrigger.d.ts.map +1 -0
  133. package/dist/Layer/useTouchTrigger.js +241 -0
  134. package/dist/Layout/container.stylex.d.ts +4 -2
  135. package/dist/Layout/container.stylex.d.ts.map +1 -1
  136. package/dist/Layout/container.stylex.js +19 -11
  137. package/dist/Layout/index.d.ts +1 -0
  138. package/dist/Layout/index.d.ts.map +1 -1
  139. package/dist/Layout/index.js +4 -0
  140. package/dist/Layout/padding.stylex.d.ts +315 -12
  141. package/dist/Layout/padding.stylex.d.ts.map +1 -1
  142. package/dist/Layout/padding.stylex.js +389 -12
  143. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  144. package/dist/Lightbox/Lightbox.js +5 -4
  145. package/dist/Link/Link.d.ts.map +1 -1
  146. package/dist/Link/Link.js +6 -6
  147. package/dist/MetadataList/MetadataList.d.ts.map +1 -1
  148. package/dist/MetadataList/MetadataList.js +1 -1
  149. package/dist/MobileNav/MobileNav.d.ts +1 -0
  150. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  151. package/dist/MobileNav/MobileNav.js +24 -6
  152. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  153. package/dist/MultiSelector/MultiSelector.js +8 -8
  154. package/dist/NavItem/navItemStyles.stylex.d.ts +4 -4
  155. package/dist/NavItem/navItemStyles.stylex.d.ts.map +1 -1
  156. package/dist/NavItem/navItemStyles.stylex.js +4 -4
  157. package/dist/NavMenu/NavHeadingMenuItem.d.ts.map +1 -1
  158. package/dist/NavMenu/NavHeadingMenuItem.js +3 -3
  159. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  160. package/dist/NumberInput/NumberInput.js +36 -8
  161. package/dist/Outline/Outline.d.ts.map +1 -1
  162. package/dist/Outline/Outline.js +3 -3
  163. package/dist/Pagination/Pagination.d.ts.map +1 -1
  164. package/dist/Pagination/Pagination.js +2 -2
  165. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  166. package/dist/PowerSearch/PowerSearch.js +11 -12
  167. package/dist/PowerSearch/PowerSearchToken.d.ts.map +1 -1
  168. package/dist/PowerSearch/PowerSearchToken.js +3 -1
  169. package/dist/PowerSearch/formatFilterValue.d.ts +11 -2
  170. package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
  171. package/dist/PowerSearch/formatFilterValue.js +23 -8
  172. package/dist/RadioList/RadioListItem.d.ts +2 -2
  173. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  174. package/dist/RadioList/RadioListItem.js +70 -40
  175. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  176. package/dist/Resizable/ResizeHandle.js +7 -7
  177. package/dist/Section/Section.d.ts +36 -1
  178. package/dist/Section/Section.d.ts.map +1 -1
  179. package/dist/Section/Section.js +12 -2
  180. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  181. package/dist/SegmentedControl/SegmentedControlItem.js +7 -2
  182. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  183. package/dist/SelectableCard/SelectableCard.js +3 -3
  184. package/dist/Selector/Selector.d.ts +26 -1
  185. package/dist/Selector/Selector.d.ts.map +1 -1
  186. package/dist/Selector/Selector.js +93 -20
  187. package/dist/Selector/SelectorOption.d.ts +14 -1
  188. package/dist/Selector/SelectorOption.d.ts.map +1 -1
  189. package/dist/Selector/SelectorOption.js +6 -0
  190. package/dist/Selector/SelectorRowLayoutContext.d.ts +8 -0
  191. package/dist/Selector/SelectorRowLayoutContext.d.ts.map +1 -0
  192. package/dist/Selector/SelectorRowLayoutContext.js +27 -0
  193. package/dist/Selector/types.d.ts +1 -0
  194. package/dist/Selector/types.d.ts.map +1 -1
  195. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  196. package/dist/SideNav/SideNavHeading.js +4 -4
  197. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  198. package/dist/SideNav/SideNavItem.js +3 -3
  199. package/dist/Slider/Slider.d.ts.map +1 -1
  200. package/dist/Slider/Slider.js +7 -7
  201. package/dist/Stack/Stack.d.ts +23 -1
  202. package/dist/Stack/Stack.d.ts.map +1 -1
  203. package/dist/Stack/Stack.js +12 -6
  204. package/dist/Switch/Switch.d.ts.map +1 -1
  205. package/dist/Switch/Switch.js +2 -2
  206. package/dist/TabList/Tab.d.ts.map +1 -1
  207. package/dist/TabList/Tab.js +1 -1
  208. package/dist/TabList/TabMenu.d.ts.map +1 -1
  209. package/dist/TabList/TabMenu.js +3 -3
  210. package/dist/Table/TableRow.js +4 -4
  211. package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
  212. package/dist/Table/plugins/columnResize/useTableColumnResize.js +1 -1
  213. package/dist/Table/plugins/filtering/useTableFiltering.d.ts.map +1 -1
  214. package/dist/Table/plugins/filtering/useTableFiltering.js +2 -2
  215. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  216. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +2 -2
  217. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  218. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +2 -2
  219. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  220. package/dist/Table/plugins/sortable/useTableSortable.js +1 -1
  221. package/dist/Table/plugins/sortable/useTableSortableState.d.ts +5 -3
  222. package/dist/Table/plugins/sortable/useTableSortableState.d.ts.map +1 -1
  223. package/dist/Table/plugins/sortable/useTableSortableState.js +12 -9
  224. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
  225. package/dist/Table/plugins/tree/useTableTreeData.js +3 -3
  226. package/dist/TextArea/TextArea.js +1 -1
  227. package/dist/TextInput/TextInput.js +1 -1
  228. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  229. package/dist/Thumbnail/Thumbnail.js +3 -3
  230. package/dist/TimeInput/TimeInput.js +2 -2
  231. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  232. package/dist/Timestamp/Timestamp.js +6 -4
  233. package/dist/Timestamp/formatInstant.d.ts +3 -2
  234. package/dist/Timestamp/formatInstant.d.ts.map +1 -1
  235. package/dist/Timestamp/formatInstant.js +8 -8
  236. package/dist/Timestamp/tooltipEntries.d.ts +2 -1
  237. package/dist/Timestamp/tooltipEntries.d.ts.map +1 -1
  238. package/dist/Timestamp/tooltipEntries.js +5 -3
  239. package/dist/Toast/Toast.d.ts +4 -3
  240. package/dist/Toast/Toast.d.ts.map +1 -1
  241. package/dist/Toast/Toast.js +10 -7
  242. package/dist/Token/Token.d.ts.map +1 -1
  243. package/dist/Token/Token.js +6 -6
  244. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  245. package/dist/Tokenizer/Tokenizer.js +1 -1
  246. package/dist/Tooltip/Tooltip.d.ts +16 -3
  247. package/dist/Tooltip/Tooltip.d.ts.map +1 -1
  248. package/dist/Tooltip/Tooltip.js +2 -0
  249. package/dist/Tooltip/index.d.ts +1 -1
  250. package/dist/Tooltip/index.d.ts.map +1 -1
  251. package/dist/Tooltip/useTooltip.d.ts +21 -2
  252. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  253. package/dist/Tooltip/useTooltip.js +71 -13
  254. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  255. package/dist/TopNav/TopNavHeading.js +4 -4
  256. package/dist/TopNav/TopNavItem.d.ts.map +1 -1
  257. package/dist/TopNav/TopNavItem.js +3 -3
  258. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  259. package/dist/TopNav/TopNavMegaMenu.js +2 -2
  260. package/dist/TopNav/TopNavMegaMenuItem.d.ts.map +1 -1
  261. package/dist/TopNav/TopNavMegaMenuItem.js +2 -2
  262. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  263. package/dist/TopNav/TopNavMenu.js +4 -4
  264. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  265. package/dist/TreeList/TreeListItem.js +7 -7
  266. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  267. package/dist/Typeahead/BaseTypeahead.js +2 -2
  268. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  269. package/dist/Typeahead/Typeahead.js +1 -1
  270. package/dist/astryx.css +124 -62
  271. package/dist/hooks/containerReveal.stylex.d.ts.map +1 -1
  272. package/dist/hooks/containerReveal.stylex.js +18 -18
  273. package/dist/hooks/scrollbarGutter.d.ts +28 -0
  274. package/dist/hooks/scrollbarGutter.d.ts.map +1 -0
  275. package/dist/hooks/scrollbarGutter.js +103 -0
  276. package/dist/hooks/useAutoMediaMode.d.ts +31 -0
  277. package/dist/hooks/useAutoMediaMode.d.ts.map +1 -0
  278. package/dist/hooks/useAutoMediaMode.js +201 -0
  279. package/dist/hooks/useInputStatusIcon.d.ts.map +1 -1
  280. package/dist/hooks/useInputStatusIcon.js +1 -1
  281. package/dist/hooks/useListFocus.d.ts +5 -2
  282. package/dist/hooks/useListFocus.d.ts.map +1 -1
  283. package/dist/hooks/useListFocus.js +12 -6
  284. package/dist/hooks/useScrollLock.d.ts +4 -0
  285. package/dist/hooks/useScrollLock.d.ts.map +1 -1
  286. package/dist/hooks/useScrollLock.js +13 -1
  287. package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
  288. package/dist/i18n/InternationalizationContext.js +2 -0
  289. package/dist/i18n/index.d.ts +6 -0
  290. package/dist/i18n/index.d.ts.map +1 -1
  291. package/dist/i18n/index.js +6 -0
  292. package/dist/i18n/useCollator.d.ts +12 -0
  293. package/dist/i18n/useCollator.d.ts.map +1 -0
  294. package/dist/i18n/useCollator.js +40 -0
  295. package/dist/i18n/useLocale.d.ts +3 -0
  296. package/dist/i18n/useLocale.d.ts.map +1 -0
  297. package/dist/i18n/useLocale.js +31 -0
  298. package/dist/theme/MediaTheme.d.ts +25 -5
  299. package/dist/theme/MediaTheme.d.ts.map +1 -1
  300. package/dist/theme/MediaTheme.js +31 -6
  301. package/dist/theme/defineTheme.d.ts +5 -0
  302. package/dist/theme/defineTheme.d.ts.map +1 -1
  303. package/dist/theme/defineTheme.js +5 -0
  304. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  305. package/dist/theme/derivedVarRegistry.js +7 -0
  306. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  307. package/dist/theme/generateThemeRules.js +66 -5
  308. package/dist/theme/index.d.ts +1 -1
  309. package/dist/theme/index.d.ts.map +1 -1
  310. package/dist/theme/syntax/index.d.ts +6 -0
  311. package/dist/theme/syntax/index.d.ts.map +1 -1
  312. package/dist/theme/syntax/index.js +7 -2
  313. package/dist/utils/dateParser.d.ts +4 -3
  314. package/dist/utils/dateParser.d.ts.map +1 -1
  315. package/dist/utils/dateParser.js +8 -8
  316. package/dist/utils/index.d.ts +1 -1
  317. package/dist/utils/index.d.ts.map +1 -1
  318. package/dist/utils/index.js +1 -1
  319. package/dist/utils/plainDate.d.ts +5 -2
  320. package/dist/utils/plainDate.d.ts.map +1 -1
  321. package/dist/utils/plainDate.js +20 -4
  322. package/locales/en.json +28 -0
  323. package/locales/pseudo.json +21 -0
  324. package/package.json +3 -3
  325. package/src/Avatar/Avatar.doc.mjs +10 -6
  326. package/src/Avatar/Avatar.test.tsx +219 -1
  327. package/src/Avatar/Avatar.tsx +179 -37
  328. package/src/Avatar/AvatarStatusDot.tsx +30 -4
  329. package/src/Avatar/AvatarStatusLabelContext.ts +47 -0
  330. package/src/AvatarGroup/AvatarGroup.doc.mjs +10 -6
  331. package/src/AvatarGroup/AvatarGroup.test.tsx +62 -0
  332. package/src/AvatarGroup/AvatarGroup.tsx +3 -1
  333. package/src/AvatarGroup/AvatarGroupOverflow.tsx +31 -8
  334. package/src/Banner/Banner.doc.mjs +2 -0
  335. package/src/Blockquote/Blockquote.doc.mjs +30 -7
  336. package/src/Blockquote/Blockquote.test.tsx +34 -3
  337. package/src/Blockquote/Blockquote.tsx +11 -9
  338. package/src/BottomSheet/BottomSheet.doc.mjs +3 -3
  339. package/src/BottomSheet/BottomSheet.test.tsx +24 -0
  340. package/src/BottomSheet/BottomSheetPanel.test.tsx +91 -0
  341. package/src/BottomSheet/BottomSheetPanel.tsx +58 -3
  342. package/src/Breadcrumbs/BreadcrumbItem.tsx +36 -23
  343. package/src/Breadcrumbs/Breadcrumbs.doc.mjs +26 -2
  344. package/src/Breadcrumbs/Breadcrumbs.test.tsx +31 -0
  345. package/src/Button/Button.tsx +12 -9
  346. package/src/Calendar/Calendar.tsx +15 -9
  347. package/src/Calendar/hooks/useCalendarNavigation.ts +6 -4
  348. package/src/Calendar/styles.ts +8 -5
  349. package/src/Center/Center.doc.mjs +48 -0
  350. package/src/Center/Center.test.tsx +158 -0
  351. package/src/Center/Center.tsx +50 -9
  352. package/src/Chat/ChatComposer.tsx +11 -5
  353. package/src/Chat/ChatComposerDrawer.tsx +4 -1
  354. package/src/Chat/ChatToolCalls.tsx +13 -4
  355. package/src/Chat/{useChatDictation.test.ts → useChatDictation.test.tsx} +29 -14
  356. package/src/Chat/useChatDictation.ts +1 -1
  357. package/src/Chat/useSpeechRecognition.ts +5 -3
  358. package/src/Chat/useTriggerMenu.tsx +4 -1
  359. package/src/CheckboxInput/CheckboxInput.tsx +5 -2
  360. package/src/Citation/Citation.test.tsx +6 -1
  361. package/src/Citation/Citation.tsx +11 -5
  362. package/src/ClickableCard/ClickableCard.tsx +7 -4
  363. package/src/CodeBlock/CodeBlock.tsx +4 -1
  364. package/src/Collapsible/Collapsible.tsx +5 -2
  365. package/src/CommandPalette/CommandPaletteItem.tsx +6 -3
  366. package/src/ComplexSelector/ComplexSelector.doc.mjs +10 -0
  367. package/src/ComplexSelector/ComplexSelector.tsx +14 -7
  368. package/src/DateInput/DateInput.test.tsx +17 -1
  369. package/src/DateInput/DateInput.tsx +93 -21
  370. package/src/DateInput/DateInputTouch.test.tsx +2582 -0
  371. package/src/DateInput/MonthScroller.tsx +878 -0
  372. package/src/DateInput/MonthYearWheels.tsx +147 -0
  373. package/src/DateInput/TouchDateField.tsx +1223 -0
  374. package/src/DateInput/Wheel.tsx +473 -0
  375. package/src/DateInput/monthGeometry.ts +118 -0
  376. package/src/DateInput/tokens.stylex.ts +99 -0
  377. package/src/DateInput/useOwnScrollGesture.ts +227 -0
  378. package/src/DateInput/usePointerDragScroll.ts +220 -0
  379. package/src/DateInput/useScrollSettle.ts +164 -0
  380. package/src/DateRangeInput/DateRangeInput.doc.mjs +1 -1
  381. package/src/DateRangeInput/DateRangeInput.tsx +31 -13
  382. package/src/DateTimeInput/DateTimeInput.tsx +25 -9
  383. package/src/Dialog/Dialog.test.tsx +24 -0
  384. package/src/Dialog/Dialog.tsx +3 -0
  385. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +5 -2
  386. package/src/DropdownMenu/DropdownMenuItem.tsx +5 -2
  387. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +5 -2
  388. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +5 -2
  389. package/src/Field/Field.doc.mjs +2 -0
  390. package/src/Field/FieldLabel.tsx +9 -3
  391. package/src/Field/InputClearButton.test.tsx +110 -3
  392. package/src/Field/InputClearButton.tsx +38 -0
  393. package/src/Field/inputStyles.stylex.ts +17 -13
  394. package/src/FileInput/FileInput.tsx +15 -8
  395. package/src/FormLayout/FormLayout.doc.mjs +1 -1
  396. package/src/HoverCard/HoverCard.doc.mjs +18 -0
  397. package/src/HoverCard/HoverCard.test.tsx +189 -0
  398. package/src/HoverCard/HoverCard.tsx +22 -2
  399. package/src/HoverCard/index.ts +1 -0
  400. package/src/HoverCard/useHoverCard.doc.mjs +2 -0
  401. package/src/HoverCard/useHoverCard.tsx +103 -7
  402. package/src/InputGroup/InputGroup.tsx +1 -1
  403. package/src/Item/Item.doc.mjs +1 -0
  404. package/src/Item/Item.test.tsx +50 -0
  405. package/src/Item/Item.tsx +54 -6
  406. package/src/Layer/index.ts +10 -0
  407. package/src/Layer/useLayer.tsx +13 -2
  408. package/src/Layer/useTouchTrigger.test.ts +70 -0
  409. package/src/Layer/useTouchTrigger.ts +366 -0
  410. package/src/Layout/Layout.doc.mjs +18 -0
  411. package/src/Layout/container.stylex.ts +11 -3
  412. package/src/Layout/index.ts +4 -0
  413. package/src/Layout/overlayPaddingReset.test.tsx +222 -0
  414. package/src/Layout/padding.stylex.ts +192 -12
  415. package/src/Lightbox/Lightbox.tsx +11 -3
  416. package/src/Link/Link.tsx +9 -6
  417. package/src/MetadataList/MetadataList.tsx +4 -1
  418. package/src/MobileNav/MobileNav.tsx +61 -5
  419. package/src/MobileNav/MobileNavEntryAnimation.test.tsx +212 -0
  420. package/src/MobileNav/MobileNavScrollbarGutter.test.tsx +109 -0
  421. package/src/MultiSelector/MultiSelector.test.tsx +1 -1
  422. package/src/MultiSelector/MultiSelector.tsx +26 -10
  423. package/src/NavItem/navItemStyles.stylex.ts +7 -4
  424. package/src/NavMenu/NavHeadingMenuItem.tsx +6 -3
  425. package/src/NumberInput/NumberInput.doc.mjs +24 -0
  426. package/src/NumberInput/NumberInput.test.tsx +138 -0
  427. package/src/NumberInput/NumberInput.tsx +47 -8
  428. package/src/Outline/Outline.tsx +5 -2
  429. package/src/Pagination/Pagination.tsx +5 -2
  430. package/src/Popover/Popover.test.tsx +27 -1
  431. package/src/PowerSearch/PowerSearch.tsx +17 -8
  432. package/src/PowerSearch/PowerSearchToken.tsx +3 -0
  433. package/src/PowerSearch/formatFilterValue.test.ts +22 -2
  434. package/src/PowerSearch/formatFilterValue.ts +31 -6
  435. package/src/RadioList/RadioList.doc.mjs +1 -1
  436. package/src/RadioList/RadioList.test.tsx +170 -2
  437. package/src/RadioList/RadioListItem.tsx +88 -53
  438. package/src/Resizable/ResizeHandle.test.tsx +22 -0
  439. package/src/Resizable/ResizeHandle.tsx +25 -7
  440. package/src/Section/Section.doc.mjs +55 -0
  441. package/src/Section/Section.test.tsx +201 -4
  442. package/src/Section/Section.tsx +69 -0
  443. package/src/SegmentedControl/SegmentedControl.test.tsx +31 -0
  444. package/src/SegmentedControl/SegmentedControlItem.tsx +15 -3
  445. package/src/SelectableCard/SelectableCard.tsx +6 -3
  446. package/src/Selector/Selector.doc.mjs +16 -2
  447. package/src/Selector/Selector.test.tsx +525 -1
  448. package/src/Selector/Selector.tsx +180 -25
  449. package/src/Selector/SelectorOption.doc.mjs +7 -0
  450. package/src/Selector/SelectorOption.tsx +21 -0
  451. package/src/Selector/SelectorRowLayoutContext.ts +32 -0
  452. package/src/Selector/types.ts +4 -4
  453. package/src/SideNav/SideNavHeading.tsx +14 -5
  454. package/src/SideNav/SideNavItem.tsx +9 -3
  455. package/src/Slider/Slider.tsx +25 -6
  456. package/src/Stack/Stack.doc.mjs +72 -0
  457. package/src/Stack/Stack.test.tsx +156 -0
  458. package/src/Stack/Stack.tsx +50 -8
  459. package/src/Switch/Switch.tsx +5 -2
  460. package/src/TabList/Tab.tsx +4 -1
  461. package/src/TabList/TabMenu.tsx +9 -3
  462. package/src/Table/TableRow.tsx +4 -4
  463. package/src/Table/plugins/columnResize/useTableColumnResize.tsx +6 -2
  464. package/src/Table/plugins/filtering/useTableFiltering.tsx +4 -1
  465. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +10 -3
  466. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +6 -3
  467. package/src/Table/plugins/sortable/useTableSortable.tsx +4 -1
  468. package/src/Table/plugins/sortable/useTableSortableState.test.tsx +34 -0
  469. package/src/Table/plugins/sortable/useTableSortableState.tsx +26 -23
  470. package/src/Table/plugins/tree/useTableTreeData.tsx +10 -4
  471. package/src/TextArea/TextArea.doc.mjs +1 -1
  472. package/src/TextArea/TextArea.tsx +1 -1
  473. package/src/TextInput/TextInput.tsx +1 -1
  474. package/src/Thumbnail/Thumbnail.tsx +9 -3
  475. package/src/TimeInput/TimeInput.tsx +1 -1
  476. package/src/Timestamp/Timestamp.test.tsx +27 -7
  477. package/src/Timestamp/Timestamp.tsx +8 -4
  478. package/src/Timestamp/formatInstant.ts +9 -7
  479. package/src/Timestamp/tooltipEntries.test.ts +11 -6
  480. package/src/Timestamp/tooltipEntries.ts +6 -2
  481. package/src/Toast/Toast.tsx +9 -7
  482. package/src/Token/Token.tsx +14 -5
  483. package/src/Tokenizer/Tokenizer.tsx +4 -1
  484. package/src/Tooltip/Tooltip.doc.mjs +18 -0
  485. package/src/Tooltip/Tooltip.test.tsx +254 -1
  486. package/src/Tooltip/Tooltip.tsx +22 -2
  487. package/src/Tooltip/index.ts +1 -0
  488. package/src/Tooltip/useTooltip.doc.mjs +2 -0
  489. package/src/Tooltip/useTooltip.tsx +99 -21
  490. package/src/TopNav/TopNavHeading.tsx +13 -4
  491. package/src/TopNav/TopNavItem.tsx +6 -3
  492. package/src/TopNav/TopNavMegaMenu.tsx +5 -2
  493. package/src/TopNav/TopNavMegaMenuItem.tsx +5 -2
  494. package/src/TopNav/TopNavMenu.tsx +10 -4
  495. package/src/TreeList/TreeListItem.tsx +22 -7
  496. package/src/Typeahead/BaseTypeahead.tsx +5 -2
  497. package/src/Typeahead/Typeahead.tsx +4 -1
  498. package/src/hooks/containerReveal.stylex.ts +54 -18
  499. package/src/hooks/scrollbarGutter.test.ts +167 -0
  500. package/src/hooks/scrollbarGutter.ts +121 -0
  501. package/src/hooks/useAutoMediaMode.test.ts +109 -0
  502. package/src/hooks/useAutoMediaMode.ts +233 -0
  503. package/src/hooks/useInputStatusIcon.tsx +4 -1
  504. package/src/hooks/useListFocus.doc.mjs +2 -2
  505. package/src/hooks/useListFocus.test.tsx +65 -3
  506. package/src/hooks/useListFocus.ts +15 -7
  507. package/src/hooks/useScrollLock.doc.mjs +4 -4
  508. package/src/hooks/useScrollLock.test.ts +73 -0
  509. package/src/hooks/useScrollLock.ts +14 -0
  510. package/src/i18n/InternationalizationContext.ts +2 -0
  511. package/src/i18n/__tests__/e2e-powersearch.test.tsx +37 -1
  512. package/src/i18n/__tests__/useCollator.test.tsx +115 -0
  513. package/src/i18n/__tests__/useLocale.test.tsx +52 -0
  514. package/src/i18n/index.ts +6 -0
  515. package/src/i18n/useCollator.doc.mjs +84 -0
  516. package/src/i18n/useCollator.ts +44 -0
  517. package/src/i18n/useLocale.doc.mjs +70 -0
  518. package/src/i18n/useLocale.ts +34 -0
  519. package/src/i18n/useTranslator.doc.mjs +1 -1
  520. package/src/reset.css +9 -2
  521. package/src/reset.test.ts +22 -0
  522. package/src/theme/MediaTheme.doc.mjs +23 -4
  523. package/src/theme/MediaTheme.dom.test.tsx +97 -0
  524. package/src/theme/MediaTheme.tsx +42 -7
  525. package/src/theme/defineTheme.test.ts +9 -3
  526. package/src/theme/defineTheme.ts +5 -0
  527. package/src/theme/derivedVarRegistry.test.ts +19 -5
  528. package/src/theme/derivedVarRegistry.ts +4 -0
  529. package/src/theme/generateThemeRules.test.ts +118 -0
  530. package/src/theme/generateThemeRules.ts +83 -5
  531. package/src/theme/index.ts +1 -1
  532. package/src/theme/syntax/index.ts +6 -2
  533. package/src/theme/syntax/serverSafeSyntax.test.ts +68 -0
  534. package/src/utils/dateParser.test.ts +20 -0
  535. package/src/utils/dateParser.ts +14 -7
  536. package/src/utils/index.ts +2 -0
  537. package/src/utils/plainDate.test.ts +6 -0
  538. package/src/utils/plainDate.ts +21 -4
@@ -17,6 +17,9 @@ describe('useScrollLock', () => {
17
17
  afterEach(() => {
18
18
  cleanup();
19
19
  document.body.style.cssText = '';
20
+ document.documentElement.style.cssText = '';
21
+ // @ts-expect-error -- drop the viewport stub so jsdom's own value comes back
22
+ delete document.documentElement.clientWidth;
20
23
  vi.restoreAllMocks();
21
24
  });
22
25
 
@@ -69,4 +72,74 @@ describe('useScrollLock', () => {
69
72
  expect(document.body.style.left).toBe('');
70
73
  expect(document.body.style.right).toBe('');
71
74
  });
75
+
76
+ it('holds the page still across the scrollbar it hides', () => {
77
+ // A 1024px window over a 1009px layout viewport = a 15px classic
78
+ // scrollbar. Pinning the body hides it, which would widen the page by
79
+ // those 15px and reflow everything sideways.
80
+ Object.defineProperty(window, 'innerWidth', {
81
+ value: 1024,
82
+ configurable: true,
83
+ writable: true,
84
+ });
85
+ Object.defineProperty(document.documentElement, 'clientWidth', {
86
+ value: 1009,
87
+ configurable: true,
88
+ });
89
+ vi.spyOn(window, 'scrollTo').mockImplementation(() => {});
90
+
91
+ const lock = renderHook(() => useScrollLock(true));
92
+
93
+ expect(document.documentElement.style.scrollbarGutter).toBe('stable');
94
+
95
+ lock.unmount();
96
+
97
+ expect(document.documentElement.style.scrollbarGutter).toBe('');
98
+ });
99
+
100
+ it('leaves the page alone when the scrollbar is an overlay one', () => {
101
+ Object.defineProperty(window, 'innerWidth', {
102
+ value: 1024,
103
+ configurable: true,
104
+ writable: true,
105
+ });
106
+ Object.defineProperty(document.documentElement, 'clientWidth', {
107
+ value: 1024,
108
+ configurable: true,
109
+ });
110
+ vi.spyOn(window, 'scrollTo').mockImplementation(() => {});
111
+
112
+ const lock = renderHook(() => useScrollLock(true));
113
+
114
+ expect(document.documentElement.style.scrollbarGutter).toBe('');
115
+ expect(document.body.style.paddingRight).toBe('');
116
+
117
+ lock.unmount();
118
+ });
119
+
120
+ it('holds the gutter for the outermost overlay only, and gives it back once', () => {
121
+ Object.defineProperty(window, 'innerWidth', {
122
+ value: 1024,
123
+ configurable: true,
124
+ writable: true,
125
+ });
126
+ Object.defineProperty(document.documentElement, 'clientWidth', {
127
+ value: 1009,
128
+ configurable: true,
129
+ });
130
+ vi.spyOn(window, 'scrollTo').mockImplementation(() => {});
131
+
132
+ const first = renderHook(() => useScrollLock(true));
133
+ const second = renderHook(() => useScrollLock(true));
134
+
135
+ expect(document.documentElement.style.scrollbarGutter).toBe('stable');
136
+
137
+ first.unmount();
138
+
139
+ expect(document.documentElement.style.scrollbarGutter).toBe('stable');
140
+
141
+ second.unmount();
142
+
143
+ expect(document.documentElement.style.scrollbarGutter).toBe('');
144
+ });
72
145
  });
@@ -13,9 +13,11 @@
13
13
  *
14
14
  * SYNC: When modified, update:
15
15
  * - /packages/core/src/hooks/index.ts
16
+ * - /packages/core/src/hooks/scrollbarGutter.ts
16
17
  */
17
18
 
18
19
  import {useEffect} from 'react';
20
+ import {holdScrollbarGutter, type ScrollbarGutterHold} from './scrollbarGutter';
19
21
 
20
22
  interface ScrollLockSnapshot {
21
23
  scrollX: number;
@@ -25,6 +27,7 @@ interface ScrollLockSnapshot {
25
27
  top: string;
26
28
  left: string;
27
29
  right: string;
30
+ gutter: ScrollbarGutterHold;
28
31
  }
29
32
 
30
33
  let lockCount = 0;
@@ -38,6 +41,10 @@ let originalBodyState: ScrollLockSnapshot | null = null;
38
41
  * does not prevent body scroll behind modals. Restores scroll position
39
42
  * on unlock.
40
43
  *
44
+ * Pinning also hides the document's scrollbar, so the gutter that scrollbar
45
+ * occupied is held open for the duration of the lock — without it the page
46
+ * reflows sideways by ~15px the moment an overlay opens.
47
+ *
41
48
  * @example
42
49
  * ```
43
50
  * useScrollLock(isOpen);
@@ -55,6 +62,9 @@ export function useScrollLock(isLocked: boolean): void {
55
62
  const scrollX = window.scrollX;
56
63
  const scrollY = window.scrollY;
57
64
 
65
+ // Taken before the pinning styles below hide the scrollbar.
66
+ const gutter = holdScrollbarGutter(body);
67
+
58
68
  originalBodyState = {
59
69
  scrollX,
60
70
  scrollY,
@@ -63,6 +73,7 @@ export function useScrollLock(isLocked: boolean): void {
63
73
  top: body.style.top,
64
74
  left: body.style.left,
65
75
  right: body.style.right,
76
+ gutter,
66
77
  };
67
78
 
68
79
  body.style.overflow = 'hidden';
@@ -70,6 +81,8 @@ export function useScrollLock(isLocked: boolean): void {
70
81
  body.style.top = `-${scrollY}px`;
71
82
  body.style.left = '0';
72
83
  body.style.right = '0';
84
+
85
+ gutter.settle();
73
86
  }
74
87
 
75
88
  lockCount += 1;
@@ -89,6 +102,7 @@ export function useScrollLock(isLocked: boolean): void {
89
102
  body.style.top = state.top;
90
103
  body.style.left = state.left;
91
104
  body.style.right = state.right;
105
+ state.gutter.release();
92
106
  window.scrollTo(state.scrollX, state.scrollY);
93
107
  };
94
108
  }, [isLocked]);
@@ -16,6 +16,8 @@
16
16
  * - /packages/core/src/i18n/InternationalizationProvider.tsx
17
17
  * - /packages/core/src/i18n/t.client.ts
18
18
  * - /packages/core/src/i18n/useDirection.ts
19
+ * - /packages/core/src/i18n/useLocale.ts
20
+ * - /packages/core/src/i18n/useCollator.ts
19
21
  * - /packages/core/src/i18n/getLocaleDirection.ts
20
22
  * - /packages/core/src/i18n/index.ts
21
23
  */
@@ -23,7 +23,11 @@ import {describe, test, expect} from 'vitest';
23
23
  import {render, screen} from '@testing-library/react';
24
24
  import React, {useMemo} from 'react';
25
25
  import {PowerSearch, usePowerSearchConfig} from '../../PowerSearch';
26
- import type {FieldDefinition, PowerSearchFilter} from '../../PowerSearch';
26
+ import type {
27
+ FieldDefinition,
28
+ PowerSearchConfig,
29
+ PowerSearchFilter,
30
+ } from '../../PowerSearch';
27
31
  import {InternationalizationProvider} from '../InternationalizationProvider';
28
32
  import pseudoCatalog from '../../../locales/pseudo.json';
29
33
 
@@ -112,6 +116,38 @@ describe('PowerSearch × i18n — end to end', () => {
112
116
  expect(screen.getByText(/Name: contient/)).toBeInTheDocument();
113
117
  });
114
118
 
119
+ test('date tokens update when the provider locale changes', () => {
120
+ const config: PowerSearchConfig = {
121
+ name: 'Dates',
122
+ fields: [
123
+ {
124
+ key: 'created',
125
+ label: 'Created',
126
+ defaultOperator: 'is',
127
+ operators: [{key: 'is', label: 'is', value: {type: 'date_absolute'}}],
128
+ },
129
+ ],
130
+ };
131
+ const filters: PowerSearchFilter[] = [
132
+ {
133
+ field: 'created',
134
+ operator: 'is',
135
+ value: {type: 'date_absolute', unixSeconds: 1769342400},
136
+ },
137
+ ];
138
+ const search = (locale: string) => (
139
+ <InternationalizationProvider locale={locale}>
140
+ <PowerSearch config={config} filters={filters} onChange={() => {}} />
141
+ </InternationalizationProvider>
142
+ );
143
+
144
+ const {rerender} = render(search('en-US'));
145
+ expect(screen.getByText('Jan 25, 2026')).toBeInTheDocument();
146
+
147
+ rerender(search('de-DE'));
148
+ expect(screen.getByText('25. Jan. 2026')).toBeInTheDocument();
149
+ });
150
+
115
151
  test('resultCount ICU plural swaps under provider overrides', () => {
116
152
  render(
117
153
  <InternationalizationProvider
@@ -0,0 +1,115 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file useCollator.test.tsx
5
+ * @input packages/core/src/i18n/useCollator.ts, InternationalizationProvider
6
+ * @output Unit tests for the internal provider-aware Intl.Collator hook
7
+ * @position Colocated tests; targets the default (no-provider) fallback,
8
+ * locale-driven comparison order, option threading, and memoization.
9
+ */
10
+
11
+ import type {ReactNode} from 'react';
12
+ import {describe, expect, test} from 'vitest';
13
+ import {render, renderHook} from '@testing-library/react';
14
+ import {useCollator} from '../useCollator';
15
+ import {InternationalizationProvider} from '../InternationalizationProvider';
16
+
17
+ function wrapperFor(locale: string) {
18
+ return ({children}: {children: ReactNode}) => (
19
+ <InternationalizationProvider locale={locale}>
20
+ {children}
21
+ </InternationalizationProvider>
22
+ );
23
+ }
24
+
25
+ describe('useCollator', () => {
26
+ test('compares using the en fallback when rendered without a provider', () => {
27
+ const {result} = renderHook(() => useCollator());
28
+ expect(result.current.compare('a', 'b')).toBeLessThan(0);
29
+ });
30
+
31
+ test('orders "ä" before "z" under Swedish, and after "z" under German', () => {
32
+ const {result: sv} = renderHook(() => useCollator(), {
33
+ wrapper: wrapperFor('sv-SE'),
34
+ });
35
+ expect(['z', 'ä'].sort((a, b) => sv.current.compare(a, b))).toEqual([
36
+ 'z',
37
+ 'ä',
38
+ ]);
39
+
40
+ const {result: de} = renderHook(() => useCollator(), {
41
+ wrapper: wrapperFor('de-DE'),
42
+ });
43
+ expect(['z', 'ä'].sort((a, b) => de.current.compare(a, b))).toEqual([
44
+ 'ä',
45
+ 'z',
46
+ ]);
47
+ });
48
+
49
+ test('threads options through to the underlying Intl.Collator (numeric)', () => {
50
+ const {result} = renderHook(() => useCollator({numeric: true}));
51
+ expect(
52
+ ['item2', 'item10'].sort((a, b) => result.current.compare(a, b)),
53
+ ).toEqual(['item2', 'item10']);
54
+ });
55
+
56
+ test('without numeric, orders "item10" before "item2" lexicographically', () => {
57
+ const {result} = renderHook(() => useCollator());
58
+ expect(
59
+ ['item2', 'item10'].sort((a, b) => result.current.compare(a, b)),
60
+ ).toEqual(['item10', 'item2']);
61
+ });
62
+
63
+ test('memoizes the collator when locale and options identity are unchanged', () => {
64
+ const options = {numeric: true} satisfies Intl.CollatorOptions;
65
+ const {result, rerender} = renderHook(
66
+ ({collatorOptions}) => useCollator(collatorOptions),
67
+ {
68
+ initialProps: {collatorOptions: options},
69
+ wrapper: wrapperFor('en'),
70
+ },
71
+ );
72
+ const first = result.current;
73
+ rerender({collatorOptions: options});
74
+ expect(result.current).toBe(first);
75
+ });
76
+
77
+ test('rebuilds the collator when options identity changes', () => {
78
+ const {result, rerender} = renderHook(
79
+ ({collatorOptions}) => useCollator(collatorOptions),
80
+ {
81
+ initialProps: {
82
+ collatorOptions: {numeric: true} satisfies Intl.CollatorOptions,
83
+ },
84
+ wrapper: wrapperFor('en'),
85
+ },
86
+ );
87
+ const first = result.current;
88
+ rerender({collatorOptions: {numeric: true}});
89
+ expect(result.current).not.toBe(first);
90
+ });
91
+
92
+ test('re-renders with a new collator when the provider locale changes', () => {
93
+ let latestCollator: Intl.Collator | undefined;
94
+ function Probe() {
95
+ latestCollator = useCollator();
96
+ const order = ['z', 'ä'].sort((a, b) => latestCollator!.compare(a, b));
97
+ return <span data-testid="order">{order.join(',')}</span>;
98
+ }
99
+ const {getByTestId, rerender} = render(
100
+ <InternationalizationProvider locale="sv-SE">
101
+ <Probe />
102
+ </InternationalizationProvider>,
103
+ );
104
+ expect(getByTestId('order').textContent).toBe('z,ä');
105
+ const svCollator = latestCollator;
106
+
107
+ rerender(
108
+ <InternationalizationProvider locale="de-DE">
109
+ <Probe />
110
+ </InternationalizationProvider>,
111
+ );
112
+ expect(getByTestId('order').textContent).toBe('ä,z');
113
+ expect(latestCollator).not.toBe(svCollator);
114
+ });
115
+ });
@@ -0,0 +1,52 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file useLocale.test.tsx
5
+ * @input packages/core/src/i18n/useLocale.ts, InternationalizationProvider
6
+ * @output Unit tests for the internal provider-aware locale accessor
7
+ * @position Colocated tests; targets the default (no-provider) fallback, the
8
+ * provider locale, and re-rendering when the provider locale changes.
9
+ */
10
+
11
+ import type {ReactNode} from 'react';
12
+ import {describe, expect, test} from 'vitest';
13
+ import {render, renderHook} from '@testing-library/react';
14
+ import {useLocale} from '../useLocale';
15
+ import {InternationalizationProvider} from '../InternationalizationProvider';
16
+
17
+ describe('useLocale', () => {
18
+ test('returns en when rendered without a provider', () => {
19
+ const {result} = renderHook(() => useLocale());
20
+ expect(result.current).toBe('en');
21
+ });
22
+
23
+ test('returns the provider locale', () => {
24
+ const {result} = renderHook(() => useLocale(), {
25
+ wrapper: ({children}: {children: ReactNode}) => (
26
+ <InternationalizationProvider locale="fr">
27
+ {children}
28
+ </InternationalizationProvider>
29
+ ),
30
+ });
31
+ expect(result.current).toBe('fr');
32
+ });
33
+
34
+ test('re-renders with the new locale when the provider locale changes', () => {
35
+ function Probe() {
36
+ return <span data-testid="locale">{useLocale()}</span>;
37
+ }
38
+ const {getByTestId, rerender} = render(
39
+ <InternationalizationProvider locale="en">
40
+ <Probe />
41
+ </InternationalizationProvider>,
42
+ );
43
+ expect(getByTestId('locale').textContent).toBe('en');
44
+
45
+ rerender(
46
+ <InternationalizationProvider locale="ja-JP">
47
+ <Probe />
48
+ </InternationalizationProvider>,
49
+ );
50
+ expect(getByTestId('locale').textContent).toBe('ja-JP');
51
+ });
52
+ });
package/src/i18n/index.ts CHANGED
@@ -10,12 +10,16 @@
10
10
  * The public API is deliberately small:
11
11
  * - InternationalizationProvider — provider component
12
12
  * - useTranslator — hook returning a translator function
13
+ * - useLocale — hook returning the provider locale
14
+ * - useCollator — provider-bound locale-aware comparison
13
15
  * - useDirection — hook returning the ambient text direction
14
16
  * - getLocaleDirection — server-safe locale → direction helper
15
17
  * - Translator — interface for consumer-injected runtimes
16
18
  *
17
19
  * SYNC: When modified, update these files to stay in sync:
18
20
  * - /packages/core/src/index.ts
21
+ * - /packages/core/src/i18n/useLocale.ts
22
+ * - /packages/core/src/i18n/useCollator.ts
19
23
  * - /packages/core/src/i18n/useDirection.ts
20
24
  * - /packages/core/src/i18n/getLocaleDirection.ts
21
25
  */
@@ -26,6 +30,8 @@ export {InternationalizationContext} from './InternationalizationContext';
26
30
  export type {InternationalizationContextValue} from './InternationalizationContext';
27
31
  export {useTranslator} from './useTranslator';
28
32
  export type {TranslatorFn} from './useTranslator';
33
+ export {useLocale} from './useLocale';
34
+ export {useCollator} from './useCollator';
29
35
  export {useDirection} from './useDirection';
30
36
  export {getLocaleDirection} from './getLocaleDirection';
31
37
  export type {Translator} from './translator';
@@ -0,0 +1,84 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /** @type {import('@astryxdesign/cli/authoring').HookDoc} */
4
+ export const docs = {
5
+ name: 'useCollator',
6
+ displayName: 'useCollator',
7
+ category: 'utilities',
8
+ keywords: [
9
+ 'i18n',
10
+ 'internationalization',
11
+ 'locale',
12
+ 'collation',
13
+ 'compare',
14
+ 'sort',
15
+ 'table',
16
+ 'hook',
17
+ ],
18
+ params: [
19
+ {
20
+ name: 'options',
21
+ type: 'Intl.CollatorOptions',
22
+ description:
23
+ 'Optional collation behavior such as numeric ordering, sensitivity, punctuation handling, and case order.',
24
+ required: false,
25
+ },
26
+ ],
27
+ returns: [
28
+ {
29
+ name: 'collator',
30
+ type: 'Intl.Collator',
31
+ description:
32
+ 'A memoized collator bound to the active InternationalizationProvider locale.',
33
+ },
34
+ ],
35
+ usage: {
36
+ description:
37
+ 'Returns the sanctioned locale-aware comparator for custom sorting. The collator is recreated when the provider locale or an option changes.',
38
+ bestPractices: [
39
+ {
40
+ guidance: true,
41
+ description:
42
+ 'Reuse collator.compare in custom Table comparators and other user-visible string ordering.',
43
+ },
44
+ {
45
+ guidance: false,
46
+ description:
47
+ 'Construct Intl.Collator directly or call localeCompare; those bypass the provider-backed locale contract.',
48
+ },
49
+ ],
50
+ },
51
+ relatedComponents: ['InternationalizationProvider', 'Table'],
52
+ relatedHooks: ['useLocale'],
53
+ importPath: '@astryxdesign/core',
54
+ };
55
+
56
+ /** @type {import('@astryxdesign/cli/authoring').HookTranslationDoc} */
57
+ export const docsDense = {
58
+ description:
59
+ 'Returns a memoized Intl.Collator bound to the active InternationalizationProvider locale.',
60
+ paramDescriptions: {
61
+ options:
62
+ 'optional Intl.CollatorOptions: numeric ordering, sensitivity, punctuation, case order, etc.',
63
+ },
64
+ returnDescriptions: {
65
+ collator:
66
+ 'memoized provider-bound collator for locale-aware comparison and sorting.',
67
+ },
68
+ usage: {
69
+ description:
70
+ 'Use collator.compare for custom user-visible string ordering instead of raw Intl.Collator or localeCompare.',
71
+ bestPractices: [
72
+ {
73
+ guidance: true,
74
+ description:
75
+ 'Reuse collator.compare in custom Table comparators and string sorting.',
76
+ },
77
+ {
78
+ guidance: false,
79
+ description:
80
+ 'Construct raw Intl.Collator or call localeCompare directly.',
81
+ },
82
+ ],
83
+ },
84
+ };
@@ -0,0 +1,44 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file useCollator.ts
7
+ * @input InternationalizationContext (via use()), optional Intl.CollatorOptions
8
+ * @output A memoized Intl.Collator bound to the active locale
9
+ * @position Public provider-aware string-comparison hook. Exported from the
10
+ * i18n barrel for components, sibling packages, and consumers that need
11
+ * locale-correct sorting without constructing a raw Intl.Collator. Raw
12
+ * collator construction stays centralized in this hook.
13
+ *
14
+ * Falls back to `'en'` when called outside a provider, matching the
15
+ * useTranslator/useDirection/useLocale fallback.
16
+ *
17
+ * SYNC: When modified, update:
18
+ * - /packages/core/src/i18n/InternationalizationContext.ts
19
+ * - /packages/core/src/i18n/useLocale.ts
20
+ * - /packages/core/src/i18n/useCollator.doc.mjs
21
+ * - /packages/core/src/i18n/index.ts
22
+ * - /packages/core/src/i18n/__tests__/useCollator.test.tsx
23
+ */
24
+
25
+ import {use, useMemo} from 'react';
26
+ import {InternationalizationContext} from './InternationalizationContext';
27
+
28
+ /**
29
+ * Returns an `Intl.Collator` for the active provider locale, memoized across
30
+ * renders where the locale and options object are unchanged.
31
+ *
32
+ * @example
33
+ * ```
34
+ * const collator = useCollator({numeric: true});
35
+ * const sorted = [...items].sort((a, b) => collator.compare(a.name, b.name));
36
+ * ```
37
+ */
38
+ export function useCollator(options?: Intl.CollatorOptions): Intl.Collator {
39
+ const ctx = use(InternationalizationContext);
40
+ return useMemo(
41
+ () => new Intl.Collator(ctx.locale, options),
42
+ [ctx.locale, options],
43
+ );
44
+ }
@@ -0,0 +1,70 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /** @type {import('@astryxdesign/cli/authoring').HookDoc} */
4
+ export const docs = {
5
+ name: 'useLocale',
6
+ displayName: 'useLocale',
7
+ category: 'utilities',
8
+ keywords: [
9
+ 'i18n',
10
+ 'internationalization',
11
+ 'localization',
12
+ 'locale',
13
+ 'language',
14
+ 'provider',
15
+ 'hook',
16
+ ],
17
+ params: [],
18
+ returns: [
19
+ {
20
+ name: 'locale',
21
+ type: 'Locale',
22
+ description:
23
+ "The active InternationalizationProvider BCP 47 locale. Falls back to 'en' when no provider is present.",
24
+ },
25
+ ],
26
+ usage: {
27
+ description:
28
+ 'Reads the authoritative Astryx locale. Use it to thread the provider locale into pure formatting helpers and sibling-package APIs; do not derive a second locale from navigator.language or a hardcoded literal.',
29
+ bestPractices: [
30
+ {
31
+ guidance: true,
32
+ description:
33
+ 'Pass the returned locale to pure Astryx helpers or package APIs that require an explicit locale.',
34
+ },
35
+ {
36
+ guidance: false,
37
+ description:
38
+ 'Use navigator.language or a hardcoded display locale as a fallback; InternationalizationProvider is the locale source.',
39
+ },
40
+ ],
41
+ },
42
+ relatedComponents: ['InternationalizationProvider'],
43
+ relatedHooks: ['useCollator', 'useTranslator', 'useDirection'],
44
+ importPath: '@astryxdesign/core',
45
+ };
46
+
47
+ /** @type {import('@astryxdesign/cli/authoring').HookTranslationDoc} */
48
+ export const docsDense = {
49
+ description:
50
+ "Returns the active InternationalizationProvider locale, falling back to 'en' without a provider.",
51
+ usage: {
52
+ description:
53
+ 'Use as the sole locale source for pure formatting helpers and sibling-package APIs.',
54
+ bestPractices: [
55
+ {
56
+ guidance: true,
57
+ description:
58
+ 'Thread this locale into pure helpers requiring an explicit locale.',
59
+ },
60
+ {
61
+ guidance: false,
62
+ description:
63
+ 'Fall back to navigator.language or a hardcoded display locale.',
64
+ },
65
+ ],
66
+ },
67
+ returnDescriptions: {
68
+ locale: "active provider BCP 47 locale; 'en' without a provider.",
69
+ },
70
+ };
@@ -0,0 +1,34 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file useLocale.ts
7
+ * @input InternationalizationContext (via use())
8
+ * @output The active BCP 47 locale tag
9
+ * @position Public provider-aware locale accessor. Exported from the i18n
10
+ * barrel for components, sibling packages, and consumers that must thread
11
+ * the provider locale into pure formatting helpers. Returns `'en'` when
12
+ * called outside a provider, matching useTranslator/useDirection.
13
+ *
14
+ * This is the approved way to read the locale that feeds a formatting helper
15
+ * (`plainDateFormat`, `formatInstant`, chart formatters, …) or `useCollator()`.
16
+ * Reading `InternationalizationContext` directly for just its `locale` field,
17
+ * or reaching for `navigator.language`/a hardcoded literal, bypasses that
18
+ * provider-backed contract.
19
+ *
20
+ * SYNC: When modified, update:
21
+ * - /packages/core/src/i18n/InternationalizationContext.ts
22
+ * - /packages/core/src/i18n/useLocale.doc.mjs
23
+ * - /packages/core/src/i18n/index.ts
24
+ * - /packages/core/src/i18n/__tests__/useLocale.test.tsx
25
+ */
26
+
27
+ import {use} from 'react';
28
+ import {InternationalizationContext} from './InternationalizationContext';
29
+ import type {Locale} from './types';
30
+
31
+ export function useLocale(): Locale {
32
+ const ctx = use(InternationalizationContext);
33
+ return ctx.locale;
34
+ }
@@ -4,7 +4,7 @@
4
4
  export const docs = {
5
5
  name: 'useTranslator',
6
6
  displayName: 'useTranslator',
7
- group: 'Utilities',
7
+ category: 'utilities',
8
8
  keywords: [
9
9
  'i18n',
10
10
  'internationalization',
package/src/reset.css CHANGED
@@ -262,9 +262,16 @@
262
262
  }
263
263
 
264
264
  /*
265
- * Default cursor for disabled elements.
265
+ * Disabled elements take back any interactive cursor: a control that will
266
+ * not respond must not answer the pointer as though it will. `default`
267
+ * rather than `not-allowed` — a disabled control sealed behind
268
+ * `pointer-events: none` shows whatever its ancestor shows, and one cursor
269
+ * everywhere beats a stronger one we can only paint on half of them.
270
+ * Covers [aria-disabled] too: astryx keeps a disabled control focusable
271
+ * that way wherever its reason must stay discoverable (Button with a
272
+ * tooltip, Selector's trigger, SideNavItem).
266
273
  */
267
- :where(:disabled) {
274
+ :where(:disabled, [aria-disabled='true']) {
268
275
  cursor: default;
269
276
  }
270
277