@astryxdesign/core 0.7.5 → 0.7.6-canary.0ef60dd

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 (559) hide show
  1. package/dist/AlertDialog/AlertDialog.d.ts +1 -1
  2. package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
  3. package/dist/AlertDialog/AlertDialog.js +5 -5
  4. package/dist/Avatar/Avatar.d.ts.map +1 -1
  5. package/dist/Avatar/Avatar.js +12 -3
  6. package/dist/Badge/Badge.d.ts.map +1 -1
  7. package/dist/Badge/Badge.js +7 -1
  8. package/dist/BottomSheet/BottomSheet.js +1 -1
  9. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
  10. package/dist/BottomSheet/BottomSheetPanel.js +2 -1
  11. package/dist/BottomSheet/useSheetGestures.d.ts +12 -0
  12. package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
  13. package/dist/BottomSheet/useSheetGestures.js +30 -3
  14. package/dist/Button/Button.js +4 -4
  15. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  16. package/dist/CheckboxInput/CheckboxInput.js +6 -5
  17. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  18. package/dist/ClickableCard/ClickableCard.js +37 -4
  19. package/dist/DateInput/DateInput.d.ts.map +1 -1
  20. package/dist/DateInput/DateInput.js +12 -4
  21. package/dist/DateInput/MonthScroller.d.ts.map +1 -1
  22. package/dist/DateInput/MonthScroller.js +101 -15
  23. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  24. package/dist/DateInput/TouchDateField.js +8 -3
  25. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  26. package/dist/DateRangeInput/DateRangeInput.js +1 -1
  27. package/dist/DateTimeInput/DateTimeInput.d.ts +5 -2
  28. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  29. package/dist/DateTimeInput/DateTimeInput.js +23 -12
  30. package/dist/DateTimeInput/NativeTimeSegment.d.ts.map +1 -1
  31. package/dist/DateTimeInput/NativeTimeSegment.js +5 -4
  32. package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
  33. package/dist/DateTimeInput/TouchDateTimeField.js +4 -3
  34. package/dist/Dialog/Dialog.d.ts.map +1 -1
  35. package/dist/Dialog/Dialog.js +34 -9
  36. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  37. package/dist/Dialog/DialogHeader.js +5 -4
  38. package/dist/Divider/Divider.d.ts.map +1 -1
  39. package/dist/Divider/Divider.js +2 -1
  40. package/dist/Drawer/Drawer.d.ts +1 -0
  41. package/dist/Drawer/Drawer.d.ts.map +1 -1
  42. package/dist/Drawer/Drawer.js +7 -2
  43. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  44. package/dist/DropdownMenu/DropdownMenu.js +7 -3
  45. package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts.map +1 -1
  46. package/dist/DropdownMenu/MenuBottomSheetActionList.js +6 -5
  47. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts +20 -2
  48. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts.map +1 -1
  49. package/dist/DropdownMenu/lazyMenuBottomSheet.js +31 -3
  50. package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
  51. package/dist/DropdownMenu/renderDropdownItems.js +21 -16
  52. package/dist/EmptyState/EmptyState.d.ts.map +1 -1
  53. package/dist/EmptyState/EmptyState.js +2 -1
  54. package/dist/Field/FieldLabel.d.ts +1 -1
  55. package/dist/Field/FieldLabel.d.ts.map +1 -1
  56. package/dist/Field/FieldLabel.js +4 -4
  57. package/dist/Field/InputClearButton.js +3 -3
  58. package/dist/Field/PanelSearchInput.js +2 -2
  59. package/dist/FieldStatus/FieldStatus.js +2 -2
  60. package/dist/FileInput/FileInput.d.ts.map +1 -1
  61. package/dist/FileInput/FileInput.js +7 -1
  62. package/dist/Heading/Heading.js +1 -1
  63. package/dist/Icon/Icon.js +1 -1
  64. package/dist/Indicator/CheckIndicator.d.ts.map +1 -1
  65. package/dist/Indicator/CheckIndicator.js +2 -1
  66. package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -1
  67. package/dist/Indicator/CheckboxIndicator.js +3 -1
  68. package/dist/Indicator/RadioIndicator.d.ts.map +1 -1
  69. package/dist/Indicator/RadioIndicator.js +3 -1
  70. package/dist/Item/Item.d.ts.map +1 -1
  71. package/dist/Item/Item.js +2 -1
  72. package/dist/Item/ItemSwipeLayer.js +1 -1
  73. package/dist/Layer/popoverOperations.d.ts +27 -0
  74. package/dist/Layer/popoverOperations.d.ts.map +1 -0
  75. package/dist/Layer/popoverOperations.js +159 -0
  76. package/dist/Layer/useLayer.d.ts +1 -1
  77. package/dist/Layer/useLayer.d.ts.map +1 -1
  78. package/dist/Layer/useLayer.js +93 -59
  79. package/dist/Layout/Layout.js +1 -1
  80. package/dist/Layout/LayoutContent.js +1 -1
  81. package/dist/Layout/LayoutFooter.js +1 -1
  82. package/dist/Layout/LayoutHeader.js +1 -1
  83. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  84. package/dist/Lightbox/Lightbox.js +5 -0
  85. package/dist/Lightbox/LightboxViewport.a11y.browser.spec.js +5 -4
  86. package/dist/List/List.js +1 -1
  87. package/dist/List/ListItem.js +3 -3
  88. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  89. package/dist/MobileNav/MobileNav.js +7 -2
  90. package/dist/MultiSelector/CreateRow.a11y.chromium.spec.js +7 -6
  91. package/dist/MultiSelector/MultiSelector.d.ts +1 -1
  92. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  93. package/dist/MultiSelector/MultiSelector.js +26 -10
  94. package/dist/NumberInput/NumberInput.d.ts +3 -1
  95. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  96. package/dist/NumberInput/NumberInput.js +3 -3
  97. package/dist/NumberInput/numberParser.d.ts +3 -0
  98. package/dist/NumberInput/numberParser.d.ts.map +1 -1
  99. package/dist/NumberInput/numberParser.js +7 -44
  100. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  101. package/dist/ProgressBar/ProgressBar.js +16 -12
  102. package/dist/Resizable/useResizable.d.ts.map +1 -1
  103. package/dist/Resizable/useResizable.js +28 -2
  104. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  105. package/dist/SegmentedControl/SegmentedControlItem.js +4 -1
  106. package/dist/Selector/useSelectorPresentation.d.ts +8 -1
  107. package/dist/Selector/useSelectorPresentation.d.ts.map +1 -1
  108. package/dist/Selector/useSelectorPresentation.js +20 -4
  109. package/dist/Skeleton/Skeleton.d.ts.map +1 -1
  110. package/dist/Skeleton/Skeleton.js +1 -1
  111. package/dist/Slider/Slider.d.ts.map +1 -1
  112. package/dist/Slider/Slider.js +10 -2
  113. package/dist/Spinner/Spinner.d.ts.map +1 -1
  114. package/dist/Spinner/Spinner.js +3 -3
  115. package/dist/Stack/Stack.js +1 -1
  116. package/dist/Stack/StackItem.js +1 -1
  117. package/dist/TabList/TabList.d.ts.map +1 -1
  118. package/dist/TabList/TabList.js +16 -1
  119. package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
  120. package/dist/Table/plugins/columnResize/useTableColumnResize.js +9 -1
  121. package/dist/Text/Text.js +1 -1
  122. package/dist/Text/useTruncation.d.ts.map +1 -1
  123. package/dist/Text/useTruncation.js +23 -5
  124. package/dist/TextArea/TextArea.d.ts +1 -1
  125. package/dist/TextArea/TextArea.d.ts.map +1 -1
  126. package/dist/TextArea/TextArea.js +13 -2
  127. package/dist/TextInput/TextInput.d.ts.map +1 -1
  128. package/dist/TextInput/TextInput.js +3 -3
  129. package/dist/TimeInput/TimeInput.d.ts +6 -2
  130. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  131. package/dist/TimeInput/TimeInput.js +21 -14
  132. package/dist/TimeInput/TouchTimeField.d.ts.map +1 -1
  133. package/dist/TimeInput/TouchTimeField.js +5 -4
  134. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  135. package/dist/Timestamp/Timestamp.js +2 -2
  136. package/dist/Timestamp/TimestampHoverCard.js +4 -4
  137. package/dist/Toast/Toast.d.ts.map +1 -1
  138. package/dist/Toast/Toast.js +60 -20
  139. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  140. package/dist/Toast/ToastViewport.js +82 -51
  141. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  142. package/dist/Tokenizer/Tokenizer.js +13 -2
  143. package/dist/Tokenizer/TokenizerBottomSheet.js +3 -3
  144. package/dist/Toolbar/Toolbar.d.ts.map +1 -1
  145. package/dist/Toolbar/Toolbar.js +2 -1
  146. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  147. package/dist/TopNav/TopNavMegaMenu.js +3 -0
  148. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  149. package/dist/TopNav/TopNavMenu.js +1 -0
  150. package/dist/Typeahead/Typeahead.d.ts +1 -1
  151. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  152. package/dist/Typeahead/Typeahead.js +9 -1
  153. package/dist/astryx.css +20 -4
  154. package/dist/gestures/GestureArena.d.ts +6 -0
  155. package/dist/gestures/GestureArena.d.ts.map +1 -1
  156. package/dist/gestures/GestureArena.js +39 -0
  157. package/dist/gestures/GestureHost.d.ts +352 -0
  158. package/dist/gestures/GestureHost.d.ts.map +1 -0
  159. package/dist/gestures/GestureHost.js +1773 -0
  160. package/dist/gestures/GestureRecognizer.d.ts +10 -0
  161. package/dist/gestures/GestureRecognizer.d.ts.map +1 -1
  162. package/dist/gestures/GestureRecognizer.js +16 -0
  163. package/dist/gestures/LongPressGestureRecognizer.d.ts +1 -0
  164. package/dist/gestures/LongPressGestureRecognizer.d.ts.map +1 -1
  165. package/dist/gestures/LongPressGestureRecognizer.js +3 -0
  166. package/dist/gestures/PanGestureRecognizer.d.ts +1 -0
  167. package/dist/gestures/PanGestureRecognizer.d.ts.map +1 -1
  168. package/dist/gestures/PanGestureRecognizer.js +3 -0
  169. package/dist/gestures/PinchGestureRecognizer.d.ts +31 -0
  170. package/dist/gestures/PinchGestureRecognizer.d.ts.map +1 -0
  171. package/dist/gestures/PinchGestureRecognizer.js +128 -0
  172. package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts +71 -0
  173. package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts.map +1 -0
  174. package/dist/gestures/ScreenEdgePanGestureRecognizer.js +223 -0
  175. package/dist/gestures/SwipeGestureRecognizer.d.ts +37 -0
  176. package/dist/gestures/SwipeGestureRecognizer.d.ts.map +1 -0
  177. package/dist/gestures/SwipeGestureRecognizer.js +148 -0
  178. package/dist/gestures/TapGestureRecognizer.d.ts +1 -0
  179. package/dist/gestures/TapGestureRecognizer.d.ts.map +1 -1
  180. package/dist/gestures/TapGestureRecognizer.js +3 -0
  181. package/dist/gestures/VelocityTracker.d.ts +6 -2
  182. package/dist/gestures/VelocityTracker.d.ts.map +1 -1
  183. package/dist/gestures/VelocityTracker.js +7 -3
  184. package/dist/gestures/haptics.d.ts +65 -0
  185. package/dist/gestures/haptics.d.ts.map +1 -0
  186. package/dist/gestures/haptics.js +182 -0
  187. package/dist/gestures/nativeScroll.d.ts +42 -0
  188. package/dist/gestures/nativeScroll.d.ts.map +1 -0
  189. package/dist/gestures/nativeScroll.js +228 -0
  190. package/dist/gestures/touchAction.d.ts +60 -0
  191. package/dist/gestures/touchAction.d.ts.map +1 -0
  192. package/dist/gestures/touchAction.js +157 -0
  193. package/dist/gestures/touchActionRule.d.ts +34 -0
  194. package/dist/gestures/touchActionRule.d.ts.map +1 -0
  195. package/dist/gestures/touchActionRule.js +140 -0
  196. package/dist/gestures/types.d.ts +18 -7
  197. package/dist/gestures/types.d.ts.map +1 -1
  198. package/dist/gestures/types.js +22 -2
  199. package/dist/hooks/index.d.ts +1 -1
  200. package/dist/hooks/index.d.ts.map +1 -1
  201. package/dist/hooks/modalAnnounce.d.ts.map +1 -1
  202. package/dist/hooks/modalAnnounce.js +107 -61
  203. package/dist/hooks/useAdaptivePresentation.d.ts.map +1 -1
  204. package/dist/hooks/useAdaptivePresentation.js +4 -1
  205. package/dist/hooks/useAnnounce.d.ts +101 -42
  206. package/dist/hooks/useAnnounce.d.ts.map +1 -1
  207. package/dist/hooks/useAnnounce.js +161 -75
  208. package/dist/hooks/useAnnounceRenderedText.d.ts +11 -3
  209. package/dist/hooks/useAnnounceRenderedText.d.ts.map +1 -1
  210. package/dist/hooks/useAnnounceRenderedText.js +5 -3
  211. package/dist/hooks/useBusyAnnouncement.d.ts.map +1 -1
  212. package/dist/hooks/useBusyAnnouncement.js +6 -12
  213. package/dist/hooks/useMenuHover.d.ts.map +1 -1
  214. package/dist/hooks/useMenuHover.js +12 -1
  215. package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
  216. package/dist/i18n/generated-locales/en.generated.js +5 -0
  217. package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
  218. package/dist/i18n/generated-locales/pseudo.generated.js +5 -0
  219. package/dist/motion/animator.d.ts +7 -1
  220. package/dist/motion/animator.d.ts.map +1 -1
  221. package/dist/motion/animator.js +119 -27
  222. package/dist/theme/defineTheme.d.ts +19 -5
  223. package/dist/theme/defineTheme.d.ts.map +1 -1
  224. package/dist/theme/defineTheme.js +64 -4
  225. package/dist/theme/domainTokens/domainTokenDefaults.d.ts +3 -0
  226. package/dist/theme/domainTokens/domainTokenDefaults.d.ts.map +1 -0
  227. package/dist/theme/domainTokens/domainTokenDefaults.js +19 -0
  228. package/dist/theme/domainTokens/index.d.ts +5 -4
  229. package/dist/theme/domainTokens/index.d.ts.map +1 -1
  230. package/dist/theme/domainTokens/index.js +5 -9
  231. package/dist/theme/index.d.ts +1 -0
  232. package/dist/theme/index.d.ts.map +1 -1
  233. package/dist/theme/motionKnobs.d.ts +56 -0
  234. package/dist/theme/motionKnobs.d.ts.map +1 -0
  235. package/dist/theme/motionKnobs.js +48 -0
  236. package/dist/theme/resolveThemeValues.d.ts +11 -4
  237. package/dist/theme/resolveThemeValues.d.ts.map +1 -1
  238. package/dist/theme/resolveThemeValues.js +40 -4
  239. package/dist/theme/themeAdaptations.d.ts +7 -3
  240. package/dist/theme/themeAdaptations.d.ts.map +1 -1
  241. package/dist/theme/themeAdaptations.js +36 -7
  242. package/dist/theme/themeMotion.d.ts +96 -0
  243. package/dist/theme/themeMotion.d.ts.map +1 -0
  244. package/dist/theme/themeMotion.js +177 -0
  245. package/dist/theme/tokenReferences.d.ts +31 -0
  246. package/dist/theme/tokenReferences.d.ts.map +1 -0
  247. package/dist/theme/tokenReferences.js +132 -0
  248. package/dist/theme/tokens.d.ts +1 -0
  249. package/dist/theme/tokens.d.ts.map +1 -1
  250. package/dist/theme/tokens.js +9 -129
  251. package/dist/theme/tokens.stylex.d.ts +12 -0
  252. package/dist/theme/tokens.stylex.d.ts.map +1 -1
  253. package/dist/theme/tokens.stylex.js +12 -0
  254. package/dist/utils/focusReturn.d.ts +17 -1
  255. package/dist/utils/focusReturn.d.ts.map +1 -1
  256. package/dist/utils/focusReturn.js +11 -4
  257. package/dist/utils/getNodeText.d.ts +8 -0
  258. package/dist/utils/getNodeText.d.ts.map +1 -0
  259. package/dist/utils/getNodeText.js +37 -0
  260. package/dist/utils/interactionModality.d.ts +11 -2
  261. package/dist/utils/interactionModality.d.ts.map +1 -1
  262. package/dist/utils/interactionModality.js +58 -5
  263. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
  264. package/dist/utils/interactionOverlay.stylex.js +17 -8
  265. package/dist/utils/plainDate.d.ts +2 -0
  266. package/dist/utils/plainDate.d.ts.map +1 -1
  267. package/dist/utils/plainDate.js +46 -3
  268. package/dist/utils/presentation.d.ts +50 -0
  269. package/dist/utils/presentation.d.ts.map +1 -0
  270. package/dist/utils/presentation.js +125 -0
  271. package/dist/utils/pressFeedback.d.ts.map +1 -1
  272. package/dist/utils/pressFeedback.js +20 -1
  273. package/dist/utils/primaryClick.d.ts +11 -0
  274. package/dist/utils/primaryClick.d.ts.map +1 -0
  275. package/dist/utils/primaryClick.js +25 -0
  276. package/dist/utils/timeFormat.d.ts +47 -0
  277. package/dist/utils/timeFormat.d.ts.map +1 -0
  278. package/dist/utils/timeFormat.js +240 -0
  279. package/dist/utils/touchPresentation.d.ts.map +1 -1
  280. package/dist/utils/touchPresentation.js +5 -3
  281. package/dist/utils/touchPresentation.stylex.d.ts +15 -0
  282. package/dist/utils/touchPresentation.stylex.d.ts.map +1 -0
  283. package/dist/utils/touchPresentation.stylex.js +33 -0
  284. package/dist/utils/unicodeDigits.d.ts +20 -0
  285. package/dist/utils/unicodeDigits.d.ts.map +1 -0
  286. package/dist/utils/unicodeDigits.js +70 -0
  287. package/locales/en.json +23 -3
  288. package/locales/pseudo.json +15 -0
  289. package/package.json +5 -4
  290. package/src/AlertDialog/AlertDialog.tsx +6 -5
  291. package/src/AlertDialog/__tests__/AlertDialog.a11y.chromium.spec.ts +18 -6
  292. package/src/Avatar/Avatar.spec.md +22 -22
  293. package/src/Avatar/Avatar.tsx +18 -1
  294. package/src/Avatar/__tests__/AvatarForcedColors.a11y.chromium.spec.ts +126 -0
  295. package/src/Badge/Badge.doc.mjs +1 -1
  296. package/src/Badge/Badge.tsx +19 -2
  297. package/src/Badge/__tests__/BadgeLargerText.a11y.chromium.spec.ts +260 -0
  298. package/src/BottomSheet/BottomSheet.test.tsx +46 -0
  299. package/src/BottomSheet/BottomSheet.tsx +1 -1
  300. package/src/BottomSheet/BottomSheetPanel.tsx +2 -1
  301. package/src/BottomSheet/useSheetGestures.test.ts +52 -0
  302. package/src/BottomSheet/useSheetGestures.ts +37 -6
  303. package/src/Breadcrumbs/__tests__/Breadcrumbs.a11y.chromium.spec.ts +18 -6
  304. package/src/Button/Button.tsx +4 -4
  305. package/src/Calendar/Calendar.spec.md +87 -48
  306. package/src/Calendar/__tests__/Calendar.a11y.chromium.spec.ts +21 -7
  307. package/src/Carousel/__tests__/Carousel.a11y.chromium.spec.ts +21 -7
  308. package/src/CheckboxInput/CheckboxInput.tsx +6 -5
  309. package/src/ClickableCard/ClickableCard.test.tsx +96 -0
  310. package/src/ClickableCard/ClickableCard.tsx +48 -4
  311. package/src/Collapsible/Collapsible.spec.md +2 -0
  312. package/src/Collapsible/CollapsibleGroup.spec.md +57 -29
  313. package/src/Collapsible/__tests__/Collapsible.a11y.chromium.spec.ts +18 -7
  314. package/src/Collapsible/__tests__/CollapsibleGroupAccordion.a11y.chromium.spec.ts +18 -6
  315. package/src/ComplexSelector/ComplexSelector.test.tsx +37 -0
  316. package/src/ContextMenu/ContextMenu.test.tsx +35 -0
  317. package/src/DateInput/DateInput.test.tsx +115 -3
  318. package/src/DateInput/DateInput.tsx +29 -14
  319. package/src/DateInput/DateInputTouch.test.tsx +76 -0
  320. package/src/DateInput/MonthScroller.tsx +106 -20
  321. package/src/DateInput/MonthScrollerSettle.test.tsx +165 -0
  322. package/src/DateInput/TouchDateField.tsx +14 -3
  323. package/src/DateInput/__tests__/MonthScrollerSteps.interaction.browser.spec.ts +312 -0
  324. package/src/DateRangeInput/DateRangeInput.test.tsx +46 -3
  325. package/src/DateRangeInput/DateRangeInput.tsx +16 -12
  326. package/src/DateTimeInput/DateTimeInput.doc.mjs +10 -8
  327. package/src/DateTimeInput/DateTimeInput.spec.md +75 -51
  328. package/src/DateTimeInput/DateTimeInput.test.tsx +81 -0
  329. package/src/DateTimeInput/DateTimeInput.tsx +46 -24
  330. package/src/DateTimeInput/NativeTimeSegment.tsx +4 -6
  331. package/src/DateTimeInput/TouchDateTimeField.tsx +3 -7
  332. package/src/Dialog/Dialog.test.tsx +216 -2
  333. package/src/Dialog/Dialog.tsx +42 -9
  334. package/src/Dialog/DialogHeader.tsx +5 -4
  335. package/src/Dialog/__tests__/DialogSecondDocument.a11y.browser.spec.ts +202 -0
  336. package/src/Divider/Divider.tsx +2 -1
  337. package/src/Drawer/Drawer.spec.md +111 -80
  338. package/src/Drawer/Drawer.test.tsx +35 -0
  339. package/src/Drawer/Drawer.tsx +13 -2
  340. package/src/Drawer/DrawerHeader.spec.md +181 -0
  341. package/src/Drawer/__tests__/DrawerNonModalPageScroll.a11y.chromium.spec.ts +267 -0
  342. package/src/DropdownMenu/DropdownMenu.test.tsx +41 -0
  343. package/src/DropdownMenu/DropdownMenu.tsx +10 -3
  344. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +34 -0
  345. package/src/DropdownMenu/MenuBottomSheetActionList.tsx +6 -5
  346. package/src/DropdownMenu/__tests__/Menu.a11y.chromium.spec.ts +19 -7
  347. package/src/DropdownMenu/__tests__/MenuButton.a11y.chromium.spec.ts +21 -9
  348. package/src/DropdownMenu/lazyMenuBottomSheet.test.ts +60 -0
  349. package/src/DropdownMenu/lazyMenuBottomSheet.ts +36 -7
  350. package/src/DropdownMenu/renderDropdownItems.tsx +24 -19
  351. package/src/EmptyState/EmptyState.tsx +2 -1
  352. package/src/Field/FieldLabel.tsx +5 -4
  353. package/src/Field/InputClearButton.tsx +3 -3
  354. package/src/Field/PanelSearchInput.tsx +2 -2
  355. package/src/FieldStatus/FieldStatus.tsx +2 -2
  356. package/src/FileInput/FileInput.test.tsx +21 -0
  357. package/src/FileInput/FileInput.tsx +4 -1
  358. package/src/FormLayout/FormLayout.spec.md +7 -8
  359. package/src/Heading/Heading.tsx +1 -1
  360. package/src/Icon/Icon.tsx +1 -1
  361. package/src/Indicator/CheckIndicator.spec.md +47 -42
  362. package/src/Indicator/CheckIndicator.tsx +2 -1
  363. package/src/Indicator/CheckboxIndicator.spec.md +40 -37
  364. package/src/Indicator/CheckboxIndicator.tsx +3 -1
  365. package/src/Indicator/Indicator.spec.md +188 -0
  366. package/src/Indicator/RadioIndicator.tsx +3 -1
  367. package/src/Item/Item.tsx +2 -1
  368. package/src/Item/ItemSwipeLayer.tsx +1 -1
  369. package/src/Kbd/Kbd.spec.md +81 -38
  370. package/src/Layer/__tests__/LayerBrowserHide.a11y.chromium.spec.ts +126 -0
  371. package/src/Layer/popoverOperations.test.ts +205 -0
  372. package/src/Layer/popoverOperations.ts +172 -0
  373. package/src/Layer/useLayer.test.tsx +348 -1
  374. package/src/Layer/useLayer.tsx +118 -71
  375. package/src/Layout/Layout.spec.md +127 -131
  376. package/src/Layout/Layout.tsx +1 -1
  377. package/src/Layout/LayoutContent.spec.md +205 -0
  378. package/src/Layout/LayoutContent.tsx +1 -1
  379. package/src/Layout/LayoutFooter.spec.md +190 -0
  380. package/src/Layout/LayoutFooter.tsx +1 -1
  381. package/src/Layout/LayoutHeader.spec.md +193 -0
  382. package/src/Layout/LayoutHeader.tsx +1 -1
  383. package/src/Layout/LayoutPanel.spec.md +194 -0
  384. package/src/Layout/__tests__/Layout.a11y.chromium.spec.ts +18 -6
  385. package/src/Lightbox/Lightbox.test.tsx +18 -0
  386. package/src/Lightbox/Lightbox.tsx +5 -0
  387. package/src/Lightbox/LightboxViewport.a11y.browser.spec.ts +8 -4
  388. package/src/Link/__tests__/Link.a11y.chromium.spec.ts +18 -8
  389. package/src/List/List.tsx +1 -1
  390. package/src/List/ListItem.spec.md +205 -0
  391. package/src/List/ListItem.tsx +3 -3
  392. package/src/MetadataList/MetadataList.spec.md +187 -0
  393. package/src/MetadataList/MetadataListItem.spec.md +165 -0
  394. package/src/MobileNav/MobileNav.test.tsx +15 -0
  395. package/src/MobileNav/MobileNav.tsx +9 -1
  396. package/src/MobileNav/__tests__/MobileNavHeader.a11y.chromium.spec.ts +89 -0
  397. package/src/MoreMenu/MoreMenu.test.tsx +11 -0
  398. package/src/MultiSelector/CreateRow.a11y.chromium.spec.ts +7 -8
  399. package/src/MultiSelector/MultiSelector.spec.md +7 -4
  400. package/src/MultiSelector/MultiSelector.test.tsx +270 -1
  401. package/src/MultiSelector/MultiSelector.tsx +25 -10
  402. package/src/MultiSelector/__tests__/MultiSelector.listbox.a11y.test.tsx +8 -1
  403. package/src/NavMenu/NavHeadingMenu.spec.md +1 -5
  404. package/src/NumberInput/NumberInput.doc.mjs +13 -7
  405. package/src/NumberInput/NumberInput.spec.md +59 -37
  406. package/src/NumberInput/NumberInput.tsx +13 -3
  407. package/src/NumberInput/__tests__/NumberInput.coarse-pointer.a11y.chromium.spec.ts +102 -0
  408. package/src/NumberInput/numberParser.ts +7 -45
  409. package/src/ProgressBar/ProgressBar.test.tsx +108 -32
  410. package/src/ProgressBar/ProgressBar.tsx +58 -10
  411. package/src/ProgressBar/__tests__/ProgressBar.a11y.chromium.spec.ts +21 -9
  412. package/src/ProgressBar/__tests__/ProgressBarMotion.a11y.chromium.spec.ts +831 -0
  413. package/src/Resizable/__tests__/ResizeHandle.a11y.chromium.spec.ts +21 -14
  414. package/src/Resizable/useResizable.test.ts +43 -0
  415. package/src/Resizable/useResizable.ts +32 -9
  416. package/src/SegmentedControl/SegmentedControl.test.tsx +84 -0
  417. package/src/SegmentedControl/SegmentedControlItem.tsx +11 -5
  418. package/src/Selector/Selector.test.tsx +90 -1
  419. package/src/Selector/__tests__/Selector.combobox.a11y.test.tsx +8 -1
  420. package/src/Selector/__tests__/Selector.listbox.a11y.test.tsx +8 -1
  421. package/src/Selector/useSelectorPresentation.ts +31 -3
  422. package/src/SideNav/SideNav.test.tsx +27 -0
  423. package/src/SideNav/__tests__/SideNavRailMotion.interaction.browser.spec.ts +176 -51
  424. package/src/Skeleton/Skeleton.tsx +3 -1
  425. package/src/Slider/Slider.test.tsx +31 -0
  426. package/src/Slider/Slider.tsx +8 -3
  427. package/src/Slider/__tests__/Slider.a11y.chromium.spec.ts +19 -7
  428. package/src/Spinner/Spinner.tsx +5 -3
  429. package/src/Stack/Stack.tsx +1 -1
  430. package/src/Stack/StackItem.tsx +1 -1
  431. package/src/TabList/TabList.test.tsx +58 -4
  432. package/src/TabList/TabList.tsx +16 -1
  433. package/src/TabList/__tests__/TabPressPointer.interaction.browser.spec.ts +163 -0
  434. package/src/Table/__tests__/Table.a11y.chromium.spec.ts +18 -6
  435. package/src/Table/plugins/columnResize/useTableColumnResize.test.tsx +22 -0
  436. package/src/Table/plugins/columnResize/useTableColumnResize.tsx +8 -4
  437. package/src/Text/Text.tsx +1 -1
  438. package/src/Text/useTruncation.test.tsx +128 -1
  439. package/src/Text/useTruncation.ts +23 -5
  440. package/src/TextArea/TextArea.spec.md +10 -13
  441. package/src/TextArea/TextArea.test.tsx +60 -0
  442. package/src/TextArea/TextArea.tsx +15 -1
  443. package/src/TextInput/TextInput.test.tsx +21 -0
  444. package/src/TextInput/TextInput.tsx +3 -1
  445. package/src/TimeInput/NativeTimeInput.test.tsx +17 -0
  446. package/src/TimeInput/Presentation.test.tsx +21 -0
  447. package/src/TimeInput/TimeInput.doc.mjs +8 -8
  448. package/src/TimeInput/TimeInput.spec.md +45 -48
  449. package/src/TimeInput/TimeInput.test.tsx +76 -0
  450. package/src/TimeInput/TimeInput.tsx +36 -18
  451. package/src/TimeInput/TouchTimeField.tsx +4 -6
  452. package/src/Timestamp/Timestamp.spec.md +6 -12
  453. package/src/Timestamp/Timestamp.test.tsx +30 -5
  454. package/src/Timestamp/Timestamp.tsx +6 -2
  455. package/src/Timestamp/TimestampHoverCard.tsx +4 -4
  456. package/src/Toast/Toast.spec.md +14 -20
  457. package/src/Toast/Toast.tsx +104 -36
  458. package/src/Toast/ToastViewport.test.tsx +719 -1
  459. package/src/Toast/ToastViewport.tsx +100 -50
  460. package/src/Tokenizer/Tokenizer.spec.md +5 -3
  461. package/src/Tokenizer/Tokenizer.test.tsx +68 -0
  462. package/src/Tokenizer/Tokenizer.tsx +14 -2
  463. package/src/Tokenizer/TokenizerBottomSheet.test.tsx +15 -4
  464. package/src/Tokenizer/TokenizerBottomSheet.tsx +3 -3
  465. package/src/Toolbar/Toolbar.spec.md +5 -6
  466. package/src/Toolbar/Toolbar.test.tsx +30 -0
  467. package/src/Toolbar/Toolbar.tsx +2 -1
  468. package/src/Toolbar/__tests__/Toolbar.a11y.chromium.spec.ts +18 -6
  469. package/src/Tooltip/__tests__/Tooltip.a11y.chromium.spec.ts +18 -7
  470. package/src/TopNav/TopNav.test.tsx +27 -0
  471. package/src/TopNav/TopNavMegaMenu.test.tsx +21 -0
  472. package/src/TopNav/TopNavMegaMenu.tsx +4 -1
  473. package/src/TopNav/TopNavMenu.test.tsx +17 -0
  474. package/src/TopNav/TopNavMenu.tsx +1 -0
  475. package/src/Typeahead/Typeahead.test.tsx +40 -0
  476. package/src/Typeahead/Typeahead.tsx +12 -1
  477. package/src/__tests__/pressState.ts +8 -4
  478. package/src/gestures/GestureArena.ts +35 -0
  479. package/src/gestures/GestureHost.ts +2065 -0
  480. package/src/gestures/GestureRecognizer.ts +18 -0
  481. package/src/gestures/LongPressGestureRecognizer.ts +4 -0
  482. package/src/gestures/PanGestureRecognizer.ts +4 -0
  483. package/src/gestures/PinchGestureRecognizer.ts +148 -0
  484. package/src/gestures/ScreenEdgePanGestureRecognizer.ts +256 -0
  485. package/src/gestures/SwipeGestureRecognizer.ts +197 -0
  486. package/src/gestures/TapGestureRecognizer.ts +4 -0
  487. package/src/gestures/VelocityTracker.ts +10 -3
  488. package/src/gestures/__tests__/GestureHost.test.ts +2087 -0
  489. package/src/gestures/__tests__/PanGestureRecognizer.test.ts +4 -4
  490. package/src/gestures/__tests__/PinchGestureRecognizer.test.ts +74 -0
  491. package/src/gestures/__tests__/ScreenEdgePanGestureRecognizer.test.ts +498 -0
  492. package/src/gestures/__tests__/SwipeGestureRecognizer.test.ts +108 -0
  493. package/src/gestures/__tests__/arena.test.ts +5 -0
  494. package/src/gestures/__tests__/arenaPinchSwipeEdge.test.ts +193 -0
  495. package/src/gestures/__tests__/browser/build-fixture.mjs +46 -0
  496. package/src/gestures/__tests__/browser/fixture.ts +307 -0
  497. package/src/gestures/__tests__/browser/gestures.interaction.browser.spec.ts +1137 -0
  498. package/src/gestures/__tests__/browserNegotiation.test.ts +293 -0
  499. package/src/gestures/__tests__/haptics.test.ts +187 -0
  500. package/src/gestures/__tests__/harness.ts +21 -2
  501. package/src/gestures/__tests__/recognizerKind.test.ts +78 -0
  502. package/src/gestures/__tests__/touchActionRule.test.ts +54 -0
  503. package/src/gestures/haptics.ts +203 -0
  504. package/src/gestures/nativeScroll.ts +277 -0
  505. package/src/gestures/touchAction.ts +191 -0
  506. package/src/gestures/touchActionRule.ts +157 -0
  507. package/src/gestures/types.ts +30 -9
  508. package/src/hooks/index.ts +5 -1
  509. package/src/hooks/modalAnnounce.ts +129 -72
  510. package/src/hooks/useAdaptivePresentation.ts +4 -1
  511. package/src/hooks/useAnnounce.doc.mjs +35 -3
  512. package/src/hooks/useAnnounce.replace.test.tsx +516 -0
  513. package/src/hooks/useAnnounce.ts +209 -102
  514. package/src/hooks/useAnnounceRenderedText.adopters.test.tsx +10 -1
  515. package/src/hooks/useAnnounceRenderedText.ts +17 -3
  516. package/src/hooks/useBusyAnnouncement.ts +7 -10
  517. package/src/hooks/useMenuHover.ts +15 -1
  518. package/src/i18n/generated-locales/en.generated.ts +6 -0
  519. package/src/i18n/generated-locales/pseudo.generated.ts +6 -0
  520. package/src/motion/README.md +11 -1
  521. package/src/motion/animator.test.ts +151 -3
  522. package/src/motion/animator.ts +149 -33
  523. package/src/theme/Theme.doc.mjs +1 -1
  524. package/src/theme/defineTheme.ts +117 -8
  525. package/src/theme/derivedVarRegistry.test.ts +4 -0
  526. package/src/theme/domainTokens/domainTokenDefaults.ts +19 -0
  527. package/src/theme/domainTokens/index.ts +6 -10
  528. package/src/theme/expandMotionScale.test.ts +1 -1
  529. package/src/theme/index.ts +5 -0
  530. package/src/theme/motionKnobs.ts +82 -0
  531. package/src/theme/resolveThemeValues.ts +68 -6
  532. package/src/theme/themeAdaptations.ts +52 -12
  533. package/src/theme/themeMotion.test.ts +620 -0
  534. package/src/theme/themeMotion.ts +221 -0
  535. package/src/theme/tokenReferences.ts +149 -0
  536. package/src/theme/tokens.stylex.ts +10 -0
  537. package/src/theme/tokens.ts +15 -158
  538. package/src/utils/focusReturn.ts +17 -6
  539. package/src/utils/getNodeText.test.ts +24 -0
  540. package/src/utils/getNodeText.ts +37 -0
  541. package/src/utils/interactionModality.test.ts +45 -1
  542. package/src/utils/interactionModality.ts +64 -5
  543. package/src/utils/interactionOverlay.stylex.ts +12 -3
  544. package/src/utils/plainDate.test.ts +90 -0
  545. package/src/utils/plainDate.ts +58 -3
  546. package/src/utils/presentation.test.ts +380 -0
  547. package/src/utils/presentation.ts +180 -0
  548. package/src/utils/pressFeedback.test.ts +138 -0
  549. package/src/utils/pressFeedback.ts +34 -11
  550. package/src/utils/pressPaintPriority.test.ts +80 -0
  551. package/src/utils/primaryClick.test.ts +38 -0
  552. package/src/utils/primaryClick.ts +28 -0
  553. package/src/utils/timeFormat.test.ts +204 -0
  554. package/src/utils/timeFormat.ts +314 -0
  555. package/src/utils/touchPresentation.stylex.ts +43 -0
  556. package/src/utils/touchPresentation.test.ts +140 -1
  557. package/src/utils/touchPresentation.ts +5 -3
  558. package/src/utils/unicodeDigits.test.ts +44 -0
  559. package/src/utils/unicodeDigits.ts +71 -0
@@ -0,0 +1,314 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file timeFormat.ts
5
+ * @input An ISO time or typed text, plus the provider's BCP 47 locale
6
+ * @output Exports resolveHourFormat, formatLocaleTime, and parseLocaleTime
7
+ * @position Internal shared helper for TimeInput and DateTimeInput; not part
8
+ * of the public surface
9
+ *
10
+ * Time of day as the locale writes it. The hour cycle, digits, separator, and
11
+ * day-period words all come from Intl rather than a table, so a field reads
12
+ * the same way `Timestamp` does beside it.
13
+ *
14
+ * The hour cycle is the locale's own: `en-US` and `ko-KR` read twelve-hour,
15
+ * `en-GB`, `de-DE`, and `vi-VN` read twenty-four-hour. A `-u-hc-` extension
16
+ * on the provider locale (`en-US-u-hc-h23`) carries an app's per-user
17
+ * preference through the same path, so every Astryx time honors it.
18
+ *
19
+ * The parser reads back what the formatter writes: the locale's digits, its
20
+ * hour-minute separator, and its day-period words, on either side of the time.
21
+ * Whatever is left goes through the shared English-tolerant parser, so "2:30
22
+ * PM" and "14:30" keep working in every locale.
23
+ *
24
+ * SYNC: When modified, update these files to stay in sync:
25
+ * - /packages/core/src/utils/timeFormat.test.ts
26
+ * - /packages/core/src/TimeInput/TimeInput.tsx
27
+ * - /packages/core/src/DateTimeInput/DateTimeInput.tsx
28
+ */
29
+
30
+ import type {Locale} from '../i18n/types';
31
+ import {parseISOTime, parseTimeInput, type ISOTimeString} from './timeParser';
32
+ import {INVISIBLE_CHARS, toAsciiDigits} from './unicodeDigits';
33
+
34
+ export type HourFormat = '12h' | '24h';
35
+
36
+ interface LocaleTimeSymbols {
37
+ hourFormat: HourFormat;
38
+ /**
39
+ * The text between hour and minute and between minute and second, trimmed:
40
+ * ":" nearly everywhere, "." in fi-FI, "h" and "min" in fr-CA. Read from
41
+ * both readings, because some locales write them differently: `as` writes
42
+ * "১৪:৩০" but "অপৰাহ্ন ২.৩০".
43
+ */
44
+ separators: string[];
45
+ /**
46
+ * Words the locale writes before or after the digits other than the day
47
+ * period, trimmed: "s" after fr-CA seconds, "kl." before nds-DE times, "ga"
48
+ * between an ee day period and its hour. Longest first.
49
+ */
50
+ edgeWords: string[];
51
+ /** Every day-period word the locale writes, longest first. */
52
+ dayPeriods: {word: string; isPM: boolean}[];
53
+ /**
54
+ * The locale's twelve-hour reading writes 02:00 and 14:00 the same (fr-CM
55
+ * writes no day period), so its twelve-hour text is English instead.
56
+ */
57
+ twelveHourIsAmbiguous: boolean;
58
+ }
59
+
60
+ const symbolsByLocale = new Map<string, LocaleTimeSymbols>();
61
+
62
+ // The space family Intl writes between a time and its day period ("2:30 PM"
63
+ // uses U+202F). A typed field shows a plain space so people can edit it.
64
+ const SPACES = /[\u00A0\u2007\u202F]/g;
65
+ // What may sit on a peeled word's inner side: a digit (digits are already
66
+ // ASCII here), whitespace, or nothing.
67
+ const WORD_BOUNDARY = /^[\d\s]?$/;
68
+
69
+ function utcDate(hour: number, minute: number, second: number): Date {
70
+ return new Date(Date.UTC(2000, 0, 1, hour, minute, second));
71
+ }
72
+
73
+ function timeFormatter(
74
+ locale: Locale,
75
+ hourFormat: HourFormat,
76
+ includeSeconds: boolean,
77
+ ): Intl.DateTimeFormat {
78
+ const options: Intl.DateTimeFormatOptions = {
79
+ hour: hourFormat === '12h' ? 'numeric' : '2-digit',
80
+ minute: '2-digit',
81
+ second: includeSeconds ? '2-digit' : undefined,
82
+ // `hourCycle`, not `hour12`: `hour12: true` resolves to h11 in ja-JP and
83
+ // writes noon as "午後0:30".
84
+ hourCycle: hourFormat === '12h' ? 'h12' : 'h23',
85
+ timeZone: 'UTC',
86
+ };
87
+ try {
88
+ return new Intl.DateTimeFormat(locale, options);
89
+ } catch {
90
+ return new Intl.DateTimeFormat('en', options);
91
+ }
92
+ }
93
+
94
+ function getLocaleTimeSymbols(locale: Locale): LocaleTimeSymbols {
95
+ let symbols = symbolsByLocale.get(locale);
96
+ if (symbols !== undefined) {
97
+ return symbols;
98
+ }
99
+
100
+ let hourFormat: HourFormat;
101
+ let resolved: Intl.ResolvedDateTimeFormatOptions;
102
+ try {
103
+ resolved = new Intl.DateTimeFormat(locale, {
104
+ hour: 'numeric',
105
+ }).resolvedOptions();
106
+ } catch {
107
+ // A malformed tag formats as English everywhere else in this module.
108
+ resolved = new Intl.DateTimeFormat('en', {
109
+ hour: 'numeric',
110
+ }).resolvedOptions();
111
+ }
112
+ if (resolved.hourCycle !== undefined) {
113
+ hourFormat =
114
+ resolved.hourCycle === 'h11' || resolved.hourCycle === 'h12'
115
+ ? '12h'
116
+ : '24h';
117
+ } else {
118
+ // Engines that leave hourCycle unresolved still write a day period for a
119
+ // twelve-hour locale when no cycle is forced.
120
+ let ambient: Intl.DateTimeFormat;
121
+ try {
122
+ ambient = new Intl.DateTimeFormat(locale, {hour: 'numeric'});
123
+ } catch {
124
+ ambient = new Intl.DateTimeFormat('en', {hour: 'numeric'});
125
+ }
126
+ hourFormat = ambient
127
+ .formatToParts(utcDate(13, 0, 0))
128
+ .some(part => part.type === 'dayPeriod')
129
+ ? '12h'
130
+ : '24h';
131
+ }
132
+
133
+ // Literals of every reading this module writes: twelve- and twenty-four-hour,
134
+ // with and without seconds. A literal between two numbers is a separator;
135
+ // one outside them is an edge word.
136
+ const separatorSet = new Set<string>();
137
+ const edgeSet = new Set<string>();
138
+ for (const cycle of ['12h', '24h'] as const) {
139
+ for (const withSeconds of [false, true]) {
140
+ const parts = timeFormatter(locale, cycle, withSeconds).formatToParts(
141
+ utcDate(13, 30, 5),
142
+ );
143
+ const isNumber = (part: Intl.DateTimeFormatPart) =>
144
+ part.type === 'hour' ||
145
+ part.type === 'minute' ||
146
+ part.type === 'second';
147
+ const first = parts.findIndex(isNumber);
148
+ const last = parts.length - 1 - [...parts].reverse().findIndex(isNumber);
149
+ parts.forEach((part, index) => {
150
+ if (part.type !== 'literal') {
151
+ return;
152
+ }
153
+ const text = normalizeText(part.value).trim();
154
+ if (text === '' || text === ':') {
155
+ return;
156
+ }
157
+ (index > first && index < last ? separatorSet : edgeSet).add(text);
158
+ });
159
+ }
160
+ }
161
+ const separators = [...separatorSet];
162
+ const edgeWords = [...edgeSet].sort((a, b) => b.length - a.length);
163
+
164
+ // Every hour, because some locales name several periods across the day
165
+ // (flexible day periods). A word that appears on both sides of noon cannot
166
+ // say which half it means, so it is left out.
167
+ const twelveHour = timeFormatter(locale, '12h', false);
168
+ const sides = new Map<string, Set<boolean>>();
169
+ for (let hour = 0; hour < 24; hour++) {
170
+ const word = twelveHour
171
+ .formatToParts(utcDate(hour, 0, 0))
172
+ .find(part => part.type === 'dayPeriod')?.value;
173
+ if (word === undefined) {
174
+ continue;
175
+ }
176
+ const key = normalizeText(word).trim();
177
+ if (key === '') {
178
+ continue;
179
+ }
180
+ const seen = sides.get(key) ?? new Set<boolean>();
181
+ seen.add(hour >= 12);
182
+ sides.set(key, seen);
183
+ }
184
+ const dayPeriods = [...sides]
185
+ .filter(([, seen]) => seen.size === 1)
186
+ .map(([word, seen]) => ({word, isPM: seen.has(true)}))
187
+ .sort((a, b) => b.word.length - a.word.length);
188
+
189
+ const twelveHourIsAmbiguous =
190
+ normalizeText(twelveHour.format(utcDate(2, 0, 0))) ===
191
+ normalizeText(twelveHour.format(utcDate(14, 0, 0)));
192
+
193
+ symbols = {
194
+ hourFormat,
195
+ separators,
196
+ edgeWords,
197
+ dayPeriods,
198
+ twelveHourIsAmbiguous,
199
+ };
200
+ symbolsByLocale.set(locale, symbols);
201
+ return symbols;
202
+ }
203
+
204
+ function normalizeText(text: string): string {
205
+ const folded = text
206
+ .normalize('NFKC')
207
+ .replace(INVISIBLE_CHARS, '')
208
+ .replace(SPACES, ' ');
209
+ return (toAsciiDigits(folded) ?? folded).toLowerCase();
210
+ }
211
+
212
+ function escapeRegExp(text: string): string {
213
+ return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
214
+ }
215
+
216
+ /**
217
+ * The hour format a field shows: the caller's explicit choice, else the
218
+ * locale's hour cycle (including a `-u-hc-` extension on the tag).
219
+ */
220
+ export function resolveHourFormat(
221
+ locale: Locale,
222
+ hourFormat?: HourFormat,
223
+ ): HourFormat {
224
+ return hourFormat ?? getLocaleTimeSymbols(locale).hourFormat;
225
+ }
226
+
227
+ /**
228
+ * Formats an ISO time as the locale writes it, in the given hour format.
229
+ * en-US: "14:30" → "2:30 PM"; de-DE 24h: "14:30"; ko-KR 12h: "오후 2:30".
230
+ * Returns '' for an empty or malformed time.
231
+ */
232
+ export function formatLocaleTime(
233
+ time: ISOTimeString | undefined,
234
+ locale: Locale,
235
+ hourFormat: HourFormat,
236
+ includeSeconds: boolean = false,
237
+ ): string {
238
+ if (!time) {
239
+ return '';
240
+ }
241
+ const parsed = parseISOTime(time);
242
+ if (!parsed) {
243
+ return '';
244
+ }
245
+ const formatLocale =
246
+ hourFormat === '12h' && getLocaleTimeSymbols(locale).twelveHourIsAmbiguous
247
+ ? 'en'
248
+ : locale;
249
+ return timeFormatter(formatLocale, hourFormat, includeSeconds)
250
+ .format(utcDate(parsed.hour, parsed.minute, parsed.second))
251
+ .replace(SPACES, ' ');
252
+ }
253
+
254
+ /**
255
+ * Parses typed text into an ISO time, accepting the locale's digits,
256
+ * separator, and day-period words as well as everything `parseTimeInput`
257
+ * accepts. Returns null when no reading fits.
258
+ */
259
+ export function parseLocaleTime(
260
+ input: string,
261
+ locale: Locale,
262
+ includeSeconds: boolean = false,
263
+ ): ISOTimeString | null {
264
+ if (!input) {
265
+ return null;
266
+ }
267
+ const {separators, edgeWords, dayPeriods} = getLocaleTimeSymbols(locale);
268
+ let text = normalizeText(input).trim();
269
+
270
+ // Peel the day period and edge words off both ends, in whatever order the
271
+ // locale writes them ("ŋdi ga 2:30", "kl. 2.30 pm").
272
+ let isPM: boolean | null = null;
273
+ // A word counts only when a digit, whitespace, or nothing sits on its inner
274
+ // side, so gd's "m" (morning) is not read out of an English "pm" or "p.m".
275
+ const strip = (word: string) => {
276
+ if (text.startsWith(word) && WORD_BOUNDARY.test(text.charAt(word.length))) {
277
+ text = text.slice(word.length).trim();
278
+ return true;
279
+ }
280
+ if (
281
+ text.endsWith(word) &&
282
+ WORD_BOUNDARY.test(text.charAt(text.length - word.length - 1))
283
+ ) {
284
+ text = text.slice(0, -word.length).trim();
285
+ return true;
286
+ }
287
+ return false;
288
+ };
289
+ for (let peeled = true; peeled;) {
290
+ peeled = false;
291
+ if (isPM === null) {
292
+ const period = dayPeriods.find(({word}) => strip(word));
293
+ if (period !== undefined) {
294
+ isPM = period.isPM;
295
+ peeled = true;
296
+ }
297
+ }
298
+ if (edgeWords.some(strip)) {
299
+ peeled = true;
300
+ }
301
+ }
302
+
303
+ for (const separator of separators) {
304
+ text = text.replace(
305
+ new RegExp(`(\\d)\\s*${escapeRegExp(separator)}\\s*(?=\\d)`, 'g'),
306
+ '$1:',
307
+ );
308
+ }
309
+
310
+ if (isPM !== null) {
311
+ text = `${text} ${isPM ? 'pm' : 'am'}`;
312
+ }
313
+ return parseTimeInput(text, includeSeconds);
314
+ }
@@ -0,0 +1,43 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file touchPresentation.stylex.ts
5
+ * @input Uses StyleX defineConsts
6
+ * @output Exports touchKeys: the touch presentation resolver's queries as
7
+ * StyleX at-rule keys
8
+ * @position The reference spellings of the touch, compact and iOS-gate
9
+ * conditions. Core styles write these as literal keys wherever they need
10
+ * them (`spec:AST-094` FR13, `spec:AST-012` FR9), and a test pins each
11
+ * literal to these values; utils/touchPresentation.ts holds the same
12
+ * queries for script (matchMedia)
13
+ *
14
+ * These are the spellings to match. A style that changes with these
15
+ * conditions writes the same literal key (`'@media (pointer: coarse)'`, the
16
+ * iOS gate as that media key outside `'@supports (-webkit-touch-callout:
17
+ * none)'`), and a test pins every literal in core to these values. Do not use
18
+ * an imported key as a computed StyleX key: it compiles to a different
19
+ * priority than the literal (6000 against 3200) and reorders the cascade.
20
+ * The iOS supports gate is only for a style iOS WebKit itself requires (the
21
+ * 16px input floor), never a behaviour.
22
+ *
23
+ * SYNC: When modified, update touchPresentation.ts and
24
+ * touchPresentation.test.ts.
25
+ */
26
+
27
+ import * as stylex from '@stylexjs/stylex';
28
+
29
+ export const touchKeys = stylex.defineConsts({
30
+ /** The primary pointer is coarse (TOUCH_QUERY). */
31
+ touch: '@media (pointer: coarse)',
32
+ /** The viewport is compact (COMPACT_QUERY, `spec:AST-012` FR9). */
33
+ compact: '@media (width < 768px), (height < 500px)',
34
+ /** Both: a presentation such as a sheet in place of a popover. */
35
+ compactTouch:
36
+ '@media (width < 768px) and (pointer: coarse), (height < 500px) and (pointer: coarse)',
37
+ /**
38
+ * The iOS WebKit gate, inside `touch` (IOS_SUPPORTS_QUERY): only for a
39
+ * style iOS WebKit itself requires (the 16px input floor), never a
40
+ * behaviour; touch behaviour is one model on every touch device.
41
+ */
42
+ iosSupports: '@supports (-webkit-touch-callout: none)',
43
+ });
@@ -22,6 +22,7 @@ import {
22
22
  COMPACT_TOUCH_PRESENTATION_QUERY,
23
23
  useAdaptivePresentation,
24
24
  } from '../hooks/useAdaptivePresentation';
25
+ import {reducedMotionKeys} from '../motion/reducedMotion.stylex';
25
26
  import {DEFAULT_COMPACT_DEFINITION} from '../theme/themeAdaptations';
26
27
  import {Theme, defineTheme} from '../theme';
27
28
  import {
@@ -33,6 +34,7 @@ import {
33
34
  readTouchPresentation,
34
35
  useTouchPresentation,
35
36
  } from './touchPresentation';
37
+ import {touchKeys} from './touchPresentation.stylex';
36
38
 
37
39
  /**
38
40
  * A device: what its primary pointer is, how big its viewport is, and
@@ -90,6 +92,32 @@ afterEach(() => {
90
92
  vi.unstubAllGlobals();
91
93
  });
92
94
 
95
+ /**
96
+ * The Levenshtein distance between two strings, or more than `limit` as soon
97
+ * as it must exceed it: how many characters a spelling is off another.
98
+ */
99
+ function editDistance(a: string, b: string, limit: number): number {
100
+ if (Math.abs(a.length - b.length) > limit) {
101
+ return limit + 1;
102
+ }
103
+ let previous = Array.from({length: b.length + 1}, (_, j) => j);
104
+ for (let i = 1; i <= a.length; i++) {
105
+ const current = [i];
106
+ for (let j = 1; j <= b.length; j++) {
107
+ current[j] = Math.min(
108
+ previous[j] + 1,
109
+ current[j - 1] + 1,
110
+ previous[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1),
111
+ );
112
+ }
113
+ if (Math.min(...current) > limit) {
114
+ return limit + 1;
115
+ }
116
+ previous = current;
117
+ }
118
+ return previous[b.length];
119
+ }
120
+
93
121
  describe('touch presentation', () => {
94
122
  it('keys touch on the primary pointer and compact on the width', () => {
95
123
  const {result} = renderHook(() => useTouchPresentation());
@@ -181,6 +209,116 @@ describe('touch presentation', () => {
181
209
  });
182
210
  });
183
211
 
212
+ it('holds the same keys the resolver defines', () => {
213
+ expect(touchKeys.touch).toBe(`@media ${TOUCH_QUERY}`);
214
+ expect(touchKeys.compact).toBe(`@media ${COMPACT_QUERY}`);
215
+ expect(touchKeys.compactTouch).toBe(`@media ${COMPACT_TOUCH_QUERY}`);
216
+ expect(touchKeys.iosSupports).toBe(`@supports ${IOS_SUPPORTS_QUERY}`);
217
+ expect(IOS_TOUCH_STYLE_KEYS).toEqual([
218
+ touchKeys.touch,
219
+ touchKeys.iosSupports,
220
+ ]);
221
+ });
222
+
223
+ it('keeps every touch and Reduce Motion key literal in core: no computed StyleX key', () => {
224
+ // An imported defineConsts at-rule key compiles to a different StyleX
225
+ // priority than the same literal (6000 vs 3200), which reorders the
226
+ // cascade; core spells the keys and matches them to the constants.
227
+ const root = path.resolve(__dirname, '..');
228
+ const computed: string[] = [];
229
+ const walk = (dir: string): void => {
230
+ for (const entry of fs.readdirSync(dir, {withFileTypes: true})) {
231
+ const full = path.join(dir, entry.name);
232
+ if (entry.isDirectory()) {
233
+ if (entry.name !== '__tests__' && entry.name !== 'node_modules') {
234
+ walk(full);
235
+ }
236
+ } else if (
237
+ /\.(ts|tsx)$/.test(entry.name) &&
238
+ !/\.test\.|\.spec\./.test(entry.name)
239
+ ) {
240
+ fs.readFileSync(full, 'utf8')
241
+ .split('\n')
242
+ .forEach((line, index) => {
243
+ if (
244
+ !/^\s*(\*|\/\/)/.test(line) &&
245
+ /\[(touchKeys|reducedMotionKeys)\.[a-zA-Z]+\]\s*:/.test(line)
246
+ ) {
247
+ computed.push(`${path.relative(root, full)}:${index + 1}`);
248
+ }
249
+ });
250
+ }
251
+ }
252
+ };
253
+ walk(root);
254
+ expect(computed).toEqual([]);
255
+ });
256
+
257
+ it('keeps every quoted at-rule key in core that names the pointer, the touch callout or a compact size, or that is a few characters off a reference spelling, one of the reference spellings', () => {
258
+ // Every quoted string that starts with `@` is read, whatever its at-rule
259
+ // is spelled. Two rules, so no drift depends on which character moved:
260
+ // - one that names the pointer or the touch callout (any word of either
261
+ // query, any case), or a compact size with its breakpoint, is one of
262
+ // the resolver's own spellings or a query the presentation does not
263
+ // decide (a second pointer, a fine pointer, Reduce Motion split by
264
+ // pointer);
265
+ // - one within three characters of any of those spellings, case aside,
266
+ // is that spelling exactly: a capital, a digit or a typo anywhere, in
267
+ // the at-rule, a feature or a value, fails.
268
+ const pointerKeys = new Set<string>([
269
+ touchKeys.touch,
270
+ touchKeys.compactTouch,
271
+ touchKeys.iosSupports,
272
+ '@media (any-pointer: coarse)',
273
+ '@media (pointer: fine)',
274
+ reducedMotionKeys.fade,
275
+ reducedMotionKeys.instant,
276
+ ]);
277
+ const references = new Set<string>([...pointerKeys, touchKeys.compact]);
278
+ const lowered = [...references].map(reference => reference.toLowerCase());
279
+ const root = path.resolve(__dirname, '..');
280
+ const drifted: string[] = [];
281
+ let pointerLiterals = 0;
282
+ const walk = (dir: string): void => {
283
+ for (const entry of fs.readdirSync(dir, {withFileTypes: true})) {
284
+ const full = path.join(dir, entry.name);
285
+ if (entry.isDirectory()) {
286
+ if (entry.name !== '__tests__' && entry.name !== 'node_modules') {
287
+ walk(full);
288
+ }
289
+ } else if (
290
+ /\.(ts|tsx)$/.test(entry.name) &&
291
+ !/\.(test|spec|stories)\./.test(entry.name)
292
+ ) {
293
+ const source = fs.readFileSync(full, 'utf8');
294
+ for (const match of source.matchAll(/'(@[^'\n]*)'/g)) {
295
+ const key = match[1];
296
+ if (references.has(key)) {
297
+ if (pointerKeys.has(key)) {
298
+ pointerLiterals++;
299
+ }
300
+ continue;
301
+ }
302
+ const names =
303
+ /pointer|coarse|fine|touch|callout/i.test(key) ||
304
+ (/\b(width|height)\b/i.test(key) && /\b(768|500)px\b/.test(key));
305
+ const lower = key.toLowerCase();
306
+ const isNear = lowered.some(
307
+ reference => editDistance(lower, reference, 3) <= 3,
308
+ );
309
+ if (names || isNear) {
310
+ drifted.push(`${path.relative(root, full)}: ${key}`);
311
+ }
312
+ }
313
+ }
314
+ }
315
+ };
316
+ walk(root);
317
+ expect(drifted).toEqual([]);
318
+ // Core writes the touch key as a literal in many places.
319
+ expect(pointerLiterals).toBeGreaterThan(50);
320
+ });
321
+
184
322
  it('keeps every iOS gate in core spelled and nested as the resolver', () => {
185
323
  // The gate is the media query outside and the supports query inside; a
186
324
  // single supports query that names the pointer never matches anywhere.
@@ -201,7 +339,8 @@ describe('touch presentation', () => {
201
339
  } else if (
202
340
  /\.(ts|tsx)$/.test(entry.name) &&
203
341
  !/\.test\.|\.spec\./.test(entry.name) &&
204
- entry.name !== 'touchPresentation.ts'
342
+ entry.name !== 'touchPresentation.ts' &&
343
+ entry.name !== 'touchPresentation.stylex.ts'
205
344
  ) {
206
345
  const lines = fs.readFileSync(full, 'utf8').split('\n');
207
346
  lines.forEach((line, index) => {
@@ -46,9 +46,11 @@
46
46
  * test keeps core's compact-touch keys identical to COMPACT_TOUCH_QUERY and
47
47
  * every touch-callout key spelled and nested as above. The iOS style gate
48
48
  * is only for a style iOS WebKit itself requires (core's 16px input floor);
49
- * it never selects a behaviour. The keys are literal because the Astryx
50
- * StyleX build does not resolve a key shared across files through
51
- * `defineConsts`. The hook is for behaviour. It answers the server default
49
+ * it never selects a behaviour. Core spells the keys literally: an imported
50
+ * `defineConsts` key compiles to a different StyleX priority than the same
51
+ * literal, which would reorder the cascade. `touchKeys`
52
+ * (touchPresentation.stylex.ts, internal to core) holds the same keys, and a
53
+ * test keeps every literal equal to them. The hook is for behaviour. It answers the server default
52
54
  * (not touch, not compact) until hydrated unless the caller passes a server
53
55
  * hint, and follows the pointer and size when they change (a tablet docking
54
56
  * a mouse).
@@ -0,0 +1,44 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file unicodeDigits.test.ts
5
+ * @input Uses vitest and the unicodeDigits helpers
6
+ * @output Unit tests for digit values across scripts
7
+ * @position Testing; validates utils/unicodeDigits.ts
8
+ *
9
+ * SYNC: When unicodeDigits.ts changes, update tests to match new behavior
10
+ */
11
+
12
+ import {describe, expect, it} from 'vitest';
13
+ import {INVISIBLE_CHARS, digitValue, toAsciiDigits} from './unicodeDigits';
14
+
15
+ describe('digitValue', () => {
16
+ it.each([
17
+ ['7', 7],
18
+ ['٧', 7], // Arabic-Indic
19
+ ['۷', 7], // Extended Arabic-Indic
20
+ ['७', 7], // Devanagari
21
+ ['৭', 7], // Bengali
22
+ ['7', 7], // full-width
23
+ ])('reads %s as %i', (char, value) => {
24
+ expect(digitValue(char)).toBe(value);
25
+ });
26
+
27
+ it('returns null for a non-digit', () => {
28
+ expect(digitValue('a')).toBeNull();
29
+ expect(digitValue('')).toBeNull();
30
+ });
31
+ });
32
+
33
+ describe('toAsciiDigits', () => {
34
+ it('rewrites digits and leaves everything else', () => {
35
+ expect(toAsciiDigits('٢:٣٠ م')).toBe('2:30 م');
36
+ expect(toAsciiDigits('१२,३४५.६')).toBe('12,345.6');
37
+ });
38
+ });
39
+
40
+ describe('INVISIBLE_CHARS', () => {
41
+ it('strips bidi marks and zero-width characters', () => {
42
+ expect('\u200F١٢\u061C\uFEFF'.replace(INVISIBLE_CHARS, '')).toBe('١٢');
43
+ });
44
+ });
@@ -0,0 +1,71 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file unicodeDigits.ts
5
+ * @input Text in any digit script
6
+ * @output Exports INVISIBLE_CHARS, digitValue, and toAsciiDigits
7
+ * @position Internal shared utility for the locale-aware parsers
8
+ * (NumberInput/numberParser.ts, utils/timeFormat.ts); not part of the
9
+ * public surface
10
+ *
11
+ * Locale-independent: a digit's value is a Unicode property, not a locale
12
+ * preference, so this needs no Intl and no locale.
13
+ *
14
+ * SYNC: When modified, update these files to stay in sync:
15
+ * - /packages/core/src/utils/unicodeDigits.test.ts
16
+ */
17
+
18
+ // Built at runtime rather than written as a literal: Babel's
19
+ // transform-unicode-property-regex rewrites a `\p{...}` regex LITERAL into an
20
+ // enumerated character class, and the copy bundled with Next rejects the
21
+ // General_Category short names, failing the sandbox build. Property escapes are
22
+ // ES2018 and need no transform in any browser this package supports.
23
+ const DECIMAL_DIGIT = new RegExp('\\p{Nd}', 'u');
24
+
25
+ /**
26
+ * Zero-width joiners, bidi marks and isolates (which Intl writes around RTL
27
+ * numbers and day periods), and the BOM Excel prepends.
28
+ */
29
+ export const INVISIBLE_CHARS =
30
+ /[\u200B-\u200D\u200E\u200F\u061C\u2066-\u2069\uFEFF]/g;
31
+
32
+ /**
33
+ * Value of any Unicode decimal digit. Each digit script lays its ten digits
34
+ * out consecutively, so walking back to the script's zero derives the value
35
+ * for Arabic-Indic, Devanagari, full-width and the rest without shipping a
36
+ * table of them. Returns null for a non-digit, and in the one shape the walk
37
+ * cannot resolve: two digit blocks adjacent in code space (the mathematical
38
+ * alphanumerics).
39
+ */
40
+ export function digitValue(char: string): number | null {
41
+ const codePoint = char.codePointAt(0);
42
+ if (codePoint == null || !DECIMAL_DIGIT.test(char)) {
43
+ return null;
44
+ }
45
+ for (let zero = codePoint; codePoint - zero < 10; zero--) {
46
+ if (!DECIMAL_DIGIT.test(String.fromCodePoint(zero - 1))) {
47
+ return codePoint - zero;
48
+ }
49
+ }
50
+ return null;
51
+ }
52
+
53
+ /**
54
+ * Rewrites every decimal digit as its ASCII digit, leaving other characters
55
+ * alone. Returns null when a digit's value cannot be resolved.
56
+ */
57
+ export function toAsciiDigits(text: string): string | null {
58
+ let out = '';
59
+ for (const char of text) {
60
+ if (!DECIMAL_DIGIT.test(char)) {
61
+ out += char;
62
+ continue;
63
+ }
64
+ const value = digitValue(char);
65
+ if (value == null) {
66
+ return null;
67
+ }
68
+ out += String(value);
69
+ }
70
+ return out;
71
+ }