@astryxdesign/core 0.5.0 → 0.5.1-canary.f64186a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (597) hide show
  1. package/CHANGELOG.md +222 -0
  2. package/dist/AlertDialog/AlertDialog.d.ts +1 -1
  3. package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
  4. package/dist/AlertDialog/AlertDialog.js +45 -20
  5. package/dist/AspectRatio/AspectRatio.d.ts +6 -6
  6. package/dist/Avatar/Avatar.d.ts +25 -1
  7. package/dist/Avatar/Avatar.d.ts.map +1 -1
  8. package/dist/Avatar/Avatar.js +43 -9
  9. package/dist/Avatar/index.d.ts +2 -2
  10. package/dist/Avatar/index.d.ts.map +1 -1
  11. package/dist/Avatar/index.js +1 -1
  12. package/dist/AvatarGroup/AvatarGroup.d.ts +9 -2
  13. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  14. package/dist/AvatarGroup/AvatarGroup.js +5 -2
  15. package/dist/AvatarGroup/AvatarGroupContext.d.ts +2 -1
  16. package/dist/AvatarGroup/AvatarGroupContext.d.ts.map +1 -1
  17. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  18. package/dist/AvatarGroup/AvatarGroupOverflow.js +11 -7
  19. package/dist/Badge/Badge.d.ts.map +1 -1
  20. package/dist/Badge/Badge.js +26 -2
  21. package/dist/Banner/Banner.d.ts +10 -1
  22. package/dist/Banner/Banner.d.ts.map +1 -1
  23. package/dist/Banner/Banner.js +11 -2
  24. package/dist/Button/Button.d.ts.map +1 -1
  25. package/dist/Button/Button.js +8 -7
  26. package/dist/Calendar/Calendar.d.ts +4 -2
  27. package/dist/Calendar/Calendar.d.ts.map +1 -1
  28. package/dist/Calendar/Calendar.js +15 -21
  29. package/dist/Calendar/hooks/useCalendarDays.js +4 -6
  30. package/dist/Calendar/hooks/useCalendarNavigation.js +4 -6
  31. package/dist/Calendar/styles.d.ts +5 -20
  32. package/dist/Calendar/styles.d.ts.map +1 -1
  33. package/dist/Calendar/styles.js +15 -17
  34. package/dist/Card/Card.d.ts +12 -12
  35. package/dist/Card/Card.d.ts.map +1 -1
  36. package/dist/Card/Card.js +17 -9
  37. package/dist/Card/index.d.ts +35 -1
  38. package/dist/Card/index.d.ts.map +1 -1
  39. package/dist/Card/index.js +21 -1
  40. package/dist/Carousel/Carousel.d.ts.map +1 -1
  41. package/dist/Carousel/Carousel.js +108 -7
  42. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  43. package/dist/CheckboxInput/CheckboxInput.js +7 -1
  44. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  45. package/dist/CodeBlock/CodeBlock.js +15 -4
  46. package/dist/CodeBlock/highlightRanges.js +1 -1
  47. package/dist/CodeBlock/highlightStyles.js +13 -13
  48. package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
  49. package/dist/CommandPalette/CommandPaletteItem.js +2 -7
  50. package/dist/ComplexSelector/ComplexSelector.d.ts +10 -2
  51. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  52. package/dist/ComplexSelector/ComplexSelector.js +14 -7
  53. package/dist/DateInput/DateInput.d.ts +43 -0
  54. package/dist/DateInput/DateInput.d.ts.map +1 -1
  55. package/dist/DateInput/DateInput.js +22 -5
  56. package/dist/DateInput/MonthScroller.d.ts.map +1 -1
  57. package/dist/DateInput/MonthScroller.js +5 -3
  58. package/dist/DateInput/MonthYearWheels.d.ts.map +1 -1
  59. package/dist/DateInput/MonthYearWheels.js +6 -4
  60. package/dist/DateInput/NativeDateField.d.ts +10 -0
  61. package/dist/DateInput/NativeDateField.d.ts.map +1 -0
  62. package/dist/DateInput/NativeDateField.js +494 -0
  63. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  64. package/dist/DateInput/TouchDateField.js +52 -25
  65. package/dist/DateInput/Wheel.d.ts.map +1 -1
  66. package/dist/DateInput/Wheel.js +1 -0
  67. package/dist/DateInput/index.d.ts +1 -1
  68. package/dist/DateInput/index.d.ts.map +1 -1
  69. package/dist/DateInput/nativeDateSegments.d.ts +22 -0
  70. package/dist/DateInput/nativeDateSegments.d.ts.map +1 -0
  71. package/dist/DateInput/nativeDateSegments.js +111 -0
  72. package/dist/DateRangeInput/DateRangeInput.d.ts +4 -2
  73. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  74. package/dist/DateRangeInput/DateRangeInput.js +3 -5
  75. package/dist/DateTimeInput/DateTimeInput.d.ts +23 -24
  76. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  77. package/dist/DateTimeInput/DateTimeInput.js +35 -10
  78. package/dist/DateTimeInput/TouchDateTimeField.d.ts +6 -0
  79. package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -0
  80. package/dist/DateTimeInput/TouchDateTimeField.js +1021 -0
  81. package/dist/Dialog/Dialog.d.ts +16 -2
  82. package/dist/Dialog/Dialog.d.ts.map +1 -1
  83. package/dist/Dialog/Dialog.js +28 -7
  84. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  85. package/dist/DropdownMenu/DropdownMenu.js +4 -13
  86. package/dist/Field/FieldLabel.d.ts.map +1 -1
  87. package/dist/Field/FieldLabel.js +9 -1
  88. package/dist/Field/InputClearButton.d.ts +9 -3
  89. package/dist/Field/InputClearButton.d.ts.map +1 -1
  90. package/dist/Field/InputClearButton.js +14 -3
  91. package/dist/Heading/Heading.d.ts.map +1 -1
  92. package/dist/Heading/Heading.js +0 -1
  93. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  94. package/dist/HoverCard/HoverCard.js +104 -3
  95. package/dist/HoverCard/useHoverCard.d.ts +14 -2
  96. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  97. package/dist/HoverCard/useHoverCard.js +7 -1
  98. package/dist/Icon/Icon.d.ts +4 -2
  99. package/dist/Icon/Icon.d.ts.map +1 -1
  100. package/dist/Icon/defaultIcons.d.ts +3 -2
  101. package/dist/Icon/defaultIcons.d.ts.map +1 -1
  102. package/dist/Icon/defaultIcons.js +7 -0
  103. package/dist/Icon/globalIconRegistry.d.ts +13 -0
  104. package/dist/Icon/globalIconRegistry.d.ts.map +1 -1
  105. package/dist/Icon/globalIconRegistry.js +34 -6
  106. package/dist/Icon/index.d.ts +1 -1
  107. package/dist/Icon/index.d.ts.map +1 -1
  108. package/dist/Icon/useIcon.d.ts +5 -2
  109. package/dist/Icon/useIcon.d.ts.map +1 -1
  110. package/dist/Icon/useIcon.js +3 -0
  111. package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -1
  112. package/dist/Indicator/CheckboxIndicator.js +6 -2
  113. package/dist/Item/Item.d.ts.map +1 -1
  114. package/dist/Item/Item.js +2 -2
  115. package/dist/Kbd/Kbd.d.ts.map +1 -1
  116. package/dist/Kbd/Kbd.js +2 -26
  117. package/dist/Layer/gestureCounter.d.ts +8 -0
  118. package/dist/Layer/gestureCounter.d.ts.map +1 -0
  119. package/dist/Layer/gestureCounter.js +53 -0
  120. package/dist/Layer/useLayer.d.ts +23 -13
  121. package/dist/Layer/useLayer.d.ts.map +1 -1
  122. package/dist/Layer/useLayer.js +146 -24
  123. package/dist/List/List.d.ts +1 -1
  124. package/dist/List/List.d.ts.map +1 -1
  125. package/dist/List/List.js +15 -4
  126. package/dist/Markdown/Markdown.d.ts +1 -1
  127. package/dist/Markdown/Markdown.d.ts.map +1 -1
  128. package/dist/Markdown/Markdown.js +20 -7
  129. package/dist/Markdown/parser.d.ts.map +1 -1
  130. package/dist/Markdown/parser.js +5 -3
  131. package/dist/MetadataList/MetadataListItem.d.ts +1 -1
  132. package/dist/MetadataList/MetadataListItem.d.ts.map +1 -1
  133. package/dist/MetadataList/MetadataListItem.js +4 -1
  134. package/dist/MultiSelector/MultiSelector.d.ts +18 -1
  135. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  136. package/dist/MultiSelector/MultiSelector.js +58 -11
  137. package/dist/MultiSelector/hooks.d.ts +7 -1
  138. package/dist/MultiSelector/hooks.d.ts.map +1 -1
  139. package/dist/MultiSelector/hooks.js +3 -2
  140. package/dist/NavIcon/NavIcon.d.ts.map +1 -1
  141. package/dist/NavIcon/NavIcon.js +5 -1
  142. package/dist/NavItem/navItemStyles.stylex.d.ts +0 -8
  143. package/dist/NavItem/navItemStyles.stylex.d.ts.map +1 -1
  144. package/dist/NavItem/navItemStyles.stylex.js +0 -2
  145. package/dist/NavMenu/NavHeadingMenu.d.ts +1 -1
  146. package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
  147. package/dist/NavMenu/NavHeadingMenu.js +7 -4
  148. package/dist/NumberInput/NumberInput.d.ts +6 -1
  149. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  150. package/dist/NumberInput/NumberInput.js +95 -126
  151. package/dist/NumberInput/numberInputCommit.d.ts +34 -0
  152. package/dist/NumberInput/numberInputCommit.d.ts.map +1 -0
  153. package/dist/NumberInput/numberInputCommit.js +71 -0
  154. package/dist/NumberInput/numberParser.d.ts +64 -0
  155. package/dist/NumberInput/numberParser.d.ts.map +1 -0
  156. package/dist/NumberInput/numberParser.js +350 -0
  157. package/dist/Outline/Outline.d.ts.map +1 -1
  158. package/dist/Outline/Outline.js +2 -3
  159. package/dist/OverflowList/OverflowList.d.ts +41 -1
  160. package/dist/OverflowList/OverflowList.d.ts.map +1 -1
  161. package/dist/OverflowList/OverflowList.js +43 -2
  162. package/dist/Popover/Popover.d.ts.map +1 -1
  163. package/dist/Popover/Popover.js +8 -14
  164. package/dist/Popover/usePopover.d.ts +15 -41
  165. package/dist/Popover/usePopover.d.ts.map +1 -1
  166. package/dist/Popover/usePopover.js +26 -7
  167. package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
  168. package/dist/PowerSearch/PowerSearchValueEditor.js +91 -18
  169. package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
  170. package/dist/PowerSearch/formatFilterValue.js +4 -2
  171. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  172. package/dist/ProgressBar/ProgressBar.js +18 -5
  173. package/dist/Resizable/useResizable.d.ts +19 -1
  174. package/dist/Resizable/useResizable.d.ts.map +1 -1
  175. package/dist/Resizable/useResizable.js +104 -38
  176. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  177. package/dist/SelectableCard/SelectableCard.js +9 -0
  178. package/dist/Selector/Selector.d.ts +18 -1
  179. package/dist/Selector/Selector.d.ts.map +1 -1
  180. package/dist/Selector/Selector.js +92 -21
  181. package/dist/Selector/hooks.d.ts +7 -1
  182. package/dist/Selector/hooks.d.ts.map +1 -1
  183. package/dist/Selector/hooks.js +3 -2
  184. package/dist/SideNav/SideNav.d.ts +6 -1
  185. package/dist/SideNav/SideNav.d.ts.map +1 -1
  186. package/dist/SideNav/SideNav.js +57 -27
  187. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  188. package/dist/SideNav/SideNavHeading.js +5 -4
  189. package/dist/SideNav/SideNavItem.d.ts +29 -4
  190. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  191. package/dist/SideNav/SideNavItem.js +75 -20
  192. package/dist/Slider/Slider.d.ts.map +1 -1
  193. package/dist/Slider/Slider.js +34 -2
  194. package/dist/Spinner/Spinner.d.ts +3 -1
  195. package/dist/Spinner/Spinner.d.ts.map +1 -1
  196. package/dist/Spinner/Spinner.js +199 -20
  197. package/dist/StatusDot/StatusDot.d.ts.map +1 -1
  198. package/dist/StatusDot/StatusDot.js +6 -1
  199. package/dist/Stepper/Step.d.ts.map +1 -1
  200. package/dist/Stepper/Step.js +7 -6
  201. package/dist/Switch/Switch.d.ts.map +1 -1
  202. package/dist/Switch/Switch.js +5 -1
  203. package/dist/Table/BaseTable.d.ts.map +1 -1
  204. package/dist/Table/BaseTable.js +6 -1
  205. package/dist/Table/Table.d.ts.map +1 -1
  206. package/dist/Table/Table.js +3 -6
  207. package/dist/Table/plugins/filtering/useTableFiltering.d.ts.map +1 -1
  208. package/dist/Table/plugins/filtering/useTableFiltering.js +73 -4
  209. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts +26 -0
  210. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  211. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +34 -3
  212. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  213. package/dist/Table/plugins/selection/useTableSelection.js +25 -1
  214. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
  215. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +3 -4
  216. package/dist/Text/Text.d.ts.map +1 -1
  217. package/dist/Text/Text.js +0 -1
  218. package/dist/TextArea/TextArea.d.ts.map +1 -1
  219. package/dist/TextArea/TextArea.js +13 -8
  220. package/dist/Timestamp/Timestamp.d.ts +1 -1
  221. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  222. package/dist/Timestamp/Timestamp.js +10 -18
  223. package/dist/Timestamp/formatInstant.d.ts.map +1 -1
  224. package/dist/Timestamp/formatInstant.js +10 -5
  225. package/dist/Toast/Toast.d.ts +17 -2
  226. package/dist/Toast/Toast.d.ts.map +1 -1
  227. package/dist/Toast/Toast.js +77 -11
  228. package/dist/Toast/ToastViewport.d.ts +1 -0
  229. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  230. package/dist/Toast/ToastViewport.js +76 -21
  231. package/dist/Toast/index.d.ts +1 -1
  232. package/dist/Toast/index.d.ts.map +1 -1
  233. package/dist/Toast/types.d.ts +38 -0
  234. package/dist/Toast/types.d.ts.map +1 -1
  235. package/dist/Toast/useToastGesture.d.ts +26 -0
  236. package/dist/Toast/useToastGesture.d.ts.map +1 -0
  237. package/dist/Toast/useToastGesture.js +223 -0
  238. package/dist/Token/Token.d.ts +1 -1
  239. package/dist/Token/Token.d.ts.map +1 -1
  240. package/dist/Token/Token.js +23 -12
  241. package/dist/Token/TokenLink.d.ts +1 -1
  242. package/dist/Token/TokenLink.d.ts.map +1 -1
  243. package/dist/Token/TokenLink.js +5 -2
  244. package/dist/Tokenizer/Tokenizer.d.ts +12 -1
  245. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  246. package/dist/Tokenizer/Tokenizer.js +31 -21
  247. package/dist/TopNav/TopNavHeading.js +2 -2
  248. package/dist/TopNav/TopNavItem.d.ts.map +1 -1
  249. package/dist/TopNav/TopNavItem.js +3 -3
  250. package/dist/TopNav/TopNavMegaMenu.d.ts +1 -1
  251. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  252. package/dist/TopNav/TopNavMegaMenu.js +30 -9
  253. package/dist/TopNav/TopNavMegaMenuItem.d.ts.map +1 -1
  254. package/dist/TopNav/TopNavMegaMenuItem.js +3 -3
  255. package/dist/TopNav/TopNavMenu.d.ts +1 -1
  256. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  257. package/dist/TopNav/TopNavMenu.js +21 -6
  258. package/dist/TreeList/TreeList.d.ts +1 -1
  259. package/dist/TreeList/TreeList.d.ts.map +1 -1
  260. package/dist/TreeList/TreeList.js +7 -2
  261. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  262. package/dist/TreeList/TreeListItem.js +2 -2
  263. package/dist/Typeahead/BaseTypeahead.d.ts +33 -0
  264. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  265. package/dist/Typeahead/BaseTypeahead.js +51 -8
  266. package/dist/Typeahead/Typeahead.d.ts +8 -1
  267. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  268. package/dist/Typeahead/Typeahead.js +2 -0
  269. package/dist/Typeahead/TypeaheadItem.d.ts +1 -1
  270. package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
  271. package/dist/Typeahead/TypeaheadItem.js +7 -2
  272. package/dist/astryx.css +87 -22
  273. package/dist/hooks/useHotkeys.d.ts.map +1 -1
  274. package/dist/hooks/useHotkeys.js +3 -25
  275. package/dist/hooks/useOverflow.d.ts.map +1 -1
  276. package/dist/hooks/useOverflow.js +14 -4
  277. package/dist/index.d.ts +1 -1
  278. package/dist/index.d.ts.map +1 -1
  279. package/dist/theme/Theme.d.ts.map +1 -1
  280. package/dist/theme/Theme.js +46 -10
  281. package/dist/theme/defineTheme.d.ts +9 -3
  282. package/dist/theme/defineTheme.d.ts.map +1 -1
  283. package/dist/theme/defineTheme.js +5 -0
  284. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  285. package/dist/theme/derivedVarRegistry.js +24 -4
  286. package/dist/theme/generateThemeRules.d.ts +21 -0
  287. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  288. package/dist/theme/generateThemeRules.js +26 -0
  289. package/dist/theme/syntax/tokens.d.ts +1 -1
  290. package/dist/theme/syntax/tokens.d.ts.map +1 -1
  291. package/dist/theme/syntax/tokens.js +5 -2
  292. package/dist/theme/useTheme.d.ts.map +1 -1
  293. package/dist/theme/useTheme.js +6 -7
  294. package/dist/utils/dateParser.d.ts +5 -8
  295. package/dist/utils/dateParser.d.ts.map +1 -1
  296. package/dist/utils/dateParser.js +10 -11
  297. package/dist/utils/focusOutline.stylex.d.ts +25 -0
  298. package/dist/utils/focusOutline.stylex.d.ts.map +1 -1
  299. package/dist/utils/focusOutline.stylex.js +15 -0
  300. package/dist/utils/interactionOverlay.stylex.d.ts +26 -0
  301. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -0
  302. package/dist/utils/interactionOverlay.stylex.js +42 -0
  303. package/dist/utils/isApplePlatform.d.ts +18 -0
  304. package/dist/utils/isApplePlatform.d.ts.map +1 -0
  305. package/dist/utils/isApplePlatform.js +37 -0
  306. package/dist/utils/plainDate.d.ts +11 -0
  307. package/dist/utils/plainDate.d.ts.map +1 -1
  308. package/dist/utils/plainDate.js +20 -4
  309. package/locales/af-ZA.json +7 -7
  310. package/locales/ar-SA.json +7 -7
  311. package/locales/ca-ES.json +6 -6
  312. package/locales/cs-CZ.json +7 -7
  313. package/locales/da-DK.json +7 -7
  314. package/locales/de-DE.json +7 -7
  315. package/locales/el-GR.json +7 -7
  316. package/locales/en.json +178 -6
  317. package/locales/es-ES.json +6 -6
  318. package/locales/fi-FI.json +7 -7
  319. package/locales/fr-FR.json +7 -7
  320. package/locales/he-IL.json +7 -7
  321. package/locales/hu-HU.json +7 -7
  322. package/locales/it-IT.json +7 -7
  323. package/locales/ja-JP.json +7 -7
  324. package/locales/ko-KR.json +7 -7
  325. package/locales/nl-NL.json +7 -7
  326. package/locales/no-NO.json +7 -7
  327. package/locales/pl-PL.json +7 -7
  328. package/locales/pseudo.json +130 -1
  329. package/locales/pt-BR.json +7 -7
  330. package/locales/pt-PT.json +7 -7
  331. package/locales/ro-RO.json +7 -7
  332. package/locales/ru-RU.json +7 -7
  333. package/locales/sr-SP.json +7 -7
  334. package/locales/sv-SE.json +7 -7
  335. package/locales/tr-TR.json +7 -7
  336. package/locales/uk-UA.json +7 -7
  337. package/locales/vi-VN.json +7 -7
  338. package/locales/zh-CN.json +7 -7
  339. package/locales/zh-TW.json +7 -7
  340. package/package.json +4 -5
  341. package/src/AlertDialog/AlertDialog.doc.mjs +114 -30
  342. package/src/AlertDialog/AlertDialog.test.tsx +211 -2
  343. package/src/AlertDialog/AlertDialog.tsx +62 -20
  344. package/src/AspectRatio/AspectRatio.doc.mjs +3 -3
  345. package/src/AspectRatio/AspectRatio.tsx +6 -6
  346. package/src/Avatar/Avatar.doc.mjs +12 -2
  347. package/src/Avatar/Avatar.test.tsx +80 -0
  348. package/src/Avatar/Avatar.tsx +64 -14
  349. package/src/Avatar/index.ts +2 -2
  350. package/src/AvatarGroup/AvatarGroup.doc.mjs +8 -2
  351. package/src/AvatarGroup/AvatarGroup.test.tsx +24 -0
  352. package/src/AvatarGroup/AvatarGroup.tsx +12 -4
  353. package/src/AvatarGroup/AvatarGroupContext.ts +5 -3
  354. package/src/AvatarGroup/AvatarGroupOverflow.tsx +12 -12
  355. package/src/Badge/Badge.doc.mjs +3 -2
  356. package/src/Badge/Badge.test.tsx +32 -3
  357. package/src/Badge/Badge.tsx +42 -1
  358. package/src/Banner/Banner.doc.mjs +9 -0
  359. package/src/Banner/Banner.test.tsx +76 -11
  360. package/src/Banner/Banner.tsx +21 -2
  361. package/src/Button/Button.doc.mjs +2 -1
  362. package/src/Button/Button.test.tsx +19 -4
  363. package/src/Button/Button.tsx +9 -29
  364. package/src/ButtonGroup/ButtonGroup.doc.mjs +2 -2
  365. package/src/ButtonGroup/ButtonGroup.test.tsx +13 -0
  366. package/src/Calendar/Calendar.doc.mjs +3 -3
  367. package/src/Calendar/Calendar.test.tsx +112 -0
  368. package/src/Calendar/Calendar.tsx +18 -16
  369. package/src/Calendar/hooks/useCalendarDays.ts +4 -4
  370. package/src/Calendar/hooks/useCalendarNavigation.ts +4 -4
  371. package/src/Calendar/styles.ts +48 -42
  372. package/src/Card/Card.doc.mjs +10 -7
  373. package/src/Card/Card.test.tsx +113 -19
  374. package/src/Card/Card.tsx +67 -89
  375. package/src/Card/index.ts +36 -1
  376. package/src/Carousel/Carousel.doc.mjs +3 -0
  377. package/src/Carousel/Carousel.test.tsx +360 -0
  378. package/src/Carousel/Carousel.tsx +116 -15
  379. package/src/CheckboxInput/CheckboxInput.doc.mjs +2 -0
  380. package/src/CheckboxInput/CheckboxInput.test.tsx +15 -0
  381. package/src/CheckboxInput/CheckboxInput.tsx +5 -0
  382. package/src/CodeBlock/CodeBlock.doc.mjs +10 -4
  383. package/src/CodeBlock/CodeBlock.test.tsx +37 -0
  384. package/src/CodeBlock/CodeBlock.tsx +20 -4
  385. package/src/CodeBlock/highlightRanges.ts +1 -1
  386. package/src/CodeBlock/highlightStyles.ts +13 -13
  387. package/src/CommandPalette/CommandPaletteItem.tsx +2 -12
  388. package/src/ComplexSelector/ComplexSelector.doc.mjs +7 -0
  389. package/src/ComplexSelector/ComplexSelector.test.tsx +183 -0
  390. package/src/ComplexSelector/ComplexSelector.tsx +22 -12
  391. package/src/DateInput/DateInput.doc.mjs +16 -0
  392. package/src/DateInput/DateInput.test.tsx +9 -4
  393. package/src/DateInput/DateInput.tsx +54 -3
  394. package/src/DateInput/DateInputTouch.test.tsx +146 -32
  395. package/src/DateInput/MonthScroller.tsx +5 -1
  396. package/src/DateInput/MonthYearWheels.tsx +7 -4
  397. package/src/DateInput/NativeDateField.test.tsx +635 -0
  398. package/src/DateInput/NativeDateField.tsx +641 -0
  399. package/src/DateInput/TouchDateField.tsx +83 -33
  400. package/src/DateInput/Wheel.tsx +1 -0
  401. package/src/DateInput/index.ts +1 -0
  402. package/src/DateInput/nativeDateSegments.ts +127 -0
  403. package/src/DateRangeInput/DateRangeInput.doc.mjs +2 -2
  404. package/src/DateRangeInput/DateRangeInput.test.tsx +46 -0
  405. package/src/DateRangeInput/DateRangeInput.tsx +8 -13
  406. package/src/DateTimeInput/DateTimeInput.doc.mjs +38 -21
  407. package/src/DateTimeInput/DateTimeInput.test.tsx +76 -0
  408. package/src/DateTimeInput/DateTimeInput.tsx +54 -20
  409. package/src/DateTimeInput/DateTimeInputTouch.test.tsx +980 -0
  410. package/src/DateTimeInput/TouchDateTimeField.tsx +1437 -0
  411. package/src/Dialog/Dialog.test.tsx +185 -18
  412. package/src/Dialog/Dialog.tsx +35 -11
  413. package/src/DropdownMenu/DropdownMenu.test.tsx +44 -10
  414. package/src/DropdownMenu/DropdownMenu.tsx +4 -13
  415. package/src/Field/FieldLabel.test.tsx +29 -0
  416. package/src/Field/FieldLabel.tsx +7 -0
  417. package/src/Field/InputClearButton.test.tsx +15 -1
  418. package/src/Field/InputClearButton.tsx +28 -4
  419. package/src/Heading/Heading.tsx +0 -1
  420. package/src/HoverCard/HoverCard.doc.mjs +8 -2
  421. package/src/HoverCard/HoverCard.test.tsx +154 -4
  422. package/src/HoverCard/HoverCard.tsx +137 -3
  423. package/src/HoverCard/useHoverCard.tsx +23 -3
  424. package/src/Icon/Icon.test.tsx +55 -1
  425. package/src/Icon/Icon.tsx +5 -3
  426. package/src/Icon/defaultIcons.tsx +11 -2
  427. package/src/Icon/globalIconRegistry.test.tsx +16 -3
  428. package/src/Icon/globalIconRegistry.tsx +37 -6
  429. package/src/Icon/index.ts +1 -0
  430. package/src/Icon/useIcon.ts +9 -2
  431. package/src/Indicator/CheckboxIndicator.tsx +14 -8
  432. package/src/Indicator/Indicator.doc.mjs +2 -0
  433. package/src/Item/Item.tsx +2 -7
  434. package/src/Kbd/Kbd.test.tsx +0 -17
  435. package/src/Kbd/Kbd.tsx +2 -26
  436. package/src/Layer/gestureCounter.ts +57 -0
  437. package/src/Layer/useLayer.test.tsx +368 -16
  438. package/src/Layer/useLayer.tsx +208 -35
  439. package/src/Layout/__tests__/edgeCompensation.test.tsx +1 -1
  440. package/src/List/List.test.tsx +38 -0
  441. package/src/List/List.tsx +8 -1
  442. package/src/Markdown/Markdown.test.tsx +37 -0
  443. package/src/Markdown/Markdown.tsx +16 -5
  444. package/src/Markdown/parser.test.ts +33 -0
  445. package/src/Markdown/parser.ts +9 -3
  446. package/src/MetadataList/MetadataList.test.tsx +75 -2
  447. package/src/MetadataList/MetadataListItem.tsx +5 -2
  448. package/src/MultiSelector/MultiSelector.doc.mjs +22 -1
  449. package/src/MultiSelector/MultiSelector.test.tsx +205 -0
  450. package/src/MultiSelector/MultiSelector.tsx +103 -16
  451. package/src/MultiSelector/hooks.ts +9 -2
  452. package/src/NavIcon/NavIcon.doc.mjs +8 -2
  453. package/src/NavIcon/NavIcon.test.tsx +9 -0
  454. package/src/NavIcon/NavIcon.tsx +5 -1
  455. package/src/NavItem/navItemStyles.stylex.ts +0 -8
  456. package/src/NavMenu/NavHeadingMenu.test.tsx +30 -0
  457. package/src/NavMenu/NavHeadingMenu.tsx +7 -4
  458. package/src/NumberInput/NumberInput.doc.mjs +26 -7
  459. package/src/NumberInput/NumberInput.test.tsx +563 -8
  460. package/src/NumberInput/NumberInput.tsx +77 -131
  461. package/src/NumberInput/numberInputCommit.test.ts +72 -0
  462. package/src/NumberInput/numberInputCommit.ts +103 -0
  463. package/src/NumberInput/numberParser.docblock.test.ts +234 -0
  464. package/src/NumberInput/numberParser.test.ts +222 -0
  465. package/src/NumberInput/numberParser.ts +403 -0
  466. package/src/Outline/Outline.tsx +2 -4
  467. package/src/OverflowList/OverflowList.doc.mjs +102 -21
  468. package/src/OverflowList/OverflowList.test.tsx +550 -4
  469. package/src/OverflowList/OverflowList.tsx +100 -2
  470. package/src/Pagination/Pagination.test.tsx +3 -2
  471. package/src/Popover/Popover.doc.mjs +2 -2
  472. package/src/Popover/Popover.test.tsx +38 -0
  473. package/src/Popover/Popover.tsx +28 -66
  474. package/src/Popover/usePopover.tsx +44 -5
  475. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +87 -0
  476. package/src/PowerSearch/PowerSearchValueEditor.test.tsx +64 -0
  477. package/src/PowerSearch/PowerSearchValueEditor.tsx +109 -10
  478. package/src/PowerSearch/formatFilterValue.test.ts +16 -1
  479. package/src/PowerSearch/formatFilterValue.ts +2 -0
  480. package/src/ProgressBar/ProgressBar.doc.mjs +42 -6
  481. package/src/ProgressBar/ProgressBar.test.tsx +24 -0
  482. package/src/ProgressBar/ProgressBar.tsx +28 -8
  483. package/src/Resizable/Resizable.doc.mjs +2 -2
  484. package/src/Resizable/useResizable.doc.mjs +21 -2
  485. package/src/Resizable/useResizable.test.ts +421 -0
  486. package/src/Resizable/useResizable.ts +133 -48
  487. package/src/SelectableCard/SelectableCard.doc.mjs +3 -0
  488. package/src/SelectableCard/SelectableCard.tsx +16 -0
  489. package/src/Selector/Selector.doc.mjs +14 -0
  490. package/src/Selector/Selector.source-build.test.mjs +65 -0
  491. package/src/Selector/Selector.test.tsx +301 -0
  492. package/src/Selector/Selector.tsx +145 -32
  493. package/src/Selector/hooks.ts +17 -2
  494. package/src/SideNav/SideNav.doc.mjs +2 -2
  495. package/src/SideNav/SideNav.test.tsx +1069 -6
  496. package/src/SideNav/SideNav.tsx +109 -38
  497. package/src/SideNav/SideNavHeading.tsx +5 -2
  498. package/src/SideNav/SideNavItem.doc.mjs +24 -3
  499. package/src/SideNav/SideNavItem.tsx +134 -44
  500. package/src/Slider/Slider.test.tsx +106 -1
  501. package/src/Slider/Slider.tsx +52 -1
  502. package/src/Spinner/Spinner.doc.mjs +17 -5
  503. package/src/Spinner/Spinner.test.tsx +164 -0
  504. package/src/Spinner/Spinner.tsx +252 -22
  505. package/src/StatusDot/StatusDot.doc.mjs +8 -2
  506. package/src/StatusDot/StatusDot.test.tsx +9 -0
  507. package/src/StatusDot/StatusDot.tsx +7 -1
  508. package/src/Stepper/Step.doc.mjs +1 -1
  509. package/src/Stepper/Step.tsx +7 -14
  510. package/src/Switch/Switch.doc.mjs +2 -0
  511. package/src/Switch/Switch.test.tsx +10 -0
  512. package/src/Switch/Switch.tsx +3 -0
  513. package/src/Table/BaseTable.tsx +6 -1
  514. package/src/Table/Table.doc.mjs +5 -3
  515. package/src/Table/Table.tsx +3 -8
  516. package/src/Table/TableBody.doc.mjs +2 -2
  517. package/src/Table/TableFooter.doc.mjs +1 -1
  518. package/src/Table/TableHeader.doc.mjs +1 -1
  519. package/src/Table/plugins/filtering/useTableFiltering.test.tsx +44 -6
  520. package/src/Table/plugins/filtering/useTableFiltering.tsx +100 -4
  521. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +50 -4
  522. package/src/Table/plugins/selection/useTableSelection.test.tsx +62 -0
  523. package/src/Table/plugins/selection/useTableSelection.tsx +25 -2
  524. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +1 -2
  525. package/src/Table/useTableGroupedRows.doc.mjs +3 -3
  526. package/src/Table/useTablePagination.doc.mjs +1 -1
  527. package/src/Table/useTableSelection.doc.mjs +1 -1
  528. package/src/Text/Text.test.tsx +44 -0
  529. package/src/Text/Text.tsx +0 -1
  530. package/src/TextArea/TextArea.doc.mjs +12 -2
  531. package/src/TextArea/TextArea.test.tsx +11 -0
  532. package/src/TextArea/TextArea.tsx +34 -22
  533. package/src/Timestamp/Timestamp.test.tsx +89 -0
  534. package/src/Timestamp/Timestamp.tsx +8 -8
  535. package/src/Timestamp/formatInstant.ts +5 -0
  536. package/src/Toast/Toast.doc.mjs +213 -44
  537. package/src/Toast/Toast.tsx +118 -23
  538. package/src/Toast/ToastViewport.test.tsx +1434 -8
  539. package/src/Toast/ToastViewport.tsx +85 -14
  540. package/src/Toast/index.ts +2 -0
  541. package/src/Toast/types.ts +43 -5
  542. package/src/Toast/useToastGesture.ts +361 -0
  543. package/src/Token/Token.test.tsx +95 -0
  544. package/src/Token/Token.tsx +19 -17
  545. package/src/Token/TokenLink.tsx +12 -3
  546. package/src/Tokenizer/Tokenizer.doc.mjs +16 -3
  547. package/src/Tokenizer/Tokenizer.test.tsx +161 -0
  548. package/src/Tokenizer/Tokenizer.tsx +49 -24
  549. package/src/TopNav/TopNavHeading.tsx +2 -2
  550. package/src/TopNav/TopNavItem.tsx +3 -7
  551. package/src/TopNav/TopNavMegaMenu.test.tsx +104 -0
  552. package/src/TopNav/TopNavMegaMenu.tsx +47 -4
  553. package/src/TopNav/TopNavMegaMenuItem.tsx +10 -9
  554. package/src/TopNav/TopNavMenu.test.tsx +133 -1
  555. package/src/TopNav/TopNavMenu.tsx +38 -5
  556. package/src/TreeList/TreeList.test.tsx +49 -0
  557. package/src/TreeList/TreeList.tsx +7 -2
  558. package/src/TreeList/TreeListItem.tsx +2 -7
  559. package/src/Typeahead/BaseTypeahead.doc.mjs +13 -0
  560. package/src/Typeahead/BaseTypeahead.tsx +96 -6
  561. package/src/Typeahead/Typeahead.doc.mjs +6 -0
  562. package/src/Typeahead/Typeahead.test.tsx +154 -0
  563. package/src/Typeahead/Typeahead.tsx +9 -0
  564. package/src/Typeahead/TypeaheadItem.test.tsx +43 -0
  565. package/src/Typeahead/TypeaheadItem.tsx +8 -1
  566. package/src/hooks/useAnnounce.doc.mjs +96 -0
  567. package/src/hooks/useDevWarning.doc.mjs +96 -0
  568. package/src/hooks/useHotkeys.test.ts +0 -18
  569. package/src/hooks/useHotkeys.ts +3 -25
  570. package/src/hooks/useIndicatorFocusRing.doc.mjs +104 -0
  571. package/src/hooks/useInputStatusIcon.doc.mjs +142 -0
  572. package/src/hooks/useInteractiveRole.doc.mjs +119 -0
  573. package/src/hooks/useLongPress.doc.mjs +123 -0
  574. package/src/hooks/useOverflow.doc.mjs +58 -17
  575. package/src/hooks/useOverflow.ts +16 -4
  576. package/src/hooks/useTypeahead.doc.mjs +153 -0
  577. package/src/index.ts +2 -0
  578. package/src/raw-import.d.ts +14 -0
  579. package/src/theme/Theme.test.tsx +104 -2
  580. package/src/theme/Theme.tsx +49 -14
  581. package/src/theme/defineTheme.test.ts +23 -0
  582. package/src/theme/defineTheme.ts +12 -3
  583. package/src/theme/derivedVarRegistry.test.ts +87 -3
  584. package/src/theme/derivedVarRegistry.ts +23 -4
  585. package/src/theme/generateThemeRules.test.ts +99 -1
  586. package/src/theme/generateThemeRules.ts +28 -0
  587. package/src/theme/syntax/tokens.ts +5 -2
  588. package/src/theme/useTheme.test.tsx +10 -0
  589. package/src/theme/useTheme.ts +16 -10
  590. package/src/utils/dateParser.test.ts +34 -2
  591. package/src/utils/dateParser.ts +11 -14
  592. package/src/utils/focusOutline.stylex.ts +50 -0
  593. package/src/utils/interactionOverlay.stylex.ts +74 -0
  594. package/src/utils/isApplePlatform.test.ts +61 -0
  595. package/src/utils/isApplePlatform.ts +37 -0
  596. package/src/utils/plainDate.test.ts +46 -0
  597. package/src/utils/plainDate.ts +18 -3
@@ -0,0 +1,234 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file numberParser.docblock.test.ts
5
+ * @input The rule paragraph in numberParser.ts, and the parser itself
6
+ * @output Nothing; fails when the two disagree
7
+ * @position Test-only; grades the prose in numberParser.ts against the code
8
+ *
9
+ * The file docblock of numberParser.ts states the rule the parser follows.
10
+ * A sentence like that rots silently — the code moves and the words stay —
11
+ * and the next person to change this file reads the words. So the paragraph
12
+ * is executable here: `predict` implements it, clause by clause, and every
13
+ * input is graded prose-against-parser.
14
+ *
15
+ * The one discipline that makes the number mean anything: `predict` may use
16
+ * ONLY what the paragraph says. Every branch below quotes the clause it
17
+ * implements, and those quotes are asserted verbatim against the source, so
18
+ * a paragraph that loses a clause fails here instead of drifting. If the
19
+ * parser grows a rule the words do not mention, this test goes red — that is
20
+ * the point, not a defect.
21
+ *
22
+ * SYNC: When modified, update these files to stay in sync:
23
+ * - /packages/core/src/NumberInput/numberParser.ts
24
+ */
25
+
26
+ import {describe, it, expect} from 'vitest';
27
+ import {parseLocaleNumber} from './numberParser';
28
+ import SOURCE from './numberParser.ts?raw';
29
+
30
+ /** The docblock as running prose: comment markers and line breaks removed. */
31
+ const PROSE = SOURCE.replace(/^\s*\*\s?/gm, '').replace(/\s+/g, ' ');
32
+
33
+ /** Every clause `predict` is allowed to know, quoted from the docblock. */
34
+ const CLAUSES = {
35
+ 'defer to the alphabet': 'SEPARATOR_CHARS below is a bounded alphabet',
36
+ 'fold the space family': 'the whole space family folds to it under NFKC',
37
+ 'refuse what no reading fits': 'text that no reading fits returns null',
38
+ 'prefer the locale': 'Where both readings are well formed the locale',
39
+ 'size every group':
40
+ "Grouping is well formed only when every group fits the locale's own " +
41
+ 'sizes: the last exactly the primary size, each inner one exactly the ' +
42
+ 'secondary, the first no longer than that.',
43
+ 'fall back to the decimal point': 'keep the full stop as a decimal point',
44
+ 'read three-digit groups anywhere':
45
+ 'Groups of three fit every locale, so a separator repeated with ' +
46
+ 'three-digit groups is grouping in all of them',
47
+ 'need only one group-only occurrence':
48
+ 'for a space or apostrophe, which no locale writes as a decimal point, ' +
49
+ 'one occurrence is enough',
50
+ } as const;
51
+
52
+ /** The bounded alphabet the docblock defers to, read out of the source. */
53
+ const ALPHABET: ReadonlySet<string> = new Set(
54
+ JSON.parse(
55
+ `"${/const SEPARATOR_CHARS = "([^"]*)"/.exec(SOURCE)?.[1] ?? ''}"`,
56
+ ),
57
+ );
58
+
59
+ const symbolsCache = new Map<string, ReturnType<typeof readSymbols>>();
60
+ function readSymbols(locale: string) {
61
+ const parts = new Intl.NumberFormat(locale).formatToParts(12345.6);
62
+ const sizes = new Intl.NumberFormat(locale)
63
+ .formatToParts(11111111111)
64
+ .filter(p => p.type === 'integer')
65
+ .map(p => p.value.length);
66
+ const grouped = sizes.length > 1;
67
+ return {
68
+ group: (parts.find(p => p.type === 'group')?.value ?? ',').normalize(
69
+ 'NFKC',
70
+ ),
71
+ decimal: parts.find(p => p.type === 'decimal')?.value ?? '.',
72
+ primary: grouped ? sizes[sizes.length - 1] : 3,
73
+ secondary: grouped ? sizes[sizes.length - 2] : 3,
74
+ };
75
+ }
76
+ function symbolsOf(locale: string) {
77
+ let s = symbolsCache.get(locale);
78
+ if (s === undefined) {
79
+ s = readSymbols(locale);
80
+ symbolsCache.set(locale, s);
81
+ }
82
+ return s;
83
+ }
84
+
85
+ /** CLAUSES['size every group'], with the sizes it is handed. */
86
+ function groupsFit(chunks: string[], primary: number, secondary: number) {
87
+ return (
88
+ chunks[chunks.length - 1].length === primary &&
89
+ chunks[0].length <= secondary &&
90
+ chunks.slice(1, -1).every(chunk => chunk.length === secondary)
91
+ );
92
+ }
93
+
94
+ /** CLAUSES['need only one group-only occurrence']: "a space or apostrophe". */
95
+ const isSpaceOrApostrophe = (char: string) => /^[\s'\u2019]$/.test(char);
96
+
97
+ const SKIPPED = Symbol('outside the paragraph');
98
+
99
+ /**
100
+ * The paragraph, as code. Digits with one separator character repeated
101
+ * between them is the shape it describes; anything else is not this
102
+ * paragraph's subject and is skipped rather than guessed at.
103
+ */
104
+ function predict(input: string, locale: string): number | null | symbol {
105
+ // CLAUSES['fold the space family'].
106
+ const text = input.normalize('NFKC');
107
+ if (!/^\d/.test(text) || !/\d$/.test(text)) {
108
+ return SKIPPED;
109
+ }
110
+ const separators = [...new Set(text.replace(/\d/g, ''))];
111
+ if (separators.length !== 1) {
112
+ return SKIPPED;
113
+ }
114
+ const [separator] = separators;
115
+
116
+ // CLAUSES['defer to the alphabet'].
117
+ if (!ALPHABET.has(separator)) {
118
+ return null;
119
+ }
120
+
121
+ const chunks = text.split(separator);
122
+ const {group, decimal, primary, secondary} = symbolsOf(locale);
123
+
124
+ // CLAUSES['prefer the locale'] + CLAUSES['size every group']: of the two
125
+ // locale readings, grouping wins wherever it is well formed.
126
+ if (separator === group && groupsFit(chunks, primary, secondary)) {
127
+ return Number(chunks.join(''));
128
+ }
129
+ // The locale's other reading. A decimal point appears once.
130
+ if (separator === decimal && chunks.length === 2) {
131
+ return Number(`${chunks[0]}.${chunks[1]}`);
132
+ }
133
+ // CLAUSES['fall back to the decimal point'], for a full stop the locale
134
+ // could read neither way.
135
+ if (separator === '.' && chunks.length === 2) {
136
+ return Number(text);
137
+ }
138
+ // CLAUSES['read three-digit groups anywhere'], and CLAUSES['need only one
139
+ // group-only occurrence'] for how many occurrences it takes.
140
+ const enough = isSpaceOrApostrophe(separator) ? 1 : 2;
141
+ if (chunks.length - 1 >= enough && groupsFit(chunks, 3, 3)) {
142
+ return Number(chunks.join(''));
143
+ }
144
+ // CLAUSES['refuse what no reading fits'].
145
+ return null;
146
+ }
147
+
148
+ const LOCALES = ['en-US', 'de-DE', 'fr-FR', 'de-CH', 'en-IN', 'ar-SA'];
149
+
150
+ /** The shapes the paragraph names, plus the seams around each clause. */
151
+ const NAMED: [string, string][] = [
152
+ ['1.234', 'de-DE'],
153
+ ['1.2345', 'de-DE'],
154
+ ['1234.567', 'de-DE'],
155
+ ['12345.678', 'de-DE'],
156
+ ['12.345', 'de-DE'],
157
+ ['1.23', 'de-DE'],
158
+ ['1,234,567', 'en-US'],
159
+ ['1,234,567', 'de-DE'],
160
+ ['1.234.567', 'en-US'],
161
+ ['1234.567.890', 'de-DE'],
162
+ ['1 234', 'en-US'],
163
+ ['1\u00A0234', 'en-US'],
164
+ ['1 234 567', 'en-US'],
165
+ ['1234 567', 'fr-FR'],
166
+ ["1'234", 'de-CH'],
167
+ ["1'234", 'en-US'],
168
+ ['1\u2019234', 'de-CH'],
169
+ ['1,234', 'en-IN'],
170
+ ['12,34,567', 'en-IN'],
171
+ ['123,45,678', 'en-IN'],
172
+ ['1,2,345', 'en-IN'],
173
+ ['1\u066C234', 'ar-SA'],
174
+ ['1\u066B5', 'ar-SA'],
175
+ ['1\u00B7234\u00B7567', 'en-US'],
176
+ ['123-456-789', 'en-US'],
177
+ ];
178
+
179
+ /** Every one-, two- and three-separator shape over short digit runs. */
180
+ function* generated() {
181
+ const runs = ['1', '12', '123', '1234', '12345'];
182
+ for (const locale of LOCALES) {
183
+ for (const separator of ALPHABET) {
184
+ for (const a of runs) {
185
+ for (const b of runs) {
186
+ yield [`${a}${separator}${b}`, locale] as [string, string];
187
+ for (const c of runs) {
188
+ yield [`${a}${separator}${b}${separator}${c}`, locale] as [
189
+ string,
190
+ string,
191
+ ];
192
+ for (const d of runs) {
193
+ yield [
194
+ `${a}${separator}${b}${separator}${c}${separator}${d}`,
195
+ locale,
196
+ ] as [string, string];
197
+ }
198
+ }
199
+ }
200
+ }
201
+ }
202
+ }
203
+ }
204
+
205
+ describe('the numberParser docblock', () => {
206
+ it.each(Object.entries(CLAUSES))('still says: %s', (_name, quote) => {
207
+ expect(PROSE).toContain(quote);
208
+ });
209
+
210
+ it.each(NAMED)('reads %j in %s the way the parser does', (input, locale) => {
211
+ expect(predict(input, locale)).toBe(parseLocaleNumber(input, locale));
212
+ });
213
+
214
+ it('reads every generated shape the way the parser does', () => {
215
+ const disagreements: string[] = [];
216
+ let checked = 0;
217
+ for (const [input, locale] of generated()) {
218
+ const said = predict(input, locale);
219
+ if (said === SKIPPED) {
220
+ continue;
221
+ }
222
+ checked++;
223
+ const did = parseLocaleNumber(input, locale);
224
+ if (!Object.is(said, did)) {
225
+ disagreements.push(
226
+ `${JSON.stringify(input)} in ${locale}: docblock ${String(said)}, parser ${String(did)}`,
227
+ );
228
+ }
229
+ }
230
+ // The sweep is the evidence; a shrunken one silently proves nothing.
231
+ expect(checked).toBeGreaterThan(30000);
232
+ expect(disagreements.slice(0, 10)).toEqual([]);
233
+ });
234
+ });
@@ -0,0 +1,222 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ import {describe, it, expect} from 'vitest';
4
+ import {formatEditableNumber, parseLocaleNumber} from './numberParser';
5
+
6
+ const NBSP = '\u00A0';
7
+ const NARROW_NBSP = '\u202F';
8
+ const APOSTROPHE = '\u2019';
9
+ const MIDDLE_DOT = '\u00B7';
10
+
11
+ /**
12
+ * The contract, enumerated. A row is `[input, locale, expected]`, and `null`
13
+ * means the field stays visibly invalid rather than committing a guess.
14
+ */
15
+ const CORPUS: [string, string, number | null][] = [
16
+ // Grouped — the case this exists for, and it holds in every locale because
17
+ // a repeated separator with three digits after it cannot be a decimal point.
18
+ ['1,234,234,234', 'en-US', 1234234234],
19
+ ['1,234,234,234', 'de-DE', 1234234234],
20
+ ['1,234,234,234', 'fr-FR', 1234234234],
21
+ ['1,234,234,234', 'ar-SA', 1234234234],
22
+ ['1.234.234.234', 'de-DE', 1234234234],
23
+ ['1.234.234.234', 'en-US', 1234234234],
24
+ [`1${NARROW_NBSP}234${NARROW_NBSP}234${NARROW_NBSP}234`, 'fr-FR', 1234234234],
25
+ [`1${NBSP}234${NBSP}234`, 'fr-FR', 1234234],
26
+ [`1${NBSP}234`, 'en-US', 1234],
27
+ [`1${APOSTROPHE}234${APOSTROPHE}234`, 'de-CH', 1234234],
28
+ ["1'234'234", 'de-CH', 1234234],
29
+ ['1,234', 'en-US', 1234],
30
+ ['1,234', 'de-DE', 1.234],
31
+
32
+ // Indian lakh grouping, derived from the locale's own group sizes.
33
+ ['12,34,567', 'en-IN', 1234567],
34
+ ['12,34,567', 'en-US', null],
35
+
36
+ // Ragged grouping is a typo, not a number: the last group is not three.
37
+ ['1,23,4', 'en-US', null],
38
+ ['1,2345', 'en-US', null],
39
+ ['12 34', 'en-US', null],
40
+
41
+ // One separator, one meaning per locale, and no meaning across them.
42
+ ['1,5', 'de-DE', 1.5],
43
+ ['1,5', 'en-US', null],
44
+ ['1.5', 'en-US', 1.5],
45
+
46
+ // The machine decimal point reads everywhere: a full stop the locale cannot
47
+ // read as grouping has one meaning left, and refusing it lost a number the
48
+ // person had typed. Where grouping IS well formed the locale still wins.
49
+ ['1.5', 'de-DE', 1.5],
50
+ ['1.5', 'fr-FR', 1.5],
51
+ ['1234.56', 'de-DE', 1234.56],
52
+ ['-3.25', 'fr-FR', -3.25],
53
+ ['0.5', 'de-DE', 0.5],
54
+ ['1.5e3', 'de-DE', 1500],
55
+ ['1.234', 'de-DE', 1234],
56
+ ['1.2345', 'de-DE', 1.2345],
57
+ // The same text in the other comma-decimal locale: fr-FR groups with a
58
+ // space, so a full stop has no grouping reading there and stays the point.
59
+ ['1.234', 'fr-FR', 1.234],
60
+
61
+ // Decimals and signs.
62
+ ['1,234.56', 'en-US', 1234.56],
63
+ ['1.234,56', 'de-DE', 1234.56],
64
+ ['1,234.56', 'de-DE', null],
65
+ ['-1,234.56', 'en-US', -1234.56],
66
+ ['+7', 'en-US', 7],
67
+ ['-7', 'en-US', -7],
68
+ ['7-', 'ar-SA', -7],
69
+ ['.5', 'en-US', 0.5],
70
+ ['5.', 'en-US', 5],
71
+ ['-', 'en-US', null],
72
+ ['', 'en-US', null],
73
+ [' ', 'en-US', null],
74
+
75
+ // Spreadsheet cells arrive with their whitespace attached.
76
+ [' 42 ', 'en-US', 42],
77
+ ['\t1,234\n', 'en-US', 1234],
78
+ ['1,234\n5,678', 'en-US', null],
79
+
80
+ // Digit scripts, derived from \p{Nd} rather than enumerated.
81
+ ['١٢٣', 'ar-SA', 123],
82
+ ['۱۲۳', 'fa-IR', 123],
83
+ ['१२३', 'hi-IN', 123],
84
+ ['123', 'ja-JP', 123],
85
+ ['١,٢٣٤', 'en-US', 1234],
86
+ ['٣٫٥', 'ar-SA', 3.5],
87
+
88
+ // Currency decorates the number without changing its magnitude, so the
89
+ // symbol is dropped and the separators still decide. A number written for
90
+ // another locale still refuses.
91
+ ['$1,234.56', 'en-US', 1234.56],
92
+ ['£1,234', 'en-US', 1234],
93
+ ['1.234,56 €', 'de-DE', 1234.56],
94
+ ['1.234,56 €', 'en-US', null],
95
+ ['-$1,234', 'en-US', -1234],
96
+
97
+ // A unit suffix is not dropped: `B` and `k` carry magnitude, so guessing
98
+ // which trailing letters are inert is how a wrong number gets committed.
99
+ ['1,234 GB', 'en-US', null],
100
+ ['72°F', 'en-US', null],
101
+ ['1,234 kg', 'en-US', null],
102
+
103
+ // Accounting negatives.
104
+ ['(1,234)', 'en-US', -1234],
105
+ ['($1,234.50)', 'en-US', -1234.5],
106
+ ['(1,234', 'en-US', null],
107
+ // The parens already carry the sign; a second one reads two ways.
108
+ ['(-1,234)', 'en-US', null],
109
+ ['(+1,234)', 'en-US', null],
110
+
111
+ // Typographic minus signs.
112
+ ['\u22121234', 'en-US', -1234],
113
+ ['\u20131234', 'en-US', -1234],
114
+
115
+ // Exponents, including the shape a spreadsheet exports.
116
+ ['1.23E+09', 'en-US', 1230000000],
117
+ ['1.23e9', 'en-US', 1230000000],
118
+ ['1.5e-3', 'en-US', 0.0015],
119
+ ['1e', 'en-US', null],
120
+
121
+ // Invisible characters Excel and Sheets attach.
122
+ ['\uFEFF1,234', 'en-US', 1234],
123
+ ['1,234\u200B', 'en-US', 1234],
124
+ ['\u200E1,234', 'en-US', 1234],
125
+
126
+ // Junk.
127
+ ['NaN', 'en-US', null],
128
+ ['Infinity', 'en-US', null],
129
+ ['abc', 'en-US', null],
130
+ ['12abc', 'en-US', null],
131
+ ['1/2', 'en-US', null],
132
+ ['1 234 (approx)', 'en-US', null],
133
+ ['--5', 'en-US', null],
134
+ ['1..234', 'en-US', null],
135
+
136
+ // Only a character some locale writes between digits is a separator. None of
137
+ // these are numbers, and the last two were refused before only because their
138
+ // final group is the wrong length — luck, not a rule.
139
+ ['123-456-789', 'en-US', null],
140
+ ['1-800-555', 'en-US', null],
141
+ ['555-123-456', 'en-US', null],
142
+ ['1_234_567', 'en-US', null],
143
+ ['1/234/567', 'en-US', null],
144
+ ['1:234:567', 'en-US', null],
145
+ ['1*234*567', 'en-US', null],
146
+ ['800-555-1212', 'en-US', null],
147
+ ['2024-01-15', 'en-US', null],
148
+
149
+ // U+00B7 was in the alphabet as the Catalan middle dot. Catalan groups with
150
+ // a full stop, and no locale ICU resolves writes it between digits at all.
151
+ [`1${MIDDLE_DOT}234${MIDDLE_DOT}567`, 'en-US', null],
152
+ [`1${MIDDLE_DOT}234${MIDDLE_DOT}567`, 'ca-ES', null],
153
+
154
+ // The field has no percent semantics, so a percent sign is not dropped:
155
+ // committing 45 for `45%` is off by a factor of a hundred.
156
+ ['45%', 'en-US', null],
157
+ ['0.5%', 'en-US', null],
158
+ ['45 %', 'fr-FR', null],
159
+ ];
160
+
161
+ describe('parseLocaleNumber', () => {
162
+ it.each(CORPUS)('parses %j in %s', (input, locale, expected) => {
163
+ expect(parseLocaleNumber(input, locale)).toBe(expected);
164
+ });
165
+
166
+ it('reads back the grouping every locale writes', () => {
167
+ for (const locale of [
168
+ 'en-US',
169
+ 'de-DE',
170
+ 'fr-FR',
171
+ 'de-CH',
172
+ 'en-IN',
173
+ 'ar-SA',
174
+ ]) {
175
+ const text = new Intl.NumberFormat(locale).format(1234234234);
176
+ expect(parseLocaleNumber(text, locale)).toBe(1234234234);
177
+ }
178
+ });
179
+ });
180
+
181
+ describe('formatEditableNumber', () => {
182
+ it.each([
183
+ [1.5, 'en-US', '1.5'],
184
+ [1.5, 'de-DE', '1,5'],
185
+ [-1234.56, 'fr-FR', '-1234,56'],
186
+ // Only the decimal separator is localized. The digits stay as `String`
187
+ // writes them, which is what the field shows at rest when no `formatValue`
188
+ // is given, so localizing them here would flip the script on focus.
189
+ [3.5, 'ar-SA', '3٫5'],
190
+ // No grouping: the text has to be editable, and a separator the person did
191
+ // not type is one they have to delete.
192
+ [1234234234, 'de-DE', '1234234234'],
193
+ [42, 'de-DE', '42'],
194
+ // What `String` writes for the extremes stays untouched but for the point.
195
+ [1e21, 'de-DE', '1e+21'],
196
+ [1.5e-7, 'de-DE', '1,5e-7'],
197
+ ])('shows %j in %s as %j', (value, locale, expected) => {
198
+ expect(formatEditableNumber(value, locale)).toBe(expected);
199
+ });
200
+
201
+ it('round trips through the parser in every locale', () => {
202
+ for (const locale of [
203
+ 'en-US',
204
+ 'de-DE',
205
+ 'fr-FR',
206
+ 'de-CH',
207
+ 'en-IN',
208
+ 'ar-SA',
209
+ 'ja-JP',
210
+ 'hi-IN',
211
+ ]) {
212
+ for (const value of [
213
+ 0, 1, -1, 0.1, 1.5, -0.5, 1234.56, -1234567.125, 123456789,
214
+ 3.141592653589793, 1e21, 1.5e-7, -9007199254740991,
215
+ ]) {
216
+ expect(
217
+ parseLocaleNumber(formatEditableNumber(value, locale), locale),
218
+ ).toBe(value);
219
+ }
220
+ }
221
+ });
222
+ });