@astryxdesign/core 0.4.7 → 0.5.0-canary.32a62fd

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 (554) hide show
  1. package/CHANGELOG.md +161 -1
  2. package/dist/AppShell/AppShell.d.ts.map +1 -1
  3. package/dist/AppShell/AppShell.js +3 -2
  4. package/dist/AspectRatio/AspectRatio.d.ts +24 -0
  5. package/dist/AspectRatio/AspectRatio.d.ts.map +1 -1
  6. package/dist/AspectRatio/AspectRatio.js +23 -4
  7. package/dist/Avatar/Avatar.d.ts +25 -1
  8. package/dist/Avatar/Avatar.d.ts.map +1 -1
  9. package/dist/Avatar/Avatar.js +58 -19
  10. package/dist/Avatar/index.d.ts +2 -2
  11. package/dist/Avatar/index.d.ts.map +1 -1
  12. package/dist/Avatar/index.js +1 -1
  13. package/dist/AvatarGroup/AvatarGroup.d.ts +9 -2
  14. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  15. package/dist/AvatarGroup/AvatarGroup.js +8 -4
  16. package/dist/AvatarGroup/AvatarGroupContext.d.ts +2 -1
  17. package/dist/AvatarGroup/AvatarGroupContext.d.ts.map +1 -1
  18. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  19. package/dist/AvatarGroup/AvatarGroupOverflow.js +10 -6
  20. package/dist/Banner/Banner.d.ts +40 -15
  21. package/dist/Banner/Banner.d.ts.map +1 -1
  22. package/dist/Banner/Banner.js +51 -18
  23. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  24. package/dist/BottomSheet/BottomSheet.js +17 -4
  25. package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
  26. package/dist/BottomSheet/BottomSheetSwitcher.js +3 -2
  27. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  28. package/dist/Breadcrumbs/BreadcrumbItem.js +11 -10
  29. package/dist/Button/Button.d.ts.map +1 -1
  30. package/dist/Button/Button.js +5 -4
  31. package/dist/ButtonGroup/ButtonGroup.d.ts +5 -1
  32. package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
  33. package/dist/ButtonGroup/ButtonGroup.js +26 -7
  34. package/dist/Calendar/Calendar.d.ts +3 -1
  35. package/dist/Calendar/Calendar.d.ts.map +1 -1
  36. package/dist/Calendar/Calendar.js +13 -14
  37. package/dist/Calendar/getInitialFocusDate.d.ts +46 -0
  38. package/dist/Calendar/getInitialFocusDate.d.ts.map +1 -0
  39. package/dist/Calendar/getInitialFocusDate.js +62 -0
  40. package/dist/Carousel/Carousel.d.ts.map +1 -1
  41. package/dist/Carousel/Carousel.js +3 -3
  42. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  43. package/dist/Chat/ChatComposerInput.js +2 -3
  44. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  45. package/dist/Chat/ChatLayout.js +3 -3
  46. package/dist/Chat/ChatMessageList.d.ts +22 -3
  47. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  48. package/dist/Chat/ChatMessageList.js +6 -3
  49. package/dist/Chat/ChatTokenizedText.d.ts +2 -0
  50. package/dist/Chat/ChatTokenizedText.d.ts.map +1 -1
  51. package/dist/Chat/ChatTokenizedText.js +11 -6
  52. package/dist/Chat/useChatComposerTokens.js +1 -1
  53. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  54. package/dist/CheckboxInput/CheckboxInput.js +10 -3
  55. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  56. package/dist/ClickableCard/ClickableCard.js +3 -3
  57. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  58. package/dist/CodeBlock/CodeBlock.js +15 -4
  59. package/dist/CodeBlock/highlightRanges.js +1 -1
  60. package/dist/CodeBlock/highlightStyles.js +13 -13
  61. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  62. package/dist/CommandPalette/CommandPaletteInput.js +3 -2
  63. package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
  64. package/dist/CommandPalette/CommandPaletteItem.js +3 -2
  65. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  66. package/dist/ContextMenu/ContextMenu.js +4 -3
  67. package/dist/DateInput/DateInput.d.ts +43 -0
  68. package/dist/DateInput/DateInput.d.ts.map +1 -1
  69. package/dist/DateInput/DateInput.js +22 -2
  70. package/dist/DateInput/NativeDateField.d.ts +10 -0
  71. package/dist/DateInput/NativeDateField.d.ts.map +1 -0
  72. package/dist/DateInput/NativeDateField.js +477 -0
  73. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  74. package/dist/DateInput/TouchDateField.js +38 -4
  75. package/dist/DateInput/index.d.ts +1 -1
  76. package/dist/DateInput/index.d.ts.map +1 -1
  77. package/dist/DateTimeInput/DateTimeInput.d.ts +21 -1
  78. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  79. package/dist/DateTimeInput/DateTimeInput.js +406 -12
  80. package/dist/DateTimeInput/index.d.ts +1 -1
  81. package/dist/DateTimeInput/index.d.ts.map +1 -1
  82. package/dist/Dialog/Dialog.d.ts +7 -1
  83. package/dist/Dialog/Dialog.d.ts.map +1 -1
  84. package/dist/Dialog/Dialog.js +89 -58
  85. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  86. package/dist/DropdownMenu/DropdownMenuSubMenu.js +6 -5
  87. package/dist/Field/FieldLabel.d.ts.map +1 -1
  88. package/dist/Field/FieldLabel.js +9 -1
  89. package/dist/FileInput/FileInput.d.ts.map +1 -1
  90. package/dist/FileInput/FileInput.js +3 -2
  91. package/dist/Heading/Heading.d.ts.map +1 -1
  92. package/dist/Heading/Heading.js +6 -2
  93. package/dist/HoverCard/HoverCard.d.ts +6 -0
  94. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  95. package/dist/HoverCard/HoverCard.js +52 -3
  96. package/dist/HoverCard/useHoverCard.d.ts +16 -2
  97. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  98. package/dist/HoverCard/useHoverCard.js +74 -26
  99. package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -1
  100. package/dist/Indicator/CheckboxIndicator.js +6 -2
  101. package/dist/Item/Item.d.ts.map +1 -1
  102. package/dist/Item/Item.js +4 -2
  103. package/dist/Kbd/Kbd.d.ts.map +1 -1
  104. package/dist/Kbd/Kbd.js +2 -19
  105. package/dist/Layer/LayerDepthContext.d.ts +52 -0
  106. package/dist/Layer/LayerDepthContext.d.ts.map +1 -0
  107. package/dist/Layer/LayerDepthContext.js +66 -0
  108. package/dist/Layer/index.d.ts +3 -0
  109. package/dist/Layer/index.d.ts.map +1 -1
  110. package/dist/Layer/index.js +4 -0
  111. package/dist/Layer/layerStack.d.ts +98 -0
  112. package/dist/Layer/layerStack.d.ts.map +1 -0
  113. package/dist/Layer/layerStack.js +306 -0
  114. package/dist/Layer/useLayerDismissal.d.ts +93 -0
  115. package/dist/Layer/useLayerDismissal.d.ts.map +1 -0
  116. package/dist/Layer/useLayerDismissal.js +91 -0
  117. package/dist/Lightbox/Lightbox.d.ts +1 -0
  118. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  119. package/dist/Lightbox/Lightbox.js +103 -81
  120. package/dist/Markdown/index.d.ts +1 -1
  121. package/dist/Markdown/index.d.ts.map +1 -1
  122. package/dist/Markdown/parser.d.ts +38 -1
  123. package/dist/Markdown/parser.d.ts.map +1 -1
  124. package/dist/Markdown/parser.js +177 -29
  125. package/dist/MobileNav/MobileNav.d.ts +6 -1
  126. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  127. package/dist/MobileNav/MobileNav.js +61 -36
  128. package/dist/MultiSelector/MultiSelector.d.ts +15 -1
  129. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  130. package/dist/MultiSelector/MultiSelector.js +17 -6
  131. package/dist/MultiSelector/index.d.ts +1 -1
  132. package/dist/MultiSelector/index.d.ts.map +1 -1
  133. package/dist/NavIcon/NavIcon.d.ts.map +1 -1
  134. package/dist/NavIcon/NavIcon.js +5 -1
  135. package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
  136. package/dist/NavMenu/NavHeadingMenu.js +3 -2
  137. package/dist/NumberInput/NumberInput.d.ts +1 -0
  138. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  139. package/dist/NumberInput/NumberInput.js +27 -37
  140. package/dist/NumberInput/numberParser.d.ts +43 -0
  141. package/dist/NumberInput/numberParser.d.ts.map +1 -0
  142. package/dist/NumberInput/numberParser.js +293 -0
  143. package/dist/Outline/Outline.d.ts.map +1 -1
  144. package/dist/Outline/Outline.js +3 -2
  145. package/dist/OverflowList/OverflowList.d.ts.map +1 -1
  146. package/dist/OverflowList/OverflowList.js +3 -2
  147. package/dist/Overlay/Overlay.d.ts.map +1 -1
  148. package/dist/Overlay/Overlay.js +3 -2
  149. package/dist/Popover/usePopover.d.ts.map +1 -1
  150. package/dist/Popover/usePopover.js +20 -17
  151. package/dist/PowerSearch/PowerSearch.d.ts +8 -2
  152. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  153. package/dist/PowerSearch/PowerSearch.js +19 -6
  154. package/dist/PowerSearch/PowerSearchEditPopover.d.ts +3 -1
  155. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  156. package/dist/PowerSearch/PowerSearchEditPopover.js +28 -6
  157. package/dist/PowerSearch/PowerSearchValueEditor.d.ts +3 -1
  158. package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
  159. package/dist/PowerSearch/PowerSearchValueEditor.js +19 -9
  160. package/dist/PowerSearch/types.d.ts +2 -0
  161. package/dist/PowerSearch/types.d.ts.map +1 -1
  162. package/dist/PowerSearch/usePowerSearchSource.d.ts +6 -1
  163. package/dist/PowerSearch/usePowerSearchSource.d.ts.map +1 -1
  164. package/dist/PowerSearch/usePowerSearchSource.js +14 -5
  165. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  166. package/dist/ProgressBar/ProgressBar.js +18 -5
  167. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  168. package/dist/Resizable/ResizeHandle.js +3 -2
  169. package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  170. package/dist/SegmentedControl/SegmentedControl.js +3 -2
  171. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  172. package/dist/SelectableCard/SelectableCard.js +3 -3
  173. package/dist/Selector/Selector.d.ts.map +1 -1
  174. package/dist/Selector/Selector.js +5 -0
  175. package/dist/SideNav/SideNav.d.ts.map +1 -1
  176. package/dist/SideNav/SideNav.js +4 -3
  177. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  178. package/dist/SideNav/SideNavHeading.js +8 -7
  179. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  180. package/dist/SideNav/SideNavItem.js +4 -3
  181. package/dist/Slider/Slider.d.ts.map +1 -1
  182. package/dist/Slider/Slider.js +3 -3
  183. package/dist/Spinner/Spinner.d.ts +3 -3
  184. package/dist/Spinner/Spinner.d.ts.map +1 -1
  185. package/dist/Spinner/Spinner.js +130 -78
  186. package/dist/StatusDot/StatusDot.d.ts.map +1 -1
  187. package/dist/StatusDot/StatusDot.js +6 -1
  188. package/dist/Stepper/Step.d.ts +140 -0
  189. package/dist/Stepper/Step.d.ts.map +1 -0
  190. package/dist/Stepper/Step.js +1045 -0
  191. package/dist/Stepper/StepStatus.d.ts +24 -0
  192. package/dist/Stepper/StepStatus.d.ts.map +1 -0
  193. package/dist/Stepper/StepStatus.js +1 -0
  194. package/dist/Stepper/Stepper.d.ts +93 -0
  195. package/dist/Stepper/Stepper.d.ts.map +1 -0
  196. package/dist/Stepper/Stepper.js +184 -0
  197. package/dist/Stepper/StepperContext.d.ts +41 -0
  198. package/dist/Stepper/StepperContext.d.ts.map +1 -0
  199. package/dist/Stepper/StepperContext.js +34 -0
  200. package/dist/Stepper/index.d.ts +8 -0
  201. package/dist/Stepper/index.d.ts.map +1 -0
  202. package/dist/Stepper/index.js +7 -0
  203. package/dist/Stepper/stepper.stylex.d.ts +15 -0
  204. package/dist/Stepper/stepper.stylex.d.ts.map +1 -0
  205. package/dist/Stepper/stepper.stylex.js +20 -0
  206. package/dist/Switch/Switch.d.ts.map +1 -1
  207. package/dist/Switch/Switch.js +8 -3
  208. package/dist/TabList/Tab.d.ts +15 -2
  209. package/dist/TabList/Tab.d.ts.map +1 -1
  210. package/dist/TabList/Tab.js +32 -7
  211. package/dist/TabList/TabList.d.ts +46 -7
  212. package/dist/TabList/TabList.d.ts.map +1 -1
  213. package/dist/TabList/TabList.js +353 -23
  214. package/dist/TabList/TabListContext.d.ts +11 -1
  215. package/dist/TabList/TabListContext.d.ts.map +1 -1
  216. package/dist/TabList/TabListContext.js +11 -2
  217. package/dist/TabList/TabMenu.d.ts.map +1 -1
  218. package/dist/TabList/TabMenu.js +3 -2
  219. package/dist/TabList/index.d.ts +2 -2
  220. package/dist/TabList/index.d.ts.map +1 -1
  221. package/dist/Table/BaseTable.d.ts.map +1 -1
  222. package/dist/Table/BaseTable.js +10 -2
  223. package/dist/Table/Table.d.ts.map +1 -1
  224. package/dist/Table/Table.js +3 -6
  225. package/dist/Table/TableRow.d.ts +16 -5
  226. package/dist/Table/TableRow.d.ts.map +1 -1
  227. package/dist/Table/TableRow.js +16 -5
  228. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  229. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +20 -8
  230. package/dist/Table/plugins/pagination/useTablePagination.d.ts +3 -0
  231. package/dist/Table/plugins/pagination/useTablePagination.d.ts.map +1 -1
  232. package/dist/Table/plugins/pagination/useTablePagination.js +21 -4
  233. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  234. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +7 -2
  235. package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts.map +1 -1
  236. package/dist/Table/plugins/rowStatus/useTableRowStatus.js +10 -3
  237. package/dist/Table/plugins/selection/useTableSelection.d.ts +16 -0
  238. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  239. package/dist/Table/plugins/selection/useTableSelection.js +19 -5
  240. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
  241. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +3 -4
  242. package/dist/Table/types.d.ts +22 -4
  243. package/dist/Table/types.d.ts.map +1 -1
  244. package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
  245. package/dist/Table/useBaseTablePlugins.js +5 -0
  246. package/dist/Text/Text.d.ts.map +1 -1
  247. package/dist/Text/Text.js +6 -2
  248. package/dist/TextArea/TextArea.d.ts.map +1 -1
  249. package/dist/TextArea/TextArea.js +9 -3
  250. package/dist/TextInput/TextInput.d.ts.map +1 -1
  251. package/dist/TextInput/TextInput.js +3 -2
  252. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  253. package/dist/TimeInput/TimeInput.js +3 -2
  254. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  255. package/dist/Timestamp/Timestamp.js +5 -3
  256. package/dist/Token/TokenLink.d.ts.map +1 -1
  257. package/dist/Token/TokenLink.js +2 -2
  258. package/dist/Tokenizer/Tokenizer.d.ts +3 -1
  259. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  260. package/dist/Tokenizer/Tokenizer.js +2 -0
  261. package/dist/Tooltip/Tooltip.d.ts +5 -0
  262. package/dist/Tooltip/Tooltip.d.ts.map +1 -1
  263. package/dist/Tooltip/useTooltip.d.ts +5 -0
  264. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  265. package/dist/Tooltip/useTooltip.js +39 -24
  266. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  267. package/dist/TopNav/TopNavHeading.js +5 -4
  268. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  269. package/dist/TopNav/TopNavMegaMenu.js +3 -3
  270. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  271. package/dist/TopNav/TopNavMenu.js +4 -3
  272. package/dist/Typeahead/BaseTypeahead.d.ts +2 -0
  273. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  274. package/dist/Typeahead/BaseTypeahead.js +68 -29
  275. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  276. package/dist/Typeahead/Typeahead.js +3 -2
  277. package/dist/astryx.css +94 -7
  278. package/dist/hooks/index.d.ts +1 -0
  279. package/dist/hooks/index.d.ts.map +1 -1
  280. package/dist/hooks/index.js +1 -0
  281. package/dist/hooks/useFocusTrap.d.ts +7 -4
  282. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  283. package/dist/hooks/useFocusTrap.js +60 -95
  284. package/dist/hooks/useHotkeys.d.ts.map +1 -1
  285. package/dist/hooks/useHotkeys.js +3 -18
  286. package/dist/hooks/useMergedRefs.d.ts +18 -0
  287. package/dist/hooks/useMergedRefs.d.ts.map +1 -0
  288. package/dist/hooks/useMergedRefs.js +25 -0
  289. package/dist/index.d.ts +1 -0
  290. package/dist/index.d.ts.map +1 -1
  291. package/dist/index.js +1 -0
  292. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  293. package/dist/theme/derivedVarRegistry.js +24 -4
  294. package/dist/theme/syntax/tokens.d.ts +1 -1
  295. package/dist/theme/syntax/tokens.d.ts.map +1 -1
  296. package/dist/theme/syntax/tokens.js +5 -2
  297. package/dist/utils/groupItems.d.ts +5 -1
  298. package/dist/utils/groupItems.d.ts.map +1 -1
  299. package/dist/utils/groupItems.js +9 -9
  300. package/dist/utils/index.d.ts +1 -1
  301. package/dist/utils/index.d.ts.map +1 -1
  302. package/dist/utils/isApplePlatform.d.ts +18 -0
  303. package/dist/utils/isApplePlatform.d.ts.map +1 -0
  304. package/dist/utils/isApplePlatform.js +37 -0
  305. package/dist/utils/sharedResizeObserver.d.ts.map +1 -1
  306. package/dist/utils/sharedResizeObserver.js +10 -1
  307. package/dist/utils/timeParser.d.ts +1 -1
  308. package/dist/utils/timeParser.d.ts.map +1 -1
  309. package/dist/utils/timeParser.js +26 -12
  310. package/locales/en.json +31 -7
  311. package/locales/pseudo.json +18 -0
  312. package/package.json +8 -3
  313. package/src/AppShell/AppShell.tsx +3 -2
  314. package/src/AspectRatio/AspectRatio.doc.mjs +6 -3
  315. package/src/AspectRatio/AspectRatio.test.tsx +57 -10
  316. package/src/AspectRatio/AspectRatio.tsx +40 -1
  317. package/src/Avatar/Avatar.doc.mjs +14 -3
  318. package/src/Avatar/Avatar.test.tsx +97 -0
  319. package/src/Avatar/Avatar.tsx +125 -52
  320. package/src/Avatar/index.ts +2 -2
  321. package/src/AvatarGroup/AvatarGroup.doc.mjs +8 -2
  322. package/src/AvatarGroup/AvatarGroup.test.tsx +24 -0
  323. package/src/AvatarGroup/AvatarGroup.tsx +15 -6
  324. package/src/AvatarGroup/AvatarGroupContext.ts +5 -3
  325. package/src/AvatarGroup/AvatarGroupOverflow.tsx +10 -4
  326. package/src/Banner/Banner.doc.mjs +13 -11
  327. package/src/Banner/Banner.test.tsx +102 -15
  328. package/src/Banner/Banner.tsx +72 -25
  329. package/src/BottomSheet/BottomSheet.test.tsx +123 -0
  330. package/src/BottomSheet/BottomSheet.tsx +17 -4
  331. package/src/BottomSheet/BottomSheetSwitcher.tsx +3 -2
  332. package/src/Breadcrumbs/BreadcrumbItem.tsx +9 -5
  333. package/src/Button/Button.doc.mjs +22 -0
  334. package/src/Button/Button.test.tsx +13 -0
  335. package/src/Button/Button.tsx +5 -4
  336. package/src/ButtonGroup/ButtonGroup.doc.mjs +10 -1
  337. package/src/ButtonGroup/ButtonGroup.test.tsx +391 -1
  338. package/src/ButtonGroup/ButtonGroup.tsx +23 -5
  339. package/src/Calendar/Calendar.doc.mjs +4 -3
  340. package/src/Calendar/Calendar.test.tsx +52 -0
  341. package/src/Calendar/Calendar.tsx +18 -15
  342. package/src/Calendar/getInitialFocusDate.test.ts +94 -0
  343. package/src/Calendar/getInitialFocusDate.ts +93 -0
  344. package/src/Carousel/Carousel.tsx +3 -2
  345. package/src/Chat/ChatComposerInput.tsx +5 -1
  346. package/src/Chat/ChatLayout.tsx +3 -2
  347. package/src/Chat/ChatMessageList.doc.mjs +9 -1
  348. package/src/Chat/ChatMessageList.test.tsx +46 -0
  349. package/src/Chat/ChatMessageList.tsx +28 -4
  350. package/src/Chat/ChatTokenizedText.tsx +17 -10
  351. package/src/Chat/useChatComposerTokens.ts +1 -1
  352. package/src/CheckboxInput/CheckboxInput.doc.mjs +2 -0
  353. package/src/CheckboxInput/CheckboxInput.test.tsx +15 -0
  354. package/src/CheckboxInput/CheckboxInput.tsx +8 -2
  355. package/src/ClickableCard/ClickableCard.tsx +3 -2
  356. package/src/CodeBlock/CodeBlock.doc.mjs +16 -4
  357. package/src/CodeBlock/CodeBlock.test.tsx +37 -0
  358. package/src/CodeBlock/CodeBlock.tsx +20 -4
  359. package/src/CodeBlock/highlightRanges.ts +1 -1
  360. package/src/CodeBlock/highlightStyles.ts +13 -13
  361. package/src/CommandPalette/CommandPaletteInput.tsx +3 -2
  362. package/src/CommandPalette/CommandPaletteItem.tsx +3 -2
  363. package/src/ContextMenu/ContextMenu.doc.mjs +5 -0
  364. package/src/ContextMenu/ContextMenu.tsx +4 -3
  365. package/src/DateInput/DateInput.doc.mjs +16 -0
  366. package/src/DateInput/DateInput.tsx +55 -2
  367. package/src/DateInput/DateInputTouch.test.tsx +68 -9
  368. package/src/DateInput/NativeDateField.test.tsx +565 -0
  369. package/src/DateInput/NativeDateField.tsx +623 -0
  370. package/src/DateInput/TouchDateField.tsx +38 -4
  371. package/src/DateInput/index.ts +1 -0
  372. package/src/DateTimeInput/DateTimeInput.doc.mjs +18 -0
  373. package/src/DateTimeInput/DateTimeInput.test.tsx +1088 -0
  374. package/src/DateTimeInput/DateTimeInput.tsx +556 -24
  375. package/src/DateTimeInput/index.ts +1 -0
  376. package/src/Dialog/Dialog.doc.mjs +8 -3
  377. package/src/Dialog/Dialog.test.tsx +261 -1
  378. package/src/Dialog/Dialog.tsx +109 -58
  379. package/src/DropdownMenu/DropdownMenu.doc.mjs +6 -0
  380. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +8 -5
  381. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +8 -11
  382. package/src/Field/Field.doc.mjs +13 -2
  383. package/src/Field/FieldLabel.test.tsx +29 -0
  384. package/src/Field/FieldLabel.tsx +7 -0
  385. package/src/FileInput/FileInput.tsx +3 -2
  386. package/src/Heading/Heading.test.tsx +23 -1
  387. package/src/Heading/Heading.tsx +6 -2
  388. package/src/HoverCard/HoverCard.doc.mjs +13 -2
  389. package/src/HoverCard/HoverCard.test.tsx +101 -4
  390. package/src/HoverCard/HoverCard.tsx +71 -3
  391. package/src/HoverCard/useHoverCard.tsx +101 -33
  392. package/src/Indicator/CheckboxIndicator.tsx +14 -8
  393. package/src/Indicator/Indicator.doc.mjs +2 -0
  394. package/src/Item/Item.tsx +5 -4
  395. package/src/Kbd/Kbd.tsx +2 -19
  396. package/src/Layer/LayerDepthContext.tsx +62 -0
  397. package/src/Layer/index.ts +9 -0
  398. package/src/Layer/layerDismissalFamilies.test.tsx +359 -0
  399. package/src/Layer/layerDismissalInvariants.test.tsx +417 -0
  400. package/src/Layer/layerStack.ts +362 -0
  401. package/src/Layer/useLayerDismissal.test.tsx +469 -0
  402. package/src/Layer/useLayerDismissal.ts +173 -0
  403. package/src/Layout/Layout.doc.mjs +2 -2
  404. package/src/Lightbox/Lightbox.doc.mjs +12 -0
  405. package/src/Lightbox/Lightbox.tsx +124 -102
  406. package/src/Link/Link.doc.mjs +39 -0
  407. package/src/Markdown/Markdown.doc.mjs +5 -0
  408. package/src/Markdown/incremental.test.ts +16 -2
  409. package/src/Markdown/index.ts +1 -0
  410. package/src/Markdown/parser.perf.test.ts +96 -1
  411. package/src/Markdown/parser.test.ts +145 -2
  412. package/src/Markdown/parser.ts +244 -29
  413. package/src/MobileNav/MobileNav.tsx +62 -36
  414. package/src/MoreMenu/MoreMenu.doc.mjs +7 -1
  415. package/src/MultiSelector/MultiSelector.doc.mjs +27 -0
  416. package/src/MultiSelector/MultiSelector.test.tsx +106 -0
  417. package/src/MultiSelector/MultiSelector.tsx +50 -6
  418. package/src/MultiSelector/index.ts +1 -0
  419. package/src/NavIcon/NavIcon.doc.mjs +8 -2
  420. package/src/NavIcon/NavIcon.test.tsx +9 -0
  421. package/src/NavIcon/NavIcon.tsx +5 -1
  422. package/src/NavMenu/NavHeadingMenu.tsx +3 -2
  423. package/src/NumberInput/NumberInput.doc.mjs +20 -0
  424. package/src/NumberInput/NumberInput.tsx +28 -29
  425. package/src/NumberInput/numberParser.test.ts +137 -0
  426. package/src/NumberInput/numberParser.ts +346 -0
  427. package/src/Outline/Outline.tsx +3 -2
  428. package/src/OverflowList/OverflowList.tsx +3 -2
  429. package/src/Overlay/Overlay.tsx +3 -2
  430. package/src/Popover/usePopover.tsx +31 -28
  431. package/src/PowerSearch/PowerSearch.doc.mjs +160 -28
  432. package/src/PowerSearch/PowerSearch.test.tsx +240 -1
  433. package/src/PowerSearch/PowerSearch.tsx +34 -5
  434. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +201 -0
  435. package/src/PowerSearch/PowerSearchEditPopover.tsx +29 -2
  436. package/src/PowerSearch/PowerSearchValueEditor.test.tsx +47 -1
  437. package/src/PowerSearch/PowerSearchValueEditor.tsx +15 -0
  438. package/src/PowerSearch/types.ts +2 -0
  439. package/src/PowerSearch/usePowerSearchSource.test.ts +82 -2
  440. package/src/PowerSearch/usePowerSearchSource.ts +13 -3
  441. package/src/ProgressBar/ProgressBar.doc.mjs +42 -6
  442. package/src/ProgressBar/ProgressBar.test.tsx +24 -0
  443. package/src/ProgressBar/ProgressBar.tsx +28 -8
  444. package/src/Resizable/ResizeHandle.tsx +3 -2
  445. package/src/SegmentedControl/SegmentedControl.tsx +3 -2
  446. package/src/SelectableCard/SelectableCard.tsx +3 -2
  447. package/src/Selector/Selector.doc.mjs +12 -1
  448. package/src/Selector/Selector.test.tsx +45 -1
  449. package/src/Selector/Selector.tsx +11 -1
  450. package/src/SideNav/SideNav.doc.mjs +6 -6
  451. package/src/SideNav/SideNav.tsx +4 -2
  452. package/src/SideNav/SideNavHeading.tsx +12 -12
  453. package/src/SideNav/SideNavItem.tsx +4 -2
  454. package/src/Slider/Slider.tsx +3 -2
  455. package/src/Spinner/Spinner.test.tsx +147 -1
  456. package/src/Spinner/Spinner.tsx +120 -101
  457. package/src/StatusDot/StatusDot.doc.mjs +8 -2
  458. package/src/StatusDot/StatusDot.test.tsx +9 -0
  459. package/src/StatusDot/StatusDot.tsx +7 -1
  460. package/src/Stepper/Step.doc.mjs +98 -0
  461. package/src/Stepper/Step.tsx +1638 -0
  462. package/src/Stepper/StepStatus.ts +26 -0
  463. package/src/Stepper/Stepper.doc.mjs +370 -0
  464. package/src/Stepper/Stepper.test.tsx +1024 -0
  465. package/src/Stepper/Stepper.tsx +258 -0
  466. package/src/Stepper/StepperContext.ts +71 -0
  467. package/src/Stepper/index.ts +18 -0
  468. package/src/Stepper/stepper.stylex.ts +19 -0
  469. package/src/Switch/Switch.doc.mjs +2 -0
  470. package/src/Switch/Switch.test.tsx +10 -0
  471. package/src/Switch/Switch.tsx +6 -2
  472. package/src/TabList/Tab.doc.mjs +13 -1
  473. package/src/TabList/Tab.tsx +67 -7
  474. package/src/TabList/TabList.doc.mjs +22 -6
  475. package/src/TabList/TabList.test.tsx +559 -0
  476. package/src/TabList/TabList.tsx +490 -22
  477. package/src/TabList/TabListContext.ts +13 -2
  478. package/src/TabList/TabMenu.tsx +3 -2
  479. package/src/TabList/index.ts +6 -2
  480. package/src/Table/BaseTable.tsx +12 -4
  481. package/src/Table/Table.doc.mjs +9 -2
  482. package/src/Table/Table.test.tsx +132 -14
  483. package/src/Table/Table.tsx +3 -8
  484. package/src/Table/TableBody.doc.mjs +40 -0
  485. package/src/Table/TableFooter.doc.mjs +40 -0
  486. package/src/Table/TableHeader.doc.mjs +40 -0
  487. package/src/Table/TableRow.tsx +16 -5
  488. package/src/Table/plugins/groupedRows/useTableGroupedRows-perf.test.tsx +112 -0
  489. package/src/Table/plugins/groupedRows/useTableGroupedRows.test.tsx +100 -0
  490. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +17 -8
  491. package/src/Table/plugins/pagination/useTablePagination.test.tsx +34 -4
  492. package/src/Table/plugins/pagination/useTablePagination.tsx +35 -3
  493. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +9 -2
  494. package/src/Table/plugins/rowStatus/useTableRowStatus.test.tsx +13 -7
  495. package/src/Table/plugins/rowStatus/useTableRowStatus.tsx +12 -3
  496. package/src/Table/plugins/selection/useTableSelection.test.tsx +76 -0
  497. package/src/Table/plugins/selection/useTableSelection.tsx +40 -7
  498. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +1 -2
  499. package/src/Table/types.ts +22 -4
  500. package/src/Table/useBaseTablePlugins.ts +5 -0
  501. package/src/Table/useTableGroupedRows.doc.mjs +5 -4
  502. package/src/Table/useTablePagination.doc.mjs +7 -0
  503. package/src/Table/useTableRowStatus.doc.mjs +1 -1
  504. package/src/Table/useTableSelection.doc.mjs +31 -0
  505. package/src/Text/Text.test.tsx +23 -1
  506. package/src/Text/Text.tsx +6 -2
  507. package/src/TextArea/TextArea.doc.mjs +8 -2
  508. package/src/TextArea/TextArea.test.tsx +11 -0
  509. package/src/TextArea/TextArea.tsx +15 -8
  510. package/src/TextInput/TextInput.doc.mjs +10 -0
  511. package/src/TextInput/TextInput.tsx +3 -2
  512. package/src/Thumbnail/Thumbnail.doc.mjs +1 -1
  513. package/src/TimeInput/TimeInput.tsx +2 -2
  514. package/src/Timestamp/Timestamp.tsx +4 -2
  515. package/src/Toast/Toast.doc.mjs +6 -0
  516. package/src/Token/TokenLink.tsx +2 -2
  517. package/src/Tokenizer/Tokenizer.doc.mjs +27 -0
  518. package/src/Tokenizer/Tokenizer.tsx +4 -0
  519. package/src/Toolbar/Toolbar.doc.mjs +5 -0
  520. package/src/Tooltip/Tooltip.doc.mjs +5 -0
  521. package/src/Tooltip/Tooltip.test.tsx +32 -0
  522. package/src/Tooltip/Tooltip.tsx +5 -0
  523. package/src/Tooltip/useTooltip.tsx +47 -24
  524. package/src/TopNav/TopNavHeading.tsx +5 -4
  525. package/src/TopNav/TopNavMegaMenu.tsx +3 -2
  526. package/src/TopNav/TopNavMenu.tsx +4 -3
  527. package/src/Typeahead/BaseTypeahead.doc.mjs +11 -0
  528. package/src/Typeahead/BaseTypeahead.tsx +85 -33
  529. package/src/Typeahead/Typeahead.doc.mjs +5 -0
  530. package/src/Typeahead/Typeahead.test.tsx +49 -0
  531. package/src/Typeahead/Typeahead.tsx +3 -2
  532. package/src/hooks/index.ts +2 -0
  533. package/src/hooks/useContainerReveal.doc.mjs +2 -2
  534. package/src/hooks/useFocusTrap.test.tsx +14 -0
  535. package/src/hooks/useFocusTrap.ts +62 -111
  536. package/src/hooks/useFocusTrapEscapeShim.test.tsx +165 -0
  537. package/src/hooks/useHotkeys.ts +3 -18
  538. package/src/hooks/useMergedRefs.doc.mjs +79 -0
  539. package/src/hooks/useMergedRefs.test.tsx +62 -0
  540. package/src/hooks/useMergedRefs.ts +36 -0
  541. package/src/index.ts +1 -0
  542. package/src/theme/MediaTheme.doc.mjs +5 -5
  543. package/src/theme/derivedVarRegistry.test.ts +19 -3
  544. package/src/theme/derivedVarRegistry.ts +23 -4
  545. package/src/theme/generateThemeRules.test.ts +37 -0
  546. package/src/theme/syntax/tokens.ts +5 -2
  547. package/src/utils/groupItems.ts +12 -6
  548. package/src/utils/index.ts +1 -1
  549. package/src/utils/isApplePlatform.test.ts +61 -0
  550. package/src/utils/isApplePlatform.ts +37 -0
  551. package/src/utils/sharedResizeObserver.ts +10 -2
  552. package/src/utils/timeParser.test.ts +6 -1
  553. package/src/utils/timeParser.ts +35 -13
  554. package/src/__tests__/inputWidthContract.test.tsx +0 -69
@@ -0,0 +1,137 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ import {describe, it, expect} from 'vitest';
4
+ import {parseLocaleNumber} from './numberParser';
5
+
6
+ const NBSP = '\u00A0';
7
+ const NARROW_NBSP = '\u202F';
8
+ const APOSTROPHE = '\u2019';
9
+
10
+ /**
11
+ * The contract, enumerated. A row is `[input, locale, expected]`, and `null`
12
+ * means the field stays visibly invalid rather than committing a guess.
13
+ */
14
+ const CORPUS: [string, string, number | null][] = [
15
+ // Grouped — the case this exists for, and it holds in every locale because
16
+ // a repeated separator with three digits after it cannot be a decimal point.
17
+ ['1,234,234,234', 'en-US', 1234234234],
18
+ ['1,234,234,234', 'de-DE', 1234234234],
19
+ ['1,234,234,234', 'fr-FR', 1234234234],
20
+ ['1,234,234,234', 'ar-SA', 1234234234],
21
+ ['1.234.234.234', 'de-DE', 1234234234],
22
+ ['1.234.234.234', 'en-US', 1234234234],
23
+ [`1${NARROW_NBSP}234${NARROW_NBSP}234${NARROW_NBSP}234`, 'fr-FR', 1234234234],
24
+ [`1${NBSP}234${NBSP}234`, 'fr-FR', 1234234],
25
+ [`1${NBSP}234`, 'en-US', 1234],
26
+ [`1${APOSTROPHE}234${APOSTROPHE}234`, 'de-CH', 1234234],
27
+ ["1'234'234", 'de-CH', 1234234],
28
+ ['1,234', 'en-US', 1234],
29
+ ['1,234', 'de-DE', 1.234],
30
+
31
+ // Indian lakh grouping, derived from the locale's own group sizes.
32
+ ['12,34,567', 'en-IN', 1234567],
33
+ ['12,34,567', 'en-US', null],
34
+
35
+ // Ragged grouping is a typo, not a number: the last group is not three.
36
+ ['1,23,4', 'en-US', null],
37
+ ['1,2345', 'en-US', null],
38
+ ['12 34', 'en-US', null],
39
+
40
+ // One separator, one meaning per locale, and no meaning across them.
41
+ ['1,5', 'de-DE', 1.5],
42
+ ['1,5', 'en-US', null],
43
+ ['1.5', 'en-US', 1.5],
44
+ ['1.5', 'de-DE', null],
45
+
46
+ // Decimals and signs.
47
+ ['1,234.56', 'en-US', 1234.56],
48
+ ['1.234,56', 'de-DE', 1234.56],
49
+ ['1,234.56', 'de-DE', null],
50
+ ['-1,234.56', 'en-US', -1234.56],
51
+ ['+7', 'en-US', 7],
52
+ ['-7', 'en-US', -7],
53
+ ['7-', 'ar-SA', -7],
54
+ ['.5', 'en-US', 0.5],
55
+ ['5.', 'en-US', 5],
56
+ ['-', 'en-US', null],
57
+ ['', 'en-US', null],
58
+ [' ', 'en-US', null],
59
+
60
+ // Spreadsheet cells arrive with their whitespace attached.
61
+ [' 42 ', 'en-US', 42],
62
+ ['\t1,234\n', 'en-US', 1234],
63
+ ['1,234\n5,678', 'en-US', null],
64
+
65
+ // Digit scripts, derived from \p{Nd} rather than enumerated.
66
+ ['١٢٣', 'ar-SA', 123],
67
+ ['۱۲۳', 'fa-IR', 123],
68
+ ['१२३', 'hi-IN', 123],
69
+ ['123', 'ja-JP', 123],
70
+ ['١,٢٣٤', 'en-US', 1234],
71
+ ['٣٫٥', 'ar-SA', 3.5],
72
+
73
+ // Currency decorates the number without changing its magnitude, so the
74
+ // symbol is dropped and the separators still decide. A number written for
75
+ // another locale still refuses.
76
+ ['$1,234.56', 'en-US', 1234.56],
77
+ ['£1,234', 'en-US', 1234],
78
+ ['1.234,56 €', 'de-DE', 1234.56],
79
+ ['1.234,56 €', 'en-US', null],
80
+ ['-$1,234', 'en-US', -1234],
81
+
82
+ // A unit suffix is not dropped: `B` and `k` carry magnitude, so guessing
83
+ // which trailing letters are inert is how a wrong number gets committed.
84
+ ['1,234 GB', 'en-US', null],
85
+ ['72°F', 'en-US', null],
86
+ ['1,234 kg', 'en-US', null],
87
+
88
+ // Accounting negatives.
89
+ ['(1,234)', 'en-US', -1234],
90
+ ['($1,234.50)', 'en-US', -1234.5],
91
+ ['(1,234', 'en-US', null],
92
+
93
+ // Typographic minus signs.
94
+ ['\u22121234', 'en-US', -1234],
95
+ ['\u20131234', 'en-US', -1234],
96
+
97
+ // Exponents, including the shape a spreadsheet exports.
98
+ ['1.23E+09', 'en-US', 1230000000],
99
+ ['1.23e9', 'en-US', 1230000000],
100
+ ['1.5e-3', 'en-US', 0.0015],
101
+ ['1e', 'en-US', null],
102
+
103
+ // Invisible characters Excel and Sheets attach.
104
+ ['\uFEFF1,234', 'en-US', 1234],
105
+ ['1,234\u200B', 'en-US', 1234],
106
+ ['\u200E1,234', 'en-US', 1234],
107
+
108
+ // Junk.
109
+ ['NaN', 'en-US', null],
110
+ ['Infinity', 'en-US', null],
111
+ ['abc', 'en-US', null],
112
+ ['12abc', 'en-US', null],
113
+ ['1/2', 'en-US', null],
114
+ ['1 234 (approx)', 'en-US', null],
115
+ ['--5', 'en-US', null],
116
+ ['1..234', 'en-US', null],
117
+ ];
118
+
119
+ describe('parseLocaleNumber', () => {
120
+ it.each(CORPUS)('parses %j in %s', (input, locale, expected) => {
121
+ expect(parseLocaleNumber(input, locale)).toBe(expected);
122
+ });
123
+
124
+ it('reads back the grouping every locale writes', () => {
125
+ for (const locale of [
126
+ 'en-US',
127
+ 'de-DE',
128
+ 'fr-FR',
129
+ 'de-CH',
130
+ 'en-IN',
131
+ 'ar-SA',
132
+ ]) {
133
+ const text = new Intl.NumberFormat(locale).format(1234234234);
134
+ expect(parseLocaleNumber(text, locale)).toBe(1234234234);
135
+ }
136
+ });
137
+ });
@@ -0,0 +1,346 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file numberParser.ts
5
+ * @input Text a person typed or pasted, plus the resolved BCP 47 locale
6
+ * @output Exports parseLocaleNumber and formatEditableNumber
7
+ * @position Internal to NumberInput; not part of the public surface
8
+ *
9
+ * People paste numbers out of spreadsheets, and a spreadsheet writes them
10
+ * grouped, signed, and decorated. This reads those back. Everything locale
11
+ * specific — the grouping and decimal separators, the group sizes, the digit
12
+ * script — is derived from Intl and Unicode rather than a table, and anything
13
+ * that could mean two different numbers returns null so the field stays
14
+ * visibly invalid instead of committing a guess.
15
+ *
16
+ * SYNC: When modified, update these files to stay in sync:
17
+ * - /packages/core/src/NumberInput/NumberInput.tsx
18
+ * - /packages/core/src/NumberInput/numberParser.test.ts
19
+ */
20
+
21
+ import type {Locale} from '../i18n';
22
+
23
+ interface LocaleNumberSymbols {
24
+ group: string;
25
+ decimal: string;
26
+ /** Digits in the rightmost group — 3 nearly everywhere, 3 in en-IN too. */
27
+ primaryGroupSize: number;
28
+ /** Digits in every group left of it — 2 in en-IN's lakh grouping. */
29
+ secondaryGroupSize: number;
30
+ }
31
+
32
+ const symbolsByLocale = new Map<string, LocaleNumberSymbols>();
33
+
34
+ function getLocaleNumberSymbols(locale: Locale | undefined) {
35
+ const key = locale ?? '';
36
+ let symbols = symbolsByLocale.get(key);
37
+ if (symbols === undefined) {
38
+ let format: Intl.NumberFormat;
39
+ try {
40
+ format = new Intl.NumberFormat(locale);
41
+ } catch {
42
+ format = new Intl.NumberFormat('en');
43
+ }
44
+ const parts = format.formatToParts(12345.6);
45
+ // A probe long enough to expose a second grouping size where one exists.
46
+ const groupSizes = format
47
+ .formatToParts(11111111111)
48
+ .filter(part => part.type === 'integer')
49
+ .map(part => part.value.length);
50
+ const hasGrouping = groupSizes.length > 1;
51
+ symbols = {
52
+ // Normalized so the space-family separators compare equal to the plain
53
+ // space that input text is normalized to.
54
+ group: (parts.find(p => p.type === 'group')?.value ?? ',').normalize(
55
+ 'NFKC',
56
+ ),
57
+ decimal: parts.find(p => p.type === 'decimal')?.value ?? '.',
58
+ primaryGroupSize: hasGrouping ? groupSizes[groupSizes.length - 1] : 3,
59
+ secondaryGroupSize: hasGrouping ? groupSizes[groupSizes.length - 2] : 3,
60
+ };
61
+ symbolsByLocale.set(key, symbols);
62
+ }
63
+ return symbols;
64
+ }
65
+
66
+ // Built at runtime rather than written as literals: Babel's
67
+ // transform-unicode-property-regex rewrites a `\p{...}` regex LITERAL into an
68
+ // enumerated character class, and the copy bundled with Next rejects the
69
+ // General_Category short names, failing the sandbox build. Property escapes are
70
+ // ES2018 and need no transform in any browser this package supports.
71
+ const DECIMAL_DIGIT = new RegExp('\\p{Nd}', 'u');
72
+ const LETTER = new RegExp('\\p{L}', 'u');
73
+ const CURRENCY = new RegExp('\\p{Sc}', 'u');
74
+ // Zero-width joiners, bidi isolates and the BOM Excel prepends.
75
+ const INVISIBLES = /[\u200B-\u200D\u200E\u200F\u061C\u2066-\u2069\uFEFF]/g;
76
+ // Hyphen last: inside the character class this builds, a leading one would
77
+ // open a range.
78
+ const MINUS_SIGNS = '\u2212\u2012\u2013-';
79
+
80
+ /**
81
+ * Value of any Unicode decimal digit. Each digit script lays its ten digits
82
+ * out consecutively, so walking back to the script's zero derives the value
83
+ * for Arabic-Indic, Devanagari, full-width and the rest without shipping a
84
+ * table of them. Returns null in the one shape the walk cannot resolve: two
85
+ * digit blocks adjacent in code space (the mathematical alphanumerics).
86
+ */
87
+ function digitValue(char: string): number | null {
88
+ const codePoint = char.codePointAt(0);
89
+ if (codePoint == null) {
90
+ return null;
91
+ }
92
+ for (let zero = codePoint; codePoint - zero < 10; zero--) {
93
+ if (!DECIMAL_DIGIT.test(String.fromCodePoint(zero - 1))) {
94
+ return codePoint - zero;
95
+ }
96
+ }
97
+ return null;
98
+ }
99
+
100
+ function toAsciiDigits(text: string): string | null {
101
+ let out = '';
102
+ for (const char of text) {
103
+ if (!DECIMAL_DIGIT.test(char)) {
104
+ out += char;
105
+ continue;
106
+ }
107
+ const value = digitValue(char);
108
+ if (value == null) {
109
+ return null;
110
+ }
111
+ out += String(value);
112
+ }
113
+ return out;
114
+ }
115
+
116
+ /**
117
+ * Reduce a digits-and-separators string to a plain machine number under one
118
+ * candidate reading, or null when it is not well formed under that reading.
119
+ * `minGroups` is how many grouping separators the reading has to see before it
120
+ * believes the separator is grouping at all.
121
+ */
122
+ function readUnder(
123
+ core: string,
124
+ group: string,
125
+ decimal: string,
126
+ primaryGroupSize: number,
127
+ secondaryGroupSize: number,
128
+ minGroups: number,
129
+ ): string | null {
130
+ let intText = core;
131
+ let fracText: string | null = null;
132
+
133
+ if (decimal !== '' && core.includes(decimal)) {
134
+ const at = core.indexOf(decimal);
135
+ if (core.includes(decimal, at + decimal.length)) {
136
+ return null;
137
+ }
138
+ intText = core.slice(0, at);
139
+ fracText = core.slice(at + decimal.length);
140
+ if (!/^\d*$/.test(fracText)) {
141
+ return null;
142
+ }
143
+ }
144
+
145
+ let digits: string;
146
+ if (group !== '' && intText.includes(group)) {
147
+ const chunks = intText.split(group);
148
+ if (
149
+ chunks.length - 1 < minGroups ||
150
+ !chunks.every(chunk => /^\d+$/.test(chunk))
151
+ ) {
152
+ return null;
153
+ }
154
+ const first = chunks[0];
155
+ const last = chunks[chunks.length - 1];
156
+ if (last.length !== primaryGroupSize || first.length > secondaryGroupSize) {
157
+ return null;
158
+ }
159
+ for (let i = 1; i < chunks.length - 1; i++) {
160
+ if (chunks[i].length !== secondaryGroupSize) {
161
+ return null;
162
+ }
163
+ }
164
+ digits = chunks.join('');
165
+ } else {
166
+ if (!/^\d*$/.test(intText)) {
167
+ return null;
168
+ }
169
+ digits = intText;
170
+ }
171
+
172
+ if (digits === '' && (fracText == null || fracText === '')) {
173
+ return null;
174
+ }
175
+ return fracText == null ? digits : `${digits}.${fracText}`;
176
+ }
177
+
178
+ /**
179
+ * A separator that no locale uses as a decimal point, so one well-formed group
180
+ * of it is already unambiguous. Everything else needs two before grouping
181
+ * beats the decimal-point reading.
182
+ */
183
+ function isGroupOnlySeparator(separator: string): boolean {
184
+ return /^[\s'\u2019\u00B7]$/.test(separator);
185
+ }
186
+
187
+ function toPlainNumber(
188
+ core: string,
189
+ locale: Locale | undefined,
190
+ ): string | null {
191
+ if (LETTER.test(core)) {
192
+ return null;
193
+ }
194
+
195
+ const {group, decimal, primaryGroupSize, secondaryGroupSize} =
196
+ getLocaleNumberSymbols(locale);
197
+ const inLocale = readUnder(
198
+ core,
199
+ group,
200
+ decimal,
201
+ primaryGroupSize,
202
+ secondaryGroupSize,
203
+ 1,
204
+ );
205
+ if (inLocale != null) {
206
+ return inLocale;
207
+ }
208
+
209
+ // The locale could not read it. A repeated separator with three digits after
210
+ // each occurrence can only be grouping — a decimal point appears once — so
211
+ // that shape reads the same in every locale, which is what lets a
212
+ // `1,234,234,234` pasted out of a spreadsheet land in a de-DE app.
213
+ const separators = [...new Set(core.replace(/\d/g, ''))];
214
+ if (separators.length === 0 || separators.length > 2) {
215
+ return null;
216
+ }
217
+ for (const candidate of separators) {
218
+ const occurrences = core.split(candidate).length - 1;
219
+ const minGroups = isGroupOnlySeparator(candidate) ? 1 : 2;
220
+ if (occurrences < minGroups) {
221
+ continue;
222
+ }
223
+ const other = separators.find(s => s !== candidate) ?? '';
224
+ if (other !== '' && core.split(other).length - 1 !== 1) {
225
+ continue;
226
+ }
227
+ const read = readUnder(core, candidate, other, 3, 3, minGroups);
228
+ if (read != null) {
229
+ return read;
230
+ }
231
+ }
232
+ return null;
233
+ }
234
+
235
+ /**
236
+ * Read a number out of text the way a person in `locale` writes one: their
237
+ * grouping and decimal separators, their group sizes, their digit script, an
238
+ * optional currency symbol, and the shapes a spreadsheet pastes.
239
+ *
240
+ * Returns null rather than a guess. Grouping is validated, so en-US `1,23` —
241
+ * a comma that is neither a decimal point nor a well-formed group — is not
242
+ * silently read as 123, and neither is a number written for another locale.
243
+ *
244
+ * @example
245
+ * ```
246
+ * parseLocaleNumber('1,234,234,234', 'en-US') // 1234234234
247
+ * parseLocaleNumber('1,234,234,234', 'de-DE') // 1234234234
248
+ * parseLocaleNumber('1,5', 'de-DE') // 1.5
249
+ * parseLocaleNumber('1,5', 'en-US') // null
250
+ * ```
251
+ */
252
+ export function parseLocaleNumber(
253
+ text: string,
254
+ locale?: Locale,
255
+ ): number | null {
256
+ const normalized = toAsciiDigits(
257
+ text.normalize('NFKC').replace(INVISIBLES, ''),
258
+ );
259
+ if (normalized == null) {
260
+ return null;
261
+ }
262
+
263
+ let rest = normalized.trim();
264
+ let sign = 1;
265
+
266
+ // Accounting negatives: spreadsheets write -1234 as (1,234).
267
+ const accounting = /^\((.*)\)$/s.exec(rest);
268
+ if (accounting) {
269
+ sign = -1;
270
+ rest = accounting[1].trim();
271
+ }
272
+
273
+ rest = stripCurrency(rest);
274
+
275
+ // The sign lands on either end — RTL locales trail it, and Intl writes
276
+ // U+2212 where a keyboard writes a hyphen.
277
+ const leadingSign = new RegExp(`^([+${MINUS_SIGNS}])\\s*`).exec(rest);
278
+ if (leadingSign) {
279
+ sign = leadingSign[1] === '+' ? sign : -sign;
280
+ rest = rest.slice(leadingSign[0].length);
281
+ } else {
282
+ const trailingSign = new RegExp(`\\s*([+${MINUS_SIGNS}])$`).exec(rest);
283
+ if (trailingSign) {
284
+ sign = trailingSign[1] === '+' ? sign : -sign;
285
+ rest = rest.slice(0, rest.length - trailingSign[0].length);
286
+ }
287
+ }
288
+
289
+ rest = stripCurrency(rest);
290
+
291
+ let exponent = 0;
292
+ const exponentMatch = /\s*[eE]\s*([+-]?\d+)$/.exec(rest);
293
+ if (exponentMatch) {
294
+ exponent = Number(exponentMatch[1]);
295
+ rest = rest.slice(0, rest.length - exponentMatch[0].length);
296
+ }
297
+
298
+ const core = rest.trim();
299
+ if (core === '') {
300
+ return null;
301
+ }
302
+
303
+ const plain = toPlainNumber(core, locale);
304
+ if (plain == null) {
305
+ return null;
306
+ }
307
+
308
+ const magnitude = Number(plain);
309
+ if (!Number.isFinite(magnitude)) {
310
+ return null;
311
+ }
312
+
313
+ const scaled =
314
+ exponent === 0
315
+ ? magnitude
316
+ : // 1.23 * 1e3 is 1229.9999999999998 in binary floating point, and a
317
+ // field that commits that instead of 1230 has not round-tripped.
318
+ Number((magnitude * 10 ** exponent).toPrecision(15));
319
+ if (!Number.isFinite(scaled)) {
320
+ return null;
321
+ }
322
+ const result = sign * scaled;
323
+ return Object.is(result, -0) ? 0 : result;
324
+ }
325
+
326
+ function stripCurrency(text: string): string {
327
+ let out = text.trim();
328
+ if (CURRENCY.test(out.charAt(0))) {
329
+ out = out.slice(1).trim();
330
+ }
331
+ if (CURRENCY.test(out.charAt(out.length - 1))) {
332
+ out = out.slice(0, -1).trim();
333
+ }
334
+ return out;
335
+ }
336
+
337
+ /**
338
+ * The text shown while the field is focused: the plain machine number in the
339
+ * locale's decimal separator, so what a person sees mid-edit is what the
340
+ * parser reads back on blur.
341
+ */
342
+ export function formatEditableNumber(value: number, locale?: Locale): string {
343
+ const {decimal} = getLocaleNumberSymbols(locale);
344
+ const raw = String(value);
345
+ return decimal === '.' ? raw : raw.replace('.', decimal);
346
+ }
@@ -37,7 +37,7 @@ import {
37
37
  import {useLinkComponent} from '../Link/useLinkComponent';
38
38
  import {useListFocus} from '../hooks/useListFocus';
39
39
  import {useIsomorphicLayoutEffect} from '../hooks/useIsomorphicLayoutEffect';
40
- import {mergeProps, mergeRefs} from '../utils';
40
+ import {mergeProps} from '../utils';
41
41
  import type {BaseProps} from '../BaseProps';
42
42
  import {useScrollSpy} from './useScrollSpy';
43
43
  import type {OutlineItem} from './types';
@@ -45,6 +45,7 @@ import {themeProps} from '../utils/themeProps';
45
45
  import {focusOutlineProps} from '../utils/focusOutline.stylex';
46
46
  import {useTranslator} from '../i18n';
47
47
 
48
+ import {useMergedRefs} from '../hooks/useMergedRefs';
48
49
  export type {OutlineItem} from './types';
49
50
 
50
51
  export interface OutlineProps extends BaseProps<HTMLElement> {
@@ -443,7 +444,7 @@ export function Outline({
443
444
  return (
444
445
  <nav
445
446
  {...props}
446
- ref={mergeRefs(rootRef, ref)}
447
+ ref={useMergedRefs(rootRef, ref)}
447
448
  aria-label={label}
448
449
  data-testid={testId}
449
450
  {...mergeProps(
@@ -22,11 +22,12 @@ import {type ReactNode, type ReactElement, Children} from 'react';
22
22
  import type {BaseProps} from '../BaseProps';
23
23
  import type {SpacingStep} from '../utils/types';
24
24
  import * as stylex from '@stylexjs/stylex';
25
- import {mergeProps, mergeRefs} from '../utils';
25
+ import {mergeProps} from '../utils';
26
26
  import {useOverflow} from '../hooks/useOverflow';
27
27
  import {spacingVars} from '../theme/tokens.stylex';
28
28
  import {themeProps} from '../utils/themeProps';
29
29
 
30
+ import {useMergedRefs} from '../hooks/useMergedRefs';
30
31
  const styles = stylex.create({
31
32
  container: {
32
33
  display: 'flex',
@@ -280,7 +281,7 @@ export function OverflowList({
280
281
 
281
282
  {/* Visible container */}
282
283
  <div
283
- ref={mergeRefs(ref, containerRef)}
284
+ ref={useMergedRefs(ref, containerRef)}
284
285
  {...mergeProps(
285
286
  themeProps('overflow-list'),
286
287
  stylex.props(
@@ -17,7 +17,7 @@
17
17
 
18
18
  import type {ReactNode, Ref} from 'react';
19
19
  import * as stylex from '@stylexjs/stylex';
20
- import {mergeProps, mergeRefs} from '../utils';
20
+ import {mergeProps} from '../utils';
21
21
  import {useOverlay} from './useOverlay';
22
22
  import {useIsomorphicLayoutEffect} from '../hooks/useIsomorphicLayoutEffect';
23
23
  import {overlayScope, overlayContainerStyles} from './overlay.markers.stylex';
@@ -30,6 +30,7 @@ import type {
30
30
  OverlayShowOn,
31
31
  } from './OverlayScrim';
32
32
 
33
+ import {useMergedRefs} from '../hooks/useMergedRefs';
33
34
  export interface OverlayProps extends Pick<
34
35
  BaseProps<HTMLDivElement>,
35
36
  'xstyle' | 'className' | 'style'
@@ -113,7 +114,7 @@ export function Overlay({
113
114
 
114
115
  return (
115
116
  <div
116
- ref={mergeRefs(ref, overlay.containerRef)}
117
+ ref={useMergedRefs(ref, overlay.containerRef)}
117
118
  {...mergeProps(
118
119
  themeProps('overlay'),
119
120
  stylex.props(overlayScope, overlayContainerStyles.root, xstyle),
@@ -19,6 +19,7 @@ import React, {useCallback, useEffect, useRef, type ReactNode} from 'react';
19
19
  import * as stylex from '@stylexjs/stylex';
20
20
  import {useLayer, type ContextRenderProps} from '../Layer/useLayer';
21
21
  import {useFocusTrap} from '../hooks/useFocusTrap';
22
+ import {LayerDepthProvider} from '../Layer/LayerDepthContext';
22
23
  import type {StyleXStyles} from '@stylexjs/stylex';
23
24
  import {
24
25
  colorVars,
@@ -436,34 +437,36 @@ export function usePopover(options: UsePopoverOptions = {}): UsePopoverReturn {
436
437
  : surfaceProps.className;
437
438
 
438
439
  return layer.render(
439
- <div
440
- ref={contentRef}
441
- role={role === 'dialog' ? 'dialog' : undefined}
442
- aria-modal={role === 'dialog' && isModal ? true : undefined}
443
- aria-label={role === 'dialog' ? dialogLabel : undefined}
444
- {...mergeProps(
445
- {...surfaceProps, className: surfaceClassName},
446
- stylex.props(
447
- styles.contentWrapper,
448
- hasSurface && styles.surface,
449
- xstyle,
450
- ),
451
- )}>
452
- {children}
453
- {hasCloseButton && (
454
- <div
455
- {...stylex.props(
456
- styles.closeButtonWrapper,
457
- rtlStyles.centerInline('100%'),
458
- )}>
459
- <Button
460
- variant="secondary"
461
- label={closeButtonLabel}
462
- onClick={layer.hide}
463
- />
464
- </div>
465
- )}
466
- </div>,
440
+ <LayerDepthProvider>
441
+ <div
442
+ ref={contentRef}
443
+ role={role === 'dialog' ? 'dialog' : undefined}
444
+ aria-modal={role === 'dialog' && isModal ? true : undefined}
445
+ aria-label={role === 'dialog' ? dialogLabel : undefined}
446
+ {...mergeProps(
447
+ {...surfaceProps, className: surfaceClassName},
448
+ stylex.props(
449
+ styles.contentWrapper,
450
+ hasSurface && styles.surface,
451
+ xstyle,
452
+ ),
453
+ )}>
454
+ {children}
455
+ {hasCloseButton && (
456
+ <div
457
+ {...stylex.props(
458
+ styles.closeButtonWrapper,
459
+ rtlStyles.centerInline('100%'),
460
+ )}>
461
+ <Button
462
+ variant="secondary"
463
+ label={closeButtonLabel}
464
+ onClick={layer.hide}
465
+ />
466
+ </div>
467
+ )}
468
+ </div>
469
+ </LayerDepthProvider>,
467
470
  {...props, xstyle: props?.xstyle},
468
471
  );
469
472
  },