@astryxdesign/core 0.7.5 → 0.7.6-canary.5cd7a15

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 (463) 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/DateInput/DateInput.d.ts.map +1 -1
  18. package/dist/DateInput/DateInput.js +12 -4
  19. package/dist/DateInput/MonthScroller.d.ts.map +1 -1
  20. package/dist/DateInput/MonthScroller.js +101 -15
  21. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  22. package/dist/DateInput/TouchDateField.js +8 -3
  23. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  24. package/dist/DateRangeInput/DateRangeInput.js +1 -1
  25. package/dist/DateTimeInput/DateTimeInput.d.ts +5 -2
  26. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  27. package/dist/DateTimeInput/DateTimeInput.js +23 -12
  28. package/dist/DateTimeInput/NativeTimeSegment.d.ts.map +1 -1
  29. package/dist/DateTimeInput/NativeTimeSegment.js +5 -4
  30. package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
  31. package/dist/DateTimeInput/TouchDateTimeField.js +4 -3
  32. package/dist/Dialog/Dialog.d.ts.map +1 -1
  33. package/dist/Dialog/Dialog.js +34 -9
  34. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  35. package/dist/Dialog/DialogHeader.js +5 -4
  36. package/dist/Divider/Divider.d.ts.map +1 -1
  37. package/dist/Divider/Divider.js +2 -1
  38. package/dist/Drawer/Drawer.d.ts +1 -0
  39. package/dist/Drawer/Drawer.d.ts.map +1 -1
  40. package/dist/Drawer/Drawer.js +7 -2
  41. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  42. package/dist/DropdownMenu/DropdownMenu.js +4 -1
  43. package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts.map +1 -1
  44. package/dist/DropdownMenu/MenuBottomSheetActionList.js +6 -5
  45. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts +10 -1
  46. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts.map +1 -1
  47. package/dist/DropdownMenu/lazyMenuBottomSheet.js +16 -2
  48. package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
  49. package/dist/DropdownMenu/renderDropdownItems.js +21 -16
  50. package/dist/EmptyState/EmptyState.d.ts.map +1 -1
  51. package/dist/EmptyState/EmptyState.js +2 -1
  52. package/dist/Field/FieldLabel.d.ts +1 -1
  53. package/dist/Field/FieldLabel.d.ts.map +1 -1
  54. package/dist/Field/FieldLabel.js +4 -4
  55. package/dist/Field/InputClearButton.js +3 -3
  56. package/dist/Field/PanelSearchInput.js +2 -2
  57. package/dist/FieldStatus/FieldStatus.js +2 -2
  58. package/dist/FileInput/FileInput.d.ts.map +1 -1
  59. package/dist/FileInput/FileInput.js +7 -1
  60. package/dist/Heading/Heading.js +1 -1
  61. package/dist/Icon/Icon.js +1 -1
  62. package/dist/Indicator/CheckIndicator.d.ts.map +1 -1
  63. package/dist/Indicator/CheckIndicator.js +2 -1
  64. package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -1
  65. package/dist/Indicator/CheckboxIndicator.js +3 -1
  66. package/dist/Indicator/RadioIndicator.d.ts.map +1 -1
  67. package/dist/Indicator/RadioIndicator.js +3 -1
  68. package/dist/Item/Item.d.ts.map +1 -1
  69. package/dist/Item/Item.js +2 -1
  70. package/dist/Item/ItemSwipeLayer.js +1 -1
  71. package/dist/Layout/Layout.js +1 -1
  72. package/dist/Layout/LayoutContent.js +1 -1
  73. package/dist/Layout/LayoutFooter.js +1 -1
  74. package/dist/Layout/LayoutHeader.js +1 -1
  75. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  76. package/dist/Lightbox/Lightbox.js +5 -0
  77. package/dist/Lightbox/LightboxViewport.a11y.browser.spec.js +5 -4
  78. package/dist/List/List.js +1 -1
  79. package/dist/List/ListItem.js +3 -3
  80. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  81. package/dist/MobileNav/MobileNav.js +7 -2
  82. package/dist/MultiSelector/MultiSelector.d.ts +1 -1
  83. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  84. package/dist/MultiSelector/MultiSelector.js +5 -2
  85. package/dist/NumberInput/NumberInput.d.ts +3 -1
  86. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  87. package/dist/NumberInput/NumberInput.js +3 -3
  88. package/dist/NumberInput/numberParser.d.ts +3 -0
  89. package/dist/NumberInput/numberParser.d.ts.map +1 -1
  90. package/dist/NumberInput/numberParser.js +7 -44
  91. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  92. package/dist/ProgressBar/ProgressBar.js +16 -12
  93. package/dist/Resizable/useResizable.d.ts.map +1 -1
  94. package/dist/Resizable/useResizable.js +28 -2
  95. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  96. package/dist/SegmentedControl/SegmentedControlItem.js +4 -1
  97. package/dist/Selector/useSelectorPresentation.d.ts +8 -1
  98. package/dist/Selector/useSelectorPresentation.d.ts.map +1 -1
  99. package/dist/Selector/useSelectorPresentation.js +20 -4
  100. package/dist/Slider/Slider.d.ts.map +1 -1
  101. package/dist/Slider/Slider.js +7 -1
  102. package/dist/Spinner/Spinner.js +2 -2
  103. package/dist/Stack/Stack.js +1 -1
  104. package/dist/Stack/StackItem.js +1 -1
  105. package/dist/TabList/TabList.d.ts.map +1 -1
  106. package/dist/TabList/TabList.js +16 -1
  107. package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
  108. package/dist/Table/plugins/columnResize/useTableColumnResize.js +9 -1
  109. package/dist/Text/Text.js +1 -1
  110. package/dist/Text/useTruncation.d.ts.map +1 -1
  111. package/dist/Text/useTruncation.js +23 -5
  112. package/dist/TextArea/TextArea.d.ts +1 -1
  113. package/dist/TextArea/TextArea.d.ts.map +1 -1
  114. package/dist/TextArea/TextArea.js +13 -2
  115. package/dist/TextInput/TextInput.d.ts.map +1 -1
  116. package/dist/TextInput/TextInput.js +3 -3
  117. package/dist/TimeInput/TimeInput.d.ts +6 -2
  118. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  119. package/dist/TimeInput/TimeInput.js +21 -14
  120. package/dist/TimeInput/TouchTimeField.d.ts.map +1 -1
  121. package/dist/TimeInput/TouchTimeField.js +5 -4
  122. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  123. package/dist/Timestamp/Timestamp.js +2 -2
  124. package/dist/Timestamp/TimestampHoverCard.js +4 -4
  125. package/dist/Toast/Toast.d.ts.map +1 -1
  126. package/dist/Toast/Toast.js +60 -20
  127. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  128. package/dist/Toast/ToastViewport.js +82 -51
  129. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  130. package/dist/Tokenizer/Tokenizer.js +13 -2
  131. package/dist/Tokenizer/TokenizerBottomSheet.js +3 -3
  132. package/dist/Toolbar/Toolbar.d.ts.map +1 -1
  133. package/dist/Toolbar/Toolbar.js +2 -1
  134. package/dist/Typeahead/Typeahead.d.ts +1 -1
  135. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  136. package/dist/Typeahead/Typeahead.js +9 -1
  137. package/dist/astryx.css +15 -1
  138. package/dist/gestures/GestureArena.d.ts +6 -0
  139. package/dist/gestures/GestureArena.d.ts.map +1 -1
  140. package/dist/gestures/GestureArena.js +39 -0
  141. package/dist/gestures/GestureHost.d.ts +352 -0
  142. package/dist/gestures/GestureHost.d.ts.map +1 -0
  143. package/dist/gestures/GestureHost.js +1773 -0
  144. package/dist/gestures/GestureRecognizer.d.ts +10 -0
  145. package/dist/gestures/GestureRecognizer.d.ts.map +1 -1
  146. package/dist/gestures/GestureRecognizer.js +16 -0
  147. package/dist/gestures/LongPressGestureRecognizer.d.ts +1 -0
  148. package/dist/gestures/LongPressGestureRecognizer.d.ts.map +1 -1
  149. package/dist/gestures/LongPressGestureRecognizer.js +3 -0
  150. package/dist/gestures/PanGestureRecognizer.d.ts +1 -0
  151. package/dist/gestures/PanGestureRecognizer.d.ts.map +1 -1
  152. package/dist/gestures/PanGestureRecognizer.js +3 -0
  153. package/dist/gestures/PinchGestureRecognizer.d.ts +31 -0
  154. package/dist/gestures/PinchGestureRecognizer.d.ts.map +1 -0
  155. package/dist/gestures/PinchGestureRecognizer.js +128 -0
  156. package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts +71 -0
  157. package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts.map +1 -0
  158. package/dist/gestures/ScreenEdgePanGestureRecognizer.js +223 -0
  159. package/dist/gestures/SwipeGestureRecognizer.d.ts +37 -0
  160. package/dist/gestures/SwipeGestureRecognizer.d.ts.map +1 -0
  161. package/dist/gestures/SwipeGestureRecognizer.js +148 -0
  162. package/dist/gestures/TapGestureRecognizer.d.ts +1 -0
  163. package/dist/gestures/TapGestureRecognizer.d.ts.map +1 -1
  164. package/dist/gestures/TapGestureRecognizer.js +3 -0
  165. package/dist/gestures/VelocityTracker.d.ts +6 -2
  166. package/dist/gestures/VelocityTracker.d.ts.map +1 -1
  167. package/dist/gestures/VelocityTracker.js +7 -3
  168. package/dist/gestures/haptics.d.ts +65 -0
  169. package/dist/gestures/haptics.d.ts.map +1 -0
  170. package/dist/gestures/haptics.js +182 -0
  171. package/dist/gestures/nativeScroll.d.ts +42 -0
  172. package/dist/gestures/nativeScroll.d.ts.map +1 -0
  173. package/dist/gestures/nativeScroll.js +228 -0
  174. package/dist/gestures/touchAction.d.ts +60 -0
  175. package/dist/gestures/touchAction.d.ts.map +1 -0
  176. package/dist/gestures/touchAction.js +157 -0
  177. package/dist/gestures/touchActionRule.d.ts +34 -0
  178. package/dist/gestures/touchActionRule.d.ts.map +1 -0
  179. package/dist/gestures/touchActionRule.js +140 -0
  180. package/dist/gestures/types.d.ts +18 -7
  181. package/dist/gestures/types.d.ts.map +1 -1
  182. package/dist/gestures/types.js +22 -2
  183. package/dist/hooks/useAdaptivePresentation.d.ts.map +1 -1
  184. package/dist/hooks/useAdaptivePresentation.js +4 -1
  185. package/dist/hooks/useMenuHover.d.ts.map +1 -1
  186. package/dist/hooks/useMenuHover.js +12 -1
  187. package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
  188. package/dist/i18n/generated-locales/en.generated.js +3 -0
  189. package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
  190. package/dist/i18n/generated-locales/pseudo.generated.js +3 -0
  191. package/dist/motion/animator.d.ts +7 -1
  192. package/dist/motion/animator.d.ts.map +1 -1
  193. package/dist/motion/animator.js +119 -27
  194. package/dist/theme/defineTheme.js +1 -1
  195. package/dist/theme/domainTokens/domainTokenDefaults.d.ts +3 -0
  196. package/dist/theme/domainTokens/domainTokenDefaults.d.ts.map +1 -0
  197. package/dist/theme/domainTokens/domainTokenDefaults.js +19 -0
  198. package/dist/theme/domainTokens/index.d.ts +5 -4
  199. package/dist/theme/domainTokens/index.d.ts.map +1 -1
  200. package/dist/theme/domainTokens/index.js +5 -9
  201. package/dist/utils/focusReturn.d.ts +17 -1
  202. package/dist/utils/focusReturn.d.ts.map +1 -1
  203. package/dist/utils/focusReturn.js +11 -4
  204. package/dist/utils/getNodeText.d.ts +8 -0
  205. package/dist/utils/getNodeText.d.ts.map +1 -0
  206. package/dist/utils/getNodeText.js +37 -0
  207. package/dist/utils/interactionModality.d.ts +11 -2
  208. package/dist/utils/interactionModality.d.ts.map +1 -1
  209. package/dist/utils/interactionModality.js +58 -5
  210. package/dist/utils/plainDate.d.ts +2 -0
  211. package/dist/utils/plainDate.d.ts.map +1 -1
  212. package/dist/utils/plainDate.js +46 -3
  213. package/dist/utils/presentation.d.ts +50 -0
  214. package/dist/utils/presentation.d.ts.map +1 -0
  215. package/dist/utils/presentation.js +125 -0
  216. package/dist/utils/primaryClick.d.ts +11 -0
  217. package/dist/utils/primaryClick.d.ts.map +1 -0
  218. package/dist/utils/primaryClick.js +25 -0
  219. package/dist/utils/timeFormat.d.ts +47 -0
  220. package/dist/utils/timeFormat.d.ts.map +1 -0
  221. package/dist/utils/timeFormat.js +240 -0
  222. package/dist/utils/touchPresentation.d.ts.map +1 -1
  223. package/dist/utils/touchPresentation.js +5 -3
  224. package/dist/utils/touchPresentation.stylex.d.ts +15 -0
  225. package/dist/utils/touchPresentation.stylex.d.ts.map +1 -0
  226. package/dist/utils/touchPresentation.stylex.js +33 -0
  227. package/dist/utils/unicodeDigits.d.ts +20 -0
  228. package/dist/utils/unicodeDigits.d.ts.map +1 -0
  229. package/dist/utils/unicodeDigits.js +70 -0
  230. package/locales/en.json +15 -3
  231. package/locales/pseudo.json +9 -0
  232. package/package.json +5 -4
  233. package/src/AlertDialog/AlertDialog.tsx +6 -5
  234. package/src/AlertDialog/__tests__/AlertDialog.a11y.chromium.spec.ts +18 -6
  235. package/src/Avatar/Avatar.spec.md +22 -22
  236. package/src/Avatar/Avatar.tsx +18 -1
  237. package/src/Avatar/__tests__/AvatarForcedColors.a11y.chromium.spec.ts +126 -0
  238. package/src/Badge/Badge.doc.mjs +1 -1
  239. package/src/Badge/Badge.tsx +19 -2
  240. package/src/Badge/__tests__/BadgeLargerText.a11y.chromium.spec.ts +260 -0
  241. package/src/BottomSheet/BottomSheet.test.tsx +46 -0
  242. package/src/BottomSheet/BottomSheet.tsx +1 -1
  243. package/src/BottomSheet/BottomSheetPanel.tsx +2 -1
  244. package/src/BottomSheet/useSheetGestures.test.ts +52 -0
  245. package/src/BottomSheet/useSheetGestures.ts +37 -6
  246. package/src/Breadcrumbs/__tests__/Breadcrumbs.a11y.chromium.spec.ts +18 -6
  247. package/src/Button/Button.tsx +4 -4
  248. package/src/Calendar/Calendar.spec.md +87 -48
  249. package/src/Calendar/__tests__/Calendar.a11y.chromium.spec.ts +21 -7
  250. package/src/Carousel/__tests__/Carousel.a11y.chromium.spec.ts +21 -7
  251. package/src/CheckboxInput/CheckboxInput.tsx +6 -5
  252. package/src/Collapsible/Collapsible.spec.md +2 -0
  253. package/src/Collapsible/CollapsibleGroup.spec.md +57 -29
  254. package/src/Collapsible/__tests__/Collapsible.a11y.chromium.spec.ts +18 -7
  255. package/src/Collapsible/__tests__/CollapsibleGroupAccordion.a11y.chromium.spec.ts +18 -6
  256. package/src/ComplexSelector/ComplexSelector.test.tsx +37 -0
  257. package/src/ContextMenu/ContextMenu.test.tsx +35 -0
  258. package/src/DateInput/DateInput.test.tsx +115 -3
  259. package/src/DateInput/DateInput.tsx +29 -14
  260. package/src/DateInput/DateInputTouch.test.tsx +76 -0
  261. package/src/DateInput/MonthScroller.tsx +106 -20
  262. package/src/DateInput/MonthScrollerSettle.test.tsx +165 -0
  263. package/src/DateInput/TouchDateField.tsx +14 -3
  264. package/src/DateInput/__tests__/MonthScrollerSteps.interaction.browser.spec.ts +312 -0
  265. package/src/DateRangeInput/DateRangeInput.test.tsx +46 -3
  266. package/src/DateRangeInput/DateRangeInput.tsx +16 -12
  267. package/src/DateTimeInput/DateTimeInput.doc.mjs +10 -8
  268. package/src/DateTimeInput/DateTimeInput.spec.md +75 -51
  269. package/src/DateTimeInput/DateTimeInput.test.tsx +81 -0
  270. package/src/DateTimeInput/DateTimeInput.tsx +46 -24
  271. package/src/DateTimeInput/NativeTimeSegment.tsx +4 -6
  272. package/src/DateTimeInput/TouchDateTimeField.tsx +3 -7
  273. package/src/Dialog/Dialog.test.tsx +216 -2
  274. package/src/Dialog/Dialog.tsx +42 -9
  275. package/src/Dialog/DialogHeader.tsx +5 -4
  276. package/src/Dialog/__tests__/DialogSecondDocument.a11y.browser.spec.ts +202 -0
  277. package/src/Divider/Divider.tsx +2 -1
  278. package/src/Drawer/Drawer.spec.md +111 -80
  279. package/src/Drawer/Drawer.test.tsx +35 -0
  280. package/src/Drawer/Drawer.tsx +13 -2
  281. package/src/Drawer/DrawerHeader.spec.md +181 -0
  282. package/src/Drawer/__tests__/DrawerNonModalPageScroll.a11y.chromium.spec.ts +267 -0
  283. package/src/DropdownMenu/DropdownMenu.test.tsx +41 -0
  284. package/src/DropdownMenu/DropdownMenu.tsx +7 -1
  285. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +34 -0
  286. package/src/DropdownMenu/MenuBottomSheetActionList.tsx +6 -5
  287. package/src/DropdownMenu/__tests__/Menu.a11y.chromium.spec.ts +19 -7
  288. package/src/DropdownMenu/__tests__/MenuButton.a11y.chromium.spec.ts +21 -9
  289. package/src/DropdownMenu/lazyMenuBottomSheet.test.ts +53 -0
  290. package/src/DropdownMenu/lazyMenuBottomSheet.ts +23 -6
  291. package/src/DropdownMenu/renderDropdownItems.tsx +24 -19
  292. package/src/EmptyState/EmptyState.tsx +2 -1
  293. package/src/Field/FieldLabel.tsx +5 -4
  294. package/src/Field/InputClearButton.tsx +3 -3
  295. package/src/Field/PanelSearchInput.tsx +2 -2
  296. package/src/FieldStatus/FieldStatus.tsx +2 -2
  297. package/src/FileInput/FileInput.test.tsx +21 -0
  298. package/src/FileInput/FileInput.tsx +4 -1
  299. package/src/FormLayout/FormLayout.spec.md +7 -8
  300. package/src/Heading/Heading.tsx +1 -1
  301. package/src/Icon/Icon.tsx +1 -1
  302. package/src/Indicator/CheckIndicator.spec.md +47 -42
  303. package/src/Indicator/CheckIndicator.tsx +2 -1
  304. package/src/Indicator/CheckboxIndicator.spec.md +40 -37
  305. package/src/Indicator/CheckboxIndicator.tsx +3 -1
  306. package/src/Indicator/Indicator.spec.md +188 -0
  307. package/src/Indicator/RadioIndicator.tsx +3 -1
  308. package/src/Item/Item.tsx +2 -1
  309. package/src/Item/ItemSwipeLayer.tsx +1 -1
  310. package/src/Layout/Layout.spec.md +127 -131
  311. package/src/Layout/Layout.tsx +1 -1
  312. package/src/Layout/LayoutContent.spec.md +205 -0
  313. package/src/Layout/LayoutContent.tsx +1 -1
  314. package/src/Layout/LayoutFooter.spec.md +190 -0
  315. package/src/Layout/LayoutFooter.tsx +1 -1
  316. package/src/Layout/LayoutHeader.spec.md +193 -0
  317. package/src/Layout/LayoutHeader.tsx +1 -1
  318. package/src/Layout/LayoutPanel.spec.md +194 -0
  319. package/src/Layout/__tests__/Layout.a11y.chromium.spec.ts +18 -6
  320. package/src/Lightbox/Lightbox.test.tsx +18 -0
  321. package/src/Lightbox/Lightbox.tsx +5 -0
  322. package/src/Lightbox/LightboxViewport.a11y.browser.spec.ts +8 -4
  323. package/src/Link/__tests__/Link.a11y.chromium.spec.ts +18 -8
  324. package/src/List/List.tsx +1 -1
  325. package/src/List/ListItem.spec.md +205 -0
  326. package/src/List/ListItem.tsx +3 -3
  327. package/src/MobileNav/MobileNav.test.tsx +15 -0
  328. package/src/MobileNav/MobileNav.tsx +9 -1
  329. package/src/MobileNav/__tests__/MobileNavHeader.a11y.chromium.spec.ts +89 -0
  330. package/src/MoreMenu/MoreMenu.test.tsx +11 -0
  331. package/src/MultiSelector/MultiSelector.spec.md +7 -4
  332. package/src/MultiSelector/MultiSelector.test.tsx +118 -1
  333. package/src/MultiSelector/MultiSelector.tsx +6 -2
  334. package/src/MultiSelector/__tests__/MultiSelector.listbox.a11y.test.tsx +8 -1
  335. package/src/NavMenu/NavHeadingMenu.spec.md +1 -5
  336. package/src/NumberInput/NumberInput.doc.mjs +13 -7
  337. package/src/NumberInput/NumberInput.spec.md +59 -37
  338. package/src/NumberInput/NumberInput.tsx +13 -3
  339. package/src/NumberInput/__tests__/NumberInput.coarse-pointer.a11y.chromium.spec.ts +102 -0
  340. package/src/NumberInput/numberParser.ts +7 -45
  341. package/src/ProgressBar/ProgressBar.test.tsx +108 -32
  342. package/src/ProgressBar/ProgressBar.tsx +58 -10
  343. package/src/ProgressBar/__tests__/ProgressBar.a11y.chromium.spec.ts +21 -9
  344. package/src/ProgressBar/__tests__/ProgressBarMotion.a11y.chromium.spec.ts +831 -0
  345. package/src/Resizable/__tests__/ResizeHandle.a11y.chromium.spec.ts +21 -14
  346. package/src/Resizable/useResizable.test.ts +43 -0
  347. package/src/Resizable/useResizable.ts +32 -9
  348. package/src/SegmentedControl/SegmentedControl.test.tsx +84 -0
  349. package/src/SegmentedControl/SegmentedControlItem.tsx +11 -5
  350. package/src/Selector/Selector.test.tsx +90 -1
  351. package/src/Selector/__tests__/Selector.combobox.a11y.test.tsx +8 -1
  352. package/src/Selector/__tests__/Selector.listbox.a11y.test.tsx +8 -1
  353. package/src/Selector/useSelectorPresentation.ts +31 -3
  354. package/src/SideNav/SideNav.test.tsx +27 -0
  355. package/src/SideNav/__tests__/SideNavRailMotion.interaction.browser.spec.ts +176 -51
  356. package/src/Slider/Slider.test.tsx +12 -0
  357. package/src/Slider/Slider.tsx +4 -1
  358. package/src/Slider/__tests__/Slider.a11y.chromium.spec.ts +19 -7
  359. package/src/Spinner/Spinner.tsx +2 -2
  360. package/src/Stack/Stack.tsx +1 -1
  361. package/src/Stack/StackItem.tsx +1 -1
  362. package/src/TabList/TabList.test.tsx +58 -4
  363. package/src/TabList/TabList.tsx +16 -1
  364. package/src/TabList/__tests__/TabPressPointer.interaction.browser.spec.ts +163 -0
  365. package/src/Table/__tests__/Table.a11y.chromium.spec.ts +18 -6
  366. package/src/Table/plugins/columnResize/useTableColumnResize.test.tsx +22 -0
  367. package/src/Table/plugins/columnResize/useTableColumnResize.tsx +8 -4
  368. package/src/Text/Text.tsx +1 -1
  369. package/src/Text/useTruncation.test.tsx +128 -1
  370. package/src/Text/useTruncation.ts +23 -5
  371. package/src/TextArea/TextArea.spec.md +10 -13
  372. package/src/TextArea/TextArea.test.tsx +60 -0
  373. package/src/TextArea/TextArea.tsx +15 -1
  374. package/src/TextInput/TextInput.test.tsx +21 -0
  375. package/src/TextInput/TextInput.tsx +3 -1
  376. package/src/TimeInput/NativeTimeInput.test.tsx +17 -0
  377. package/src/TimeInput/Presentation.test.tsx +21 -0
  378. package/src/TimeInput/TimeInput.doc.mjs +8 -8
  379. package/src/TimeInput/TimeInput.spec.md +45 -48
  380. package/src/TimeInput/TimeInput.test.tsx +76 -0
  381. package/src/TimeInput/TimeInput.tsx +36 -18
  382. package/src/TimeInput/TouchTimeField.tsx +4 -6
  383. package/src/Timestamp/Timestamp.spec.md +6 -12
  384. package/src/Timestamp/Timestamp.test.tsx +30 -5
  385. package/src/Timestamp/Timestamp.tsx +6 -2
  386. package/src/Timestamp/TimestampHoverCard.tsx +4 -4
  387. package/src/Toast/Toast.spec.md +14 -20
  388. package/src/Toast/Toast.tsx +104 -36
  389. package/src/Toast/ToastViewport.test.tsx +719 -1
  390. package/src/Toast/ToastViewport.tsx +100 -50
  391. package/src/Tokenizer/Tokenizer.spec.md +5 -3
  392. package/src/Tokenizer/Tokenizer.test.tsx +68 -0
  393. package/src/Tokenizer/Tokenizer.tsx +14 -2
  394. package/src/Tokenizer/TokenizerBottomSheet.test.tsx +15 -4
  395. package/src/Tokenizer/TokenizerBottomSheet.tsx +3 -3
  396. package/src/Toolbar/Toolbar.spec.md +5 -6
  397. package/src/Toolbar/Toolbar.test.tsx +30 -0
  398. package/src/Toolbar/Toolbar.tsx +2 -1
  399. package/src/Toolbar/__tests__/Toolbar.a11y.chromium.spec.ts +18 -6
  400. package/src/Tooltip/__tests__/Tooltip.a11y.chromium.spec.ts +18 -7
  401. package/src/TopNav/TopNav.test.tsx +27 -0
  402. package/src/Typeahead/Typeahead.test.tsx +40 -0
  403. package/src/Typeahead/Typeahead.tsx +12 -1
  404. package/src/gestures/GestureArena.ts +35 -0
  405. package/src/gestures/GestureHost.ts +2065 -0
  406. package/src/gestures/GestureRecognizer.ts +18 -0
  407. package/src/gestures/LongPressGestureRecognizer.ts +4 -0
  408. package/src/gestures/PanGestureRecognizer.ts +4 -0
  409. package/src/gestures/PinchGestureRecognizer.ts +148 -0
  410. package/src/gestures/ScreenEdgePanGestureRecognizer.ts +256 -0
  411. package/src/gestures/SwipeGestureRecognizer.ts +197 -0
  412. package/src/gestures/TapGestureRecognizer.ts +4 -0
  413. package/src/gestures/VelocityTracker.ts +10 -3
  414. package/src/gestures/__tests__/GestureHost.test.ts +2087 -0
  415. package/src/gestures/__tests__/PanGestureRecognizer.test.ts +4 -4
  416. package/src/gestures/__tests__/PinchGestureRecognizer.test.ts +74 -0
  417. package/src/gestures/__tests__/ScreenEdgePanGestureRecognizer.test.ts +498 -0
  418. package/src/gestures/__tests__/SwipeGestureRecognizer.test.ts +108 -0
  419. package/src/gestures/__tests__/arena.test.ts +5 -0
  420. package/src/gestures/__tests__/arenaPinchSwipeEdge.test.ts +193 -0
  421. package/src/gestures/__tests__/browser/build-fixture.mjs +46 -0
  422. package/src/gestures/__tests__/browser/fixture.ts +307 -0
  423. package/src/gestures/__tests__/browser/gestures.interaction.browser.spec.ts +1137 -0
  424. package/src/gestures/__tests__/browserNegotiation.test.ts +293 -0
  425. package/src/gestures/__tests__/haptics.test.ts +187 -0
  426. package/src/gestures/__tests__/harness.ts +21 -2
  427. package/src/gestures/__tests__/recognizerKind.test.ts +78 -0
  428. package/src/gestures/__tests__/touchActionRule.test.ts +54 -0
  429. package/src/gestures/haptics.ts +203 -0
  430. package/src/gestures/nativeScroll.ts +277 -0
  431. package/src/gestures/touchAction.ts +191 -0
  432. package/src/gestures/touchActionRule.ts +157 -0
  433. package/src/gestures/types.ts +30 -9
  434. package/src/hooks/useAdaptivePresentation.ts +4 -1
  435. package/src/hooks/useMenuHover.ts +15 -1
  436. package/src/i18n/generated-locales/en.generated.ts +4 -0
  437. package/src/i18n/generated-locales/pseudo.generated.ts +4 -0
  438. package/src/motion/README.md +11 -1
  439. package/src/motion/animator.test.ts +151 -3
  440. package/src/motion/animator.ts +149 -33
  441. package/src/theme/defineTheme.ts +1 -1
  442. package/src/theme/derivedVarRegistry.test.ts +4 -0
  443. package/src/theme/domainTokens/domainTokenDefaults.ts +19 -0
  444. package/src/theme/domainTokens/index.ts +6 -10
  445. package/src/utils/focusReturn.ts +17 -6
  446. package/src/utils/getNodeText.test.ts +24 -0
  447. package/src/utils/getNodeText.ts +37 -0
  448. package/src/utils/interactionModality.test.ts +45 -1
  449. package/src/utils/interactionModality.ts +64 -5
  450. package/src/utils/plainDate.test.ts +90 -0
  451. package/src/utils/plainDate.ts +58 -3
  452. package/src/utils/presentation.test.ts +380 -0
  453. package/src/utils/presentation.ts +180 -0
  454. package/src/utils/pressPaintPriority.test.ts +80 -0
  455. package/src/utils/primaryClick.test.ts +38 -0
  456. package/src/utils/primaryClick.ts +28 -0
  457. package/src/utils/timeFormat.test.ts +204 -0
  458. package/src/utils/timeFormat.ts +314 -0
  459. package/src/utils/touchPresentation.stylex.ts +43 -0
  460. package/src/utils/touchPresentation.test.ts +140 -1
  461. package/src/utils/touchPresentation.ts +5 -3
  462. package/src/utils/unicodeDigits.test.ts +44 -0
  463. package/src/utils/unicodeDigits.ts +71 -0
@@ -3,11 +3,11 @@ schema_version: 3
3
3
  template_version: 7
4
4
  kind: component
5
5
  id: component:DateTimeInput
6
- authority: draft
6
+ authority: current
7
7
  archive_reason: null
8
8
  superseded_by: null
9
- approved_by: null
10
- approved_at: null
9
+ approved_by: cixzhang
10
+ approved_at: 2026-10-30
11
11
  owners: [cixzhang]
12
12
  review_triggers: [public-api, behavior, layout, theming, accessibility]
13
13
  verified_by:
@@ -16,30 +16,37 @@ verified_by:
16
16
  packages/core/src/DateTimeInput/DateTimeInputTouch.test.tsx,
17
17
  packages/core/src/DateTimeInput/NativePickerSegments.test.tsx,
18
18
  packages/core/src/DateTimeInput/Presentation.test.tsx,
19
+ packages/core/src/DateTimeInput/DateTimeInput.fr10.test.tsx,
20
+ packages/core/src/__tests__/BusyOwnerAnnouncement.test.tsx,
19
21
  packages/core/src/theme/themingTargets.test.ts,
20
22
  scripts/check-knowledge.mjs,
21
23
  ]
22
24
  modules: []
23
25
  families: [family:input-fields, family:overlay-dismissal]
24
26
  design_specs: []
25
- architecture: [architecture:component-theming-surface]
27
+ architecture:
28
+ [
29
+ architecture:component-theming-surface,
30
+ architecture:internationalization,
31
+ architecture:public-component-api,
32
+ ]
26
33
  contributing: []
27
- system_specs: [spec:AST-043]
34
+ system_specs: [spec:AST-043, spec:AST-085, spec:AST-086, spec:AST-102]
28
35
  ---
29
36
 
30
37
  # DateTimeInput component contract
31
38
 
32
39
  ## Contract at a glance
33
40
 
34
- | Area | Contract |
35
- | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
36
- | Public contract | One controlled ISO date-time value presented through coordinated date and time segments; `presentation` selects Astryx, native, or adaptive picker surfaces. |
37
- | Behavior | Date and time changes emit one combined value; clear emits `undefined`; controlled empty state remains empty in every rendered picker. |
38
- | End-user impact | People selecting a date and time see one value reflected consistently in the closed field and the active picker, including after clearing. |
39
- | Builder impact | None. |
40
- | Compatibility/readiness | Released defaults and deprecated `nativePicker` behavior remain unchanged. The presentation matrix is governed by current `spec:AST-043`; component-local observations remain draft pending owner review. |
41
- | Review checks | Reject competing picker selection, date/time output that is not one valid combined value, presentation precedence drift, lost per-segment fallback, or broken segment accessibility. |
42
- | Governing rules | `spec:AST-043`, `family:input-fields`, `family:overlay-dismissal`, and objective platform accessibility standards. |
41
+ | Area | Contract |
42
+ | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
43
+ | Public contract | One controlled ISO date-time value presented through coordinated date and time segments; `presentation` selects Astryx, native, or adaptive picker surfaces. |
44
+ | Behavior | Date and time changes emit one combined value; clear emits `undefined`; controlled empty state remains empty in every rendered picker. |
45
+ | End-user impact | People selecting a date and time see one value reflected consistently in the closed field and the active picker, including after clearing. |
46
+ | Builder impact | A caller that relied on the `12h` hour-format default under a 24-hour locale passes `hourFormat="12h"` to keep twelve-hour time text. A per-user 12/24-hour preference goes on the provider locale as a `-u-hc-` extension (`en-US-u-hc-h23`). |
47
+ | Compatibility/readiness | The `hourFormat` default is the provider locale's hour cycle (`12h` for `en`/`en-US` and with no provider); every other released default, API, and DOM shape holds. The presentation matrix and deprecated `nativePicker` mapping follow `spec:AST-043`. Fixed segment height, typed-time prefix commits, busy paint, and caller handlers while disabled are listed under Current-state impact. |
48
+ | Review checks | Reject competing picker selection, date/time output that is not one valid combined value, presentation precedence drift, lost per-segment fallback, or broken segment accessibility. |
49
+ | Governing rules | `spec:AST-043`, `family:input-fields`, `family:overlay-dismissal`, `spec:AST-085`, `spec:AST-086` FR8, and objective platform accessibility standards. |
43
50
 
44
51
  This table is a review projection; the body below is authoritative.
45
52
 
@@ -52,9 +59,11 @@ or pointer-adaptive combinations of those surfaces.
52
59
 
53
60
  ## Compatibility and migration
54
61
 
55
- - Released default preserved: `yes`
56
- - Compatibility class: no public surface change; existing types, defaults,
57
- callbacks, roles, and exports remain stable
62
+ - Released default preserved: `yes`, except `hourFormat`, which follows the
63
+ provider locale's hour cycle (`12h` for `en` and `en-US`, the released
64
+ default with no provider) and shares TimeInput's locale time text
65
+ - Compatibility class: default change for non-English-US locales; existing
66
+ types, callbacks, roles, and exports remain stable
58
67
  - Controlled/uncontrolled behavior: DateTimeInput remains controlled; `undefined`
59
68
  represents no committed date-time value
60
69
  - Migration decision: none; picker presentation and deprecated `nativePicker`
@@ -71,13 +80,16 @@ Consumer migration instructions belong in consumer docs and release notes.
71
80
  - Applying component-local date-time bounds, date constraints, time precision,
72
81
  typed-time stepping, and optional preset-time behavior.
73
82
  - Emitting `onChange` before an optional optimistic `changeAction`.
83
+ - The disabled-reason Tooltip composition, which `family:input-fields` assigns
84
+ to the member.
74
85
 
75
86
  **Does not own / non-goals**
76
87
 
77
- - Field label, description, status, disabled-reason, and clear-button presentation —
78
- owned by `component:Field` and `component:FieldStatus`.
88
+ - Field label, description, status, and clear-button presentation —
89
+ owned by Field under `family:input-fields` (shared owner section) and
90
+ `component:FieldStatus`.
79
91
  - Calendar-grid rendering and date-cell interaction — owned by
80
- `component:Calendar`.
92
+ Calendar.
81
93
  - Popover and sheet hosting or dismissal — owned by the composed layer components
82
94
  and `family:overlay-dismissal`.
83
95
  - Cross-component picker-presentation vocabulary and deprecated-prop mapping —
@@ -95,18 +107,17 @@ Consumer migration instructions belong in consumer docs and release notes.
95
107
 
96
108
  ## Behavioral and layout contract
97
109
 
98
- Draft requirements identify their basis so observed code is not mistaken for an
99
- intentional decision.
100
-
101
- | ID | Candidate invariant | Basis | Draft review state |
102
- | --- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------------------------------------------------------ |
103
- | FR1 | DateTimeInput MUST reflect one controlled date-time value across its visible segments and active picker, and MUST NOT reveal a competing selected date after the parent accepts a clear. | Public docs, controlled component seam, current source, focused tests | Verified observation; owner approval pending |
104
- | FR2 | Every committed date or time change MUST emit one valid combined ISO date-time value; clearing MUST emit `undefined`; changing time while no date is committed MUST emit nothing. | Public types, docs, current source, focused tests | Verified observation; owner approval pending |
105
- | FR3 | `presentation`, deprecated `nativePicker`, precedence, pointer adaptation, forced surfaces, and per-segment native fallbacks MUST follow `spec:AST-043` FR1–FR4. | `spec:AST-043` | Inherited current authority |
106
- | FR4 | When `changeAction` is present, every value-change path MUST call `onChange` first, show the proposed controlled value optimistically, and contribute to one busy state until the controlled value accepts or replaces it. | `family:input-fields/FR6` | Inherited current authority |
107
- | FR5 | The two pointer segments share one row while each retains its intrinsic basis; when the container is narrower, flex wrapping moves them into separate full-width rows. | Public docs, current source, focused layout tests | Verify rendered geometry; class-level behavior covered |
108
- | FR6 | Date-time bounds and date constraints MUST prevent invalid commits. Native controls MAY receive platform hints, but JavaScript validation remains the final commit boundary; calendar-only options MAY be unavailable on native surfaces. | Public docs, current source, focused presentation tests | Verified observation; owner approval pending |
109
- | FR7 | A preset-time listbox MUST remain optional, preserve typed entry, expose one selected option independently from keyboard highlight, and limit offered values to the selected date's effective minimum and maximum. | Public docs, current source, focused interaction tests | Verified observation; owner approval pending |
110
+ | ID | Invariant | Basis |
111
+ | --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------- |
112
+ | FR1 | DateTimeInput MUST reflect one controlled date-time value across its visible segments and active picker, and MUST NOT reveal a competing selected date after the parent accepts a clear. | Public docs, controlled component seam, current source, focused tests |
113
+ | FR2 | Every committed date or time change MUST emit one valid combined ISO date-time value; clearing MUST emit `undefined`; changing time while no date is committed MUST emit nothing. | Public types, docs, current source, focused tests |
114
+ | FR3 | `presentation`, deprecated `nativePicker`, precedence, pointer adaptation, forced surfaces, and per-segment native fallbacks MUST follow `spec:AST-043` FR1–FR4. | `spec:AST-043` |
115
+ | FR4 | When `changeAction` is present, every value-change path MUST call `onChange` first, show the proposed controlled value optimistically, and contribute to one busy state until the controlled value accepts or replaces it. | `family:input-fields/FR6` |
116
+ | FR5 | The two pointer segments share one row while each retains its intrinsic basis; when the container is narrower, flex wrapping moves them into separate full-width rows. Each segment is the shared element height for its size, as a minimum that grows with a set text size under `spec:AST-102` FR4. Implementation gap: the height is fixed at that size. | Public docs, current source, focused layout tests; `spec:AST-102` FR4 |
117
+ | FR6 | Date-time bounds and date constraints MUST prevent invalid commits. Native controls MAY receive platform hints, but JavaScript validation remains the final commit boundary; calendar-only options MAY be unavailable on native surfaces. | Public docs, current source, focused presentation tests |
118
+ | FR7 | A preset-time listbox MUST remain optional, preserve typed entry, expose one selected option independently from keyboard highlight, and limit offered values to the selected date's effective minimum and maximum. Time text and typed times MUST follow the active locale's digits, separator, and day-period words (`architecture:internationalization` INV1a, INV8). The hour format is `hourFormat` when set, else the provider locale's hour cycle; time text, preset options, and the stepped-time announcement come from the shared time formatter, and typed times parse the locale's digits, separators, and day-period words as well as English. Implementation gap: the typed time field commits as soon as a prefix parses. | Public docs, current source, focused interaction tests; `architecture:internationalization` INV1a, INV8 |
119
+ | FR8 | Base props and `ref` MUST reach the date segment's input; a caller `aria-describedby` joins the component's own descriptions, and a caller DOM handler runs after the field's own handler. `container*` reaches the Field box and `control*` the segment row; root `xstyle`, `className`, and `style` are not accepted. | `family:input-fields` FR10; `DateTimeInput.fr10.test.tsx` |
120
+ | FR9 | A disabled field MUST keep both segments focusable with `aria-disabled` and no native `disabled`, block every value-changing path, keep the calendar button's tab stop, and paint the keyboard focus ring. Explicit `isLoading` makes every surface inert the same way; a pending `changeAction` does so only on the popover surface, and the bottom sheet and any field with a native date segment keep accepting edits. The busy start is announced once. Implementation gap: a caller `onKeyDown` and other DOM handlers on the date segment still run while disabled (`spec:AST-085` FR2). Implementation gap: a busy field that is not disabled takes the disabled paint (half opacity), on every surface while `isLoading` and on the popover while a `changeAction` is pending, against `spec:AST-085` FR6. | `spec:AST-085` FR1, FR2, FR6; `spec:AST-086` FR8; current source and tests |
110
121
 
111
122
  ### Allowed variation
112
123
 
@@ -119,13 +130,13 @@ intentional decision.
119
130
 
120
131
  ### Representative states
121
132
 
122
- | State | Required invariant | Allowed variation |
123
- | --------------------------- | --------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
124
- | Empty | Both segments and every active picker expose no committed selection. | Placeholder and selected surface. |
125
- | Date-time value | Date segment, time segment, and active picker reflect the same committed value. | Locale, hour format, and time precision. |
126
- | Cleared after picker change | Closed field is empty and reopening the picker reveals no selected date or retained committed time. | Picker focus date may remain navigational. |
127
- | Busy | Proposed value remains visible; mutation paths are unavailable; both editable segments expose busy. | Explicit loading or pending action source. |
128
- | Focusable disabled | Both segments remain focusable enough to expose the reason while every value-changing path stays blocked. | Disabled-reason text. |
133
+ | State | Required invariant | Allowed variation |
134
+ | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
135
+ | Empty | Both segments and every active picker expose no committed selection. | Placeholder and selected surface. |
136
+ | Date-time value | Date segment, time segment, and active picker reflect the same committed value. | Locale, hour format, and time precision. |
137
+ | Cleared after picker change | Closed field is empty and reopening the picker reveals no selected date or retained committed time. | Picker focus date may remain navigational. |
138
+ | Busy | Proposed value remains visible; both editable segments expose busy. With explicit `isLoading`, mutation paths are unavailable on every surface; with a pending `changeAction`, only on the popover surface. | Explicit loading or pending action source. |
139
+ | Focusable disabled | Both segments stay focusable with `aria-disabled` while every value-changing path stays blocked. | Disabled-reason text. |
129
140
 
130
141
  ### Transformation and precedence order
131
142
 
@@ -220,24 +231,37 @@ leading clock glyph uses `date-time-input-clock-icon`.
220
231
 
221
232
  ## Verification map
222
233
 
223
- | Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
224
- | ------------------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------- |
225
- | FR1–FR2 | `DateTimeInput.test.tsx` | empty, calendar selection, typed date/time, clear | A stale Calendar selection, partial output, or invalid mutation makes a public-state test fail. | `audit:DateTimeInput/behavior` |
226
- | FR3, FR6 | `Presentation.test.tsx`, `NativePickerSegments.test.tsx`, `DateTimeInputTouch.test.tsx` | forced, adaptive, legacy, native fallback, constrained commit | A substituted surface, precedence drift, or invalid commit makes a presentation test fail. | `audit:DateTimeInput/surfaces` |
227
- | FR4, AR4 | `DateTimeInput.test.tsx`, `DateTimeInputTouch.test.tsx` | pending, loading, disabled reason | Mutation during busy/disabled state or stale optimistic output makes a state test fail. | `audit:DateTimeInput/state` |
228
- | FR5 | `DateTimeInput.test.tsx` | intrinsic row, narrow-container wrap classes | Removing the intrinsic basis or wrap styles makes the class-level layout assertions fail; rendered geometry remains review evidence. | `audit:DateTimeInput/layout` |
229
- | FR7, AR1–AR3 | `DateTimeInput.test.tsx`, `DateTimeInputTouch.test.tsx` | popovers, time options, keyboard/focus | Wrong role, name, state, keyboard behavior, or focus behavior makes a focused interaction test fail. | `audit:DateTimeInput/interaction` |
230
- | Theming anatomy map | `scripts/check-knowledge.mjs`, `themingTargets.test.ts` | root, segments, icons, listbox, options | Missing, undocumented, or wrongly placed targets fail knowledge or target checks. | `audit:DateTimeInput/theming` |
234
+ | Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
235
+ | ------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- |
236
+ | FR1–FR2 | `DateTimeInput.test.tsx` | empty, calendar selection, typed date/time, clear | A stale Calendar selection, partial output, or invalid mutation makes a public-state test fail. | `audit:DateTimeInput/behavior` |
237
+ | FR3, FR6 | `Presentation.test.tsx`, `NativePickerSegments.test.tsx`, `DateTimeInputTouch.test.tsx` | forced, adaptive, legacy, native fallback, constrained commit | A substituted surface, precedence drift, or invalid commit makes a presentation test fail. | `audit:DateTimeInput/surfaces` |
238
+ | FR4, FR9, AR4 | `DateTimeInput.test.tsx`, `DateTimeInputTouch.test.tsx`; `BusyOwnerAnnouncement.test.tsx` DateTimeInput case | pending, loading, disabled reason | Mutation during busy/disabled state or stale optimistic output makes a state test fail. Evidence gap: no test asserts that caller handlers still run while disabled. | `audit:DateTimeInput/state` |
239
+ | FR5 | `DateTimeInput.test.tsx` | intrinsic row, narrow-container wrap classes | Removing the intrinsic basis or wrap styles makes the class-level layout assertions fail; rendered geometry remains review evidence. Evidence gap: no test asserts segment heights or text growth. | `audit:DateTimeInput/layout` |
240
+ | FR7, AR1–AR3 | `DateTimeInput.test.tsx`, `DateTimeInputTouch.test.tsx` | popovers, time options, keyboard/focus | Wrong role, name, state, keyboard behavior, or focus behavior makes a focused interaction test fail. A provider-locale test asserts the closed time text follows the locale's hour cycle and day period; the shared formatter's tests cover parsing. | `audit:DateTimeInput/interaction` |
241
+ | FR8 | `DateTimeInput.fr10.test.tsx` | each surface; caller id, describedby, onClick, onKeyDown | A base prop off the date input, a dropped caller description, or styling on the wrong part fails. | `audit:DateTimeInput/api` |
242
+ | Theming anatomy map | `scripts/check-knowledge.mjs`, `themingTargets.test.ts` | root, segments, icons, listbox, options | Missing, undocumented, or wrongly placed targets fail knowledge or target checks. | `audit:DateTimeInput/theming` |
243
+
244
+ ## Current-state impact
245
+
246
+ - **Fixed height (FR5).** Segments hold the fixed shared element height instead
247
+ of growing with a set text size, against `spec:AST-102` FR4.
248
+ - **Typed-time prefix commits (FR7).** The typed time field commits a parsed
249
+ prefix, so a typed time can commit a different time, against
250
+ `architecture:internationalization` INV8.
251
+ - **Busy paint (FR9).** A busy field that is not disabled takes the disabled
252
+ half-opacity paint, against `spec:AST-085` FR6.
253
+ - **Caller handlers while disabled (FR9).** Caller DOM handlers on the date
254
+ segment, such as `onKeyDown`, still run while disabled, against
255
+ `spec:AST-085` FR2.
231
256
 
232
257
  ## Decision log
233
258
 
234
- No component-local decision is asserted by this draft. Current cross-component
235
- picker decisions remain in `spec:AST-043`.
259
+ No component-local decision. Cross-component picker decisions live in
260
+ `spec:AST-043`.
236
261
 
237
262
  ## Open questions
238
263
 
239
- None. Owner review may accept, amend, or reject the observational component-local
240
- rows without changing inherited current authority.
264
+ None.
241
265
 
242
266
  ## Content boundary
243
267
 
@@ -239,6 +239,26 @@ describe('DateTimeInput', () => {
239
239
  expect(screen.getByDisplayValue('2:30 PM')).toBeInTheDocument();
240
240
  });
241
241
 
242
+ it("follows the provider locale's hour cycle when hourFormat is unset", () => {
243
+ const renderIn = (locale: string) => (
244
+ <InternationalizationProvider locale={locale}>
245
+ <DateTimeInput
246
+ label="Meeting"
247
+ value={'2026-03-15T14:30' as ISODateTimeString}
248
+ onChange={() => {}}
249
+ />
250
+ </InternationalizationProvider>
251
+ );
252
+ const {rerender} = render(renderIn('en-US'));
253
+ expect(screen.getByDisplayValue('2:30 PM')).toBeInTheDocument();
254
+
255
+ rerender(renderIn('de-DE'));
256
+ expect(screen.getByDisplayValue('14:30')).toBeInTheDocument();
257
+
258
+ rerender(renderIn('ko-KR'));
259
+ expect(screen.getByDisplayValue('오후 2:30')).toBeInTheDocument();
260
+ });
261
+
242
262
  it('displays formatted time in 24h format', () => {
243
263
  render(
244
264
  <DateTimeInput
@@ -2293,6 +2313,67 @@ describe('DateTimeInput', () => {
2293
2313
  });
2294
2314
  });
2295
2315
 
2316
+ describe('calendar while the popover is closed', () => {
2317
+ const calendarGrid = () => document.querySelector('[role="grid"]');
2318
+
2319
+ it('renders no calendar until the popover opens, and none after it closes', () => {
2320
+ render(
2321
+ <DateTimeInput
2322
+ label="Meeting"
2323
+ value={'2026-01-15T10:00' as ISODateTimeString}
2324
+ onChange={() => {}}
2325
+ />,
2326
+ );
2327
+ const toggle = getButton('Open calendar');
2328
+ expect(calendarGrid()).toBeNull();
2329
+
2330
+ fireEvent.click(toggle);
2331
+ expect(calendarGrid()).not.toBeNull();
2332
+
2333
+ fireEvent.click(toggle);
2334
+ expect(calendarGrid()).toBeNull();
2335
+ });
2336
+
2337
+ it('opens on the month of a date typed while closed', () => {
2338
+ function Controlled() {
2339
+ const [value, setValue] = useState<ISODateTimeString | undefined>(
2340
+ '2026-01-15T10:00' as ISODateTimeString,
2341
+ );
2342
+ return (
2343
+ <DateTimeInput label="Meeting" value={value} onChange={setValue} />
2344
+ );
2345
+ }
2346
+ render(<Controlled />);
2347
+ const dateInput = screen.getAllByRole('combobox')[0];
2348
+
2349
+ fireEvent.change(dateInput, {target: {value: 'March 5, 2027'}});
2350
+ fireEvent.keyDown(dateInput, {key: 'ArrowDown'});
2351
+
2352
+ expect(calendarGrid()).toHaveAccessibleName('March 2027');
2353
+ });
2354
+
2355
+ it('moves focus into the calendar on each open from the toggle', async () => {
2356
+ render(
2357
+ <DateTimeInput
2358
+ label="Meeting"
2359
+ value={'2026-01-15T10:00' as ISODateTimeString}
2360
+ onChange={() => {}}
2361
+ />,
2362
+ );
2363
+ const toggle = getButton('Open calendar');
2364
+
2365
+ for (let i = 0; i < 2; i++) {
2366
+ fireEvent.click(toggle);
2367
+ // The first calendar control takes focus, not the dialog surface.
2368
+ await waitFor(() => {
2369
+ expect(getButton('Previous month')).toHaveFocus();
2370
+ });
2371
+ fireEvent.click(toggle);
2372
+ expect(calendarGrid()).toBeNull();
2373
+ }
2374
+ });
2375
+ });
2376
+
2296
2377
  describe('weekStartsOn', () => {
2297
2378
  // The calendar popover renders in the top layer; jsdom keeps the content in
2298
2379
  // the DOM but role queries skip it, so read the columnheaders directly.
@@ -71,9 +71,6 @@ import {
71
71
  type ISOTimeString,
72
72
  parseDateInput,
73
73
  parseISOTime,
74
- parseTimeInput,
75
- formatDisplayTime12h,
76
- formatDisplayTime24h,
77
74
  formatISOTime,
78
75
  isTimeInRange,
79
76
  adjustTime,
@@ -102,6 +99,11 @@ import {useSize} from '../SizeContext/SizeContext';
102
99
  import {themeProps} from '../utils/themeProps';
103
100
  import {focusOutlineStyles} from '../utils/focusOutline.stylex';
104
101
  import {useLocale, useTranslator} from '../i18n';
102
+ import {
103
+ formatLocaleTime,
104
+ parseLocaleTime,
105
+ resolveHourFormat,
106
+ } from '../utils/timeFormat';
105
107
 
106
108
  import {useMergedRefs} from '../hooks/useMergedRefs';
107
109
  import {useHighlightedOptionScroll} from '../hooks/useHighlightedOptionScroll';
@@ -412,8 +414,11 @@ export interface DateTimeInputProps extends Omit<
412
414
  hasSeconds?: boolean;
413
415
 
414
416
  /**
415
- * Hour display format.
416
- * @default '12h'
417
+ * Hour display format: '12h' with the locale's day period, or '24h'.
418
+ * When unset, follows the `InternationalizationProvider` locale's hour
419
+ * cycle (`en-US` 12-hour, `en-GB` 24-hour); a per-user preference rides on
420
+ * the locale tag (`en-US-u-hc-h23`).
421
+ * @default the locale's hour cycle
417
422
  */
418
423
  hourFormat?: DateTimeInputHourFormat;
419
424
 
@@ -836,8 +841,11 @@ function PointerDateTimeField({
836
841
  }
837
842
  const nativeTimeValue = nativeTimeDraft ?? valueParts.time;
838
843
 
839
- const formatDisplayTime =
840
- hourFormat === '12h' ? formatDisplayTime12h : formatDisplayTime24h;
844
+ const formatDisplayTime = useCallback(
845
+ (time: ISOTimeString, includeSeconds: boolean) =>
846
+ formatLocaleTime(time, locale, hourFormat, includeSeconds),
847
+ [locale, hourFormat],
848
+ );
841
849
 
842
850
  const timeDisplayValue = useMemo(() => {
843
851
  if (timePendingInput !== null) {
@@ -852,12 +860,12 @@ function PointerDateTimeField({
852
860
  if (timePendingInput === null || !timePendingInput.trim()) {
853
861
  return true;
854
862
  }
855
- const parsed = parseTimeInput(timePendingInput, hasSeconds);
863
+ const parsed = parseLocaleTime(timePendingInput, locale, hasSeconds);
856
864
  if (!parsed) {
857
865
  return false;
858
866
  }
859
867
  return isTimeInRange(parsed, timeMin, timeMax);
860
- }, [timePendingInput, hasSeconds, timeMin, timeMax]);
868
+ }, [timePendingInput, locale, hasSeconds, timeMin, timeMax]);
861
869
 
862
870
  const resolvedTimePlaceholder = useMemo(() => {
863
871
  if (isTimeFocused && !timeDisplayValue) {
@@ -1362,7 +1370,7 @@ function PointerDateTimeField({
1362
1370
  const text = e.target.value;
1363
1371
  setTimePendingInput(text);
1364
1372
 
1365
- const parsed = parseTimeInput(text, hasSeconds);
1373
+ const parsed = parseLocaleTime(text, locale, hasSeconds);
1366
1374
 
1367
1375
  // Typing narrows nothing — free-form entry is the contract, and a time
1368
1376
  // between two options must stay reachable. The list instead follows the
@@ -1386,6 +1394,7 @@ function PointerDateTimeField({
1386
1394
  }
1387
1395
  },
1388
1396
  [
1397
+ locale,
1389
1398
  hasSeconds,
1390
1399
  timeMin,
1391
1400
  timeMax,
@@ -1440,7 +1449,7 @@ function PointerDateTimeField({
1440
1449
  return;
1441
1450
  }
1442
1451
 
1443
- const parsed = parseTimeInput(timePendingInput, hasSeconds);
1452
+ const parsed = parseLocaleTime(timePendingInput, locale, hasSeconds);
1444
1453
  if (parsed && isTimeInRange(parsed, timeMin, timeMax)) {
1445
1454
  if (parsed !== valueParts.time && valueParts.date) {
1446
1455
  const combined = combineDateTime(valueParts.date, parsed);
@@ -1453,6 +1462,7 @@ function PointerDateTimeField({
1453
1462
  },
1454
1463
  [
1455
1464
  timePendingInput,
1465
+ locale,
1456
1466
  hasSeconds,
1457
1467
  timeMin,
1458
1468
  timeMax,
@@ -1530,7 +1540,7 @@ function PointerDateTimeField({
1530
1540
  const typed =
1531
1541
  timeHighlightFollowsTypingRef.current &&
1532
1542
  timePendingInput !== null
1533
- ? parseTimeInput(timePendingInput, hasSeconds)
1543
+ ? parseLocaleTime(timePendingInput, locale, hasSeconds)
1534
1544
  : null;
1535
1545
  const option = timeOptions[activeTimeIndex];
1536
1546
  if (typed) {
@@ -1582,6 +1592,7 @@ function PointerDateTimeField({
1582
1592
  },
1583
1593
  [
1584
1594
  valueParts,
1595
+ locale,
1585
1596
  hasSeconds,
1586
1597
  timeIncrement,
1587
1598
  timeMin,
@@ -1937,17 +1948,21 @@ function PointerDateTimeField({
1937
1948
 
1938
1949
  {!usesNativePicker &&
1939
1950
  popover.render(
1940
- <Calendar
1941
- handleRef={calendarRef}
1942
- mode="single"
1943
- value={valueParts.date ?? null}
1944
- onChange={(d: ISODateString) => handleDateChange(d, 'calendar')}
1945
- min={calendarMin}
1946
- max={calendarMax}
1947
- dateConstraints={dateConstraints}
1948
- numberOfMonths={numberOfMonths}
1949
- weekStartsOn={weekStartsOn}
1950
- />,
1951
+ // Mounted only while open, like the time list below; the calendar
1952
+ // opens on the current value.
1953
+ !popover.isOpen ? null : (
1954
+ <Calendar
1955
+ handleRef={calendarRef}
1956
+ mode="single"
1957
+ value={valueParts.date ?? null}
1958
+ onChange={(d: ISODateString) => handleDateChange(d, 'calendar')}
1959
+ min={calendarMin}
1960
+ max={calendarMax}
1961
+ dateConstraints={dateConstraints}
1962
+ numberOfMonths={numberOfMonths}
1963
+ weekStartsOn={weekStartsOn}
1964
+ />
1965
+ ),
1951
1966
  {placement: 'below', alignment: 'start'},
1952
1967
  )}
1953
1968
 
@@ -2030,11 +2045,18 @@ export function DateTimeInput(props: DateTimeInputProps) {
2030
2045
  props.presentation,
2031
2046
  props.nativePicker,
2032
2047
  );
2048
+ const locale = useLocale();
2033
2049
  const {
2034
2050
  presentation: _presentation,
2035
2051
  nativePicker: _nativePicker,
2036
- ...rest
2052
+ ...surfaceProps
2037
2053
  } = props;
2054
+ // Every surface gets the resolved hour format, so typed text, the native
2055
+ // field's resting text, preset times, and the sheet wheels agree.
2056
+ const rest = {
2057
+ ...surfaceProps,
2058
+ hourFormat: resolveHourFormat(locale, props.hourFormat),
2059
+ };
2038
2060
  if (effective === 'native') {
2039
2061
  return (
2040
2062
  <PointerDateTimeField
@@ -34,13 +34,12 @@ import type {InputStatusType} from '../Field';
34
34
  import {useMediaQuery} from '../hooks/useMediaQuery';
35
35
  import {useMergedRefs} from '../hooks/useMergedRefs';
36
36
  import {Icon} from '../Icon';
37
- import {useTranslator} from '../i18n';
37
+ import {useLocale, useTranslator} from '../i18n';
38
+ import {formatLocaleTime} from '../utils/timeFormat';
38
39
  import type {ThemeProps} from '../utils/themeProps';
39
40
  import {VisuallyHidden} from '../VisuallyHidden';
40
41
  import {
41
42
  focusOutlineStyles,
42
- formatDisplayTime12h,
43
- formatDisplayTime24h,
44
43
  formatISOTime,
45
44
  isTimeInRange,
46
45
  parseISOTime,
@@ -126,6 +125,7 @@ export function NativeTimeSegment({
126
125
  ...inputProps
127
126
  } = controlProps ?? {};
128
127
  const t = useTranslator();
128
+ const locale = useLocale();
129
129
  const isTouchPointer = useMediaQuery('(pointer: coarse)');
130
130
  const internalInputRef = useRef<HTMLInputElement | null>(null);
131
131
  const mergedInputRef = useMergedRefs(inputRef, internalInputRef);
@@ -151,10 +151,8 @@ export function NativeTimeSegment({
151
151
 
152
152
  const nativeValue = normalizeNativeTime(value) ?? '';
153
153
  const isInputValid = rejectedValue === null;
154
- const formatDisplayTime =
155
- hourFormat === '12h' ? formatDisplayTime12h : formatDisplayTime24h;
156
154
  const overlayText = nativeValue
157
- ? formatDisplayTime(nativeValue, false)
155
+ ? formatLocaleTime(nativeValue, locale, hourFormat, false)
158
156
  : placeholder;
159
157
  const showsOverlay = !!overlayText && !(isFocused && isSegmentEditable);
160
158
 
@@ -69,9 +69,8 @@ import {focusOutlineStyles} from '../utils/focusOutline.stylex';
69
69
  import {rtlStyles} from '../utils/rtlStyles';
70
70
  import {themeProps} from '../utils/themeProps';
71
71
  import {normalizeDayOfWeek} from '../utils/dateTypes';
72
+ import {formatLocaleTime} from '../utils/timeFormat';
72
73
  import {
73
- formatDisplayTime12h,
74
- formatDisplayTime24h,
75
74
  formatISOTime,
76
75
  isImeKeyEvent,
77
76
  isRenderable,
@@ -689,12 +688,9 @@ export function TouchDateTimeField({
689
688
  const timeDisplayValue = useMemo(() => {
690
689
  const displayTime = normalizedValueTime ?? draftTime;
691
690
  return displayTime
692
- ? (hourFormat === '12h' ? formatDisplayTime12h : formatDisplayTime24h)(
693
- displayTime,
694
- hasSeconds,
695
- )
691
+ ? formatLocaleTime(displayTime, locale, hourFormat, hasSeconds)
696
692
  : '';
697
- }, [draftTime, normalizedValueTime, hourFormat, hasSeconds]);
693
+ }, [draftTime, normalizedValueTime, locale, hourFormat, hasSeconds]);
698
694
 
699
695
  const timeBoundsForDate = useCallback(
700
696
  (date: ISODateString | undefined) => ({