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

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 (1575) 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/AppShell/AppShell.d.ts.map +1 -1
  5. package/dist/AppShell/AppShell.js +183 -5
  6. package/dist/AppShell/observeMainOverflow.d.ts +9 -0
  7. package/dist/AppShell/observeMainOverflow.d.ts.map +1 -0
  8. package/dist/AppShell/observeMainOverflow.js +125 -0
  9. package/dist/Avatar/Avatar.d.ts.map +1 -1
  10. package/dist/Avatar/Avatar.js +12 -3
  11. package/dist/Badge/Badge.d.ts.map +1 -1
  12. package/dist/Badge/Badge.js +8 -1
  13. package/dist/BottomSheet/BottomSheet.js +1 -1
  14. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
  15. package/dist/BottomSheet/BottomSheetPanel.js +2 -1
  16. package/dist/BottomSheet/useSheetGestures.d.ts +12 -0
  17. package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
  18. package/dist/BottomSheet/useSheetGestures.js +30 -3
  19. package/dist/Button/Button.js +4 -4
  20. package/dist/Carousel/Carousel.d.ts +3 -1
  21. package/dist/Carousel/Carousel.d.ts.map +1 -1
  22. package/dist/Carousel/Carousel.js +12 -3
  23. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  24. package/dist/CheckboxInput/CheckboxInput.js +6 -5
  25. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  26. package/dist/ClickableCard/ClickableCard.js +37 -4
  27. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  28. package/dist/ComplexSelector/ComplexSelector.js +49 -6
  29. package/dist/DateInput/DateInput.d.ts.map +1 -1
  30. package/dist/DateInput/DateInput.js +12 -4
  31. package/dist/DateInput/MonthScroller.d.ts.map +1 -1
  32. package/dist/DateInput/MonthScroller.js +108 -23
  33. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  34. package/dist/DateInput/TouchDateField.js +8 -3
  35. package/dist/DateInput/Wheel.d.ts.map +1 -1
  36. package/dist/DateInput/Wheel.js +11 -7
  37. package/dist/DateInput/usePointerDragScroll.d.ts +10 -1
  38. package/dist/DateInput/usePointerDragScroll.d.ts.map +1 -1
  39. package/dist/DateInput/usePointerDragScroll.js +25 -9
  40. package/dist/DateInput/useScrollSettle.d.ts +3 -1
  41. package/dist/DateInput/useScrollSettle.d.ts.map +1 -1
  42. package/dist/DateInput/useScrollSettle.js +37 -8
  43. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  44. package/dist/DateRangeInput/DateRangeInput.js +9 -5
  45. package/dist/DateTimeInput/DateTimeInput.d.ts +5 -2
  46. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  47. package/dist/DateTimeInput/DateTimeInput.js +23 -12
  48. package/dist/DateTimeInput/NativeTimeSegment.d.ts.map +1 -1
  49. package/dist/DateTimeInput/NativeTimeSegment.js +5 -4
  50. package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
  51. package/dist/DateTimeInput/TouchDateTimeField.js +4 -3
  52. package/dist/Dialog/Dialog.d.ts.map +1 -1
  53. package/dist/Dialog/Dialog.js +34 -9
  54. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  55. package/dist/Dialog/DialogHeader.js +5 -4
  56. package/dist/Divider/Divider.d.ts.map +1 -1
  57. package/dist/Divider/Divider.js +2 -1
  58. package/dist/Drawer/Drawer.d.ts +1 -0
  59. package/dist/Drawer/Drawer.d.ts.map +1 -1
  60. package/dist/Drawer/Drawer.js +7 -2
  61. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  62. package/dist/DropdownMenu/DropdownMenu.js +35 -22
  63. package/dist/DropdownMenu/DropdownMenuGroup.d.ts.map +1 -1
  64. package/dist/DropdownMenu/DropdownMenuGroup.js +2 -1
  65. package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts.map +1 -1
  66. package/dist/DropdownMenu/MenuBottomSheetActionList.js +6 -5
  67. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts +20 -2
  68. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts.map +1 -1
  69. package/dist/DropdownMenu/lazyMenuBottomSheet.js +31 -3
  70. package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
  71. package/dist/DropdownMenu/renderDropdownItems.js +21 -16
  72. package/dist/EmptyState/EmptyState.d.ts.map +1 -1
  73. package/dist/EmptyState/EmptyState.js +2 -1
  74. package/dist/Field/FieldLabel.d.ts +1 -1
  75. package/dist/Field/FieldLabel.d.ts.map +1 -1
  76. package/dist/Field/FieldLabel.js +31 -6
  77. package/dist/Field/InputClearButton.js +3 -3
  78. package/dist/Field/PanelSearchInput.js +2 -2
  79. package/dist/FieldStatus/FieldStatus.d.ts +3 -0
  80. package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
  81. package/dist/FieldStatus/FieldStatus.js +3 -2
  82. package/dist/FileInput/FileInput.d.ts +3 -0
  83. package/dist/FileInput/FileInput.d.ts.map +1 -1
  84. package/dist/FileInput/FileInput.js +66 -34
  85. package/dist/Heading/Heading.js +1 -1
  86. package/dist/Icon/Icon.js +1 -1
  87. package/dist/Indicator/CheckIndicator.d.ts.map +1 -1
  88. package/dist/Indicator/CheckIndicator.js +2 -1
  89. package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -1
  90. package/dist/Indicator/CheckboxIndicator.js +3 -1
  91. package/dist/Indicator/RadioIndicator.d.ts.map +1 -1
  92. package/dist/Indicator/RadioIndicator.js +3 -1
  93. package/dist/Item/Item.d.ts.map +1 -1
  94. package/dist/Item/Item.js +21 -7
  95. package/dist/Item/ItemSwipeLayer.js +1 -1
  96. package/dist/Layer/popoverOperations.d.ts +27 -0
  97. package/dist/Layer/popoverOperations.d.ts.map +1 -0
  98. package/dist/Layer/popoverOperations.js +159 -0
  99. package/dist/Layer/useLayer.d.ts +1 -1
  100. package/dist/Layer/useLayer.d.ts.map +1 -1
  101. package/dist/Layer/useLayer.js +120 -65
  102. package/dist/Layer/useTouchTrigger.d.ts +9 -0
  103. package/dist/Layer/useTouchTrigger.d.ts.map +1 -1
  104. package/dist/Layer/useTouchTrigger.js +1 -1
  105. package/dist/Layout/Layout.js +1 -1
  106. package/dist/Layout/LayoutContent.js +1 -1
  107. package/dist/Layout/LayoutFooter.js +1 -1
  108. package/dist/Layout/LayoutHeader.js +1 -1
  109. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  110. package/dist/Lightbox/Lightbox.js +5 -0
  111. package/dist/Link/Link.d.ts.map +1 -1
  112. package/dist/Link/Link.js +18 -4
  113. package/dist/List/List.js +1 -1
  114. package/dist/List/ListItem.js +3 -3
  115. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  116. package/dist/MobileNav/MobileNav.js +7 -2
  117. package/dist/MultiSelector/MultiSelector.d.ts +1 -1
  118. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  119. package/dist/MultiSelector/MultiSelector.js +45 -19
  120. package/dist/NavMenu/NavHeadingMenuItem.d.ts.map +1 -1
  121. package/dist/NavMenu/NavHeadingMenuItem.js +5 -29
  122. package/dist/NumberInput/NumberInput.d.ts +3 -1
  123. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  124. package/dist/NumberInput/NumberInput.js +21 -4
  125. package/dist/NumberInput/numberParser.d.ts +3 -0
  126. package/dist/NumberInput/numberParser.d.ts.map +1 -1
  127. package/dist/NumberInput/numberParser.js +7 -44
  128. package/dist/Outline/Outline.d.ts.map +1 -1
  129. package/dist/Outline/Outline.js +27 -0
  130. package/dist/Popover/Popover.d.ts.map +1 -1
  131. package/dist/Popover/Popover.js +32 -12
  132. package/dist/Popover/usePopover.d.ts.map +1 -1
  133. package/dist/Popover/usePopover.js +10 -3
  134. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  135. package/dist/PowerSearch/PowerSearch.js +37 -30
  136. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  137. package/dist/ProgressBar/ProgressBar.js +16 -12
  138. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  139. package/dist/RadioList/RadioListItem.js +11 -3
  140. package/dist/Resizable/useResizable.d.ts.map +1 -1
  141. package/dist/Resizable/useResizable.js +81 -12
  142. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  143. package/dist/SegmentedControl/SegmentedControlItem.js +4 -1
  144. package/dist/Selector/Selector.d.ts.map +1 -1
  145. package/dist/Selector/Selector.js +9 -6
  146. package/dist/Selector/hooks.js +2 -2
  147. package/dist/Selector/useSelectorPresentation.d.ts +8 -1
  148. package/dist/Selector/useSelectorPresentation.d.ts.map +1 -1
  149. package/dist/Selector/useSelectorPresentation.js +20 -4
  150. package/dist/SideNav/SideNavItem.d.ts +2 -2
  151. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  152. package/dist/SideNav/SideNavItem.js +18 -7
  153. package/dist/Skeleton/Skeleton.d.ts.map +1 -1
  154. package/dist/Skeleton/Skeleton.js +1 -1
  155. package/dist/Slider/Slider.d.ts.map +1 -1
  156. package/dist/Slider/Slider.js +100 -12
  157. package/dist/Spinner/Spinner.d.ts.map +1 -1
  158. package/dist/Spinner/Spinner.js +3 -3
  159. package/dist/Stack/Stack.js +1 -1
  160. package/dist/Stack/StackItem.js +1 -1
  161. package/dist/Stepper/Step.d.ts.map +1 -1
  162. package/dist/Stepper/Step.js +26 -6
  163. package/dist/Switch/Switch.d.ts.map +1 -1
  164. package/dist/Switch/Switch.js +10 -3
  165. package/dist/TabList/TabList.d.ts.map +1 -1
  166. package/dist/TabList/TabList.js +16 -1
  167. package/dist/Table/Table.d.ts.map +1 -1
  168. package/dist/Table/Table.js +36 -10
  169. package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
  170. package/dist/Table/plugins/columnResize/useTableColumnResize.js +9 -1
  171. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  172. package/dist/Table/plugins/sortable/useTableSortable.js +46 -58
  173. package/dist/Text/Text.js +1 -1
  174. package/dist/Text/useTruncation.d.ts.map +1 -1
  175. package/dist/Text/useTruncation.js +23 -5
  176. package/dist/TextArea/TextArea.d.ts +1 -1
  177. package/dist/TextArea/TextArea.d.ts.map +1 -1
  178. package/dist/TextArea/TextArea.js +13 -2
  179. package/dist/TextInput/TextInput.d.ts.map +1 -1
  180. package/dist/TextInput/TextInput.js +3 -3
  181. package/dist/TimeInput/TimeInput.d.ts +6 -2
  182. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  183. package/dist/TimeInput/TimeInput.js +21 -14
  184. package/dist/TimeInput/TouchTimeField.d.ts.map +1 -1
  185. package/dist/TimeInput/TouchTimeField.js +5 -4
  186. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  187. package/dist/Timestamp/Timestamp.js +2 -2
  188. package/dist/Timestamp/TimestampHoverCard.js +4 -4
  189. package/dist/Toast/Toast.d.ts.map +1 -1
  190. package/dist/Toast/Toast.js +60 -20
  191. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  192. package/dist/Toast/ToastViewport.js +101 -54
  193. package/dist/ToggleButton/ToggleButtonGroup.d.ts +7 -1
  194. package/dist/ToggleButton/ToggleButtonGroup.d.ts.map +1 -1
  195. package/dist/ToggleButton/ToggleButtonGroup.js +16 -2
  196. package/dist/Token/Token.d.ts +1 -1
  197. package/dist/Token/Token.d.ts.map +1 -1
  198. package/dist/Token/Token.js +52 -5
  199. package/dist/Token/TokenLink.d.ts.map +1 -1
  200. package/dist/Token/TokenLink.js +14 -2
  201. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  202. package/dist/Tokenizer/Tokenizer.js +95 -54
  203. package/dist/Tokenizer/TokenizerBottomSheet.d.ts.map +1 -1
  204. package/dist/Tokenizer/TokenizerBottomSheet.js +11 -17
  205. package/dist/Tokenizer/TokenizerClearAllMessageContext.d.ts +2 -0
  206. package/dist/Tokenizer/TokenizerClearAllMessageContext.d.ts.map +1 -0
  207. package/dist/Tokenizer/TokenizerClearAllMessageContext.js +17 -0
  208. package/dist/Toolbar/Toolbar.d.ts.map +1 -1
  209. package/dist/Toolbar/Toolbar.js +2 -1
  210. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  211. package/dist/TopNav/TopNavMegaMenu.js +3 -0
  212. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  213. package/dist/TopNav/TopNavMenu.js +1 -0
  214. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  215. package/dist/TreeList/TreeListItem.js +27 -4
  216. package/dist/Typeahead/BaseTypeahead.d.ts +4 -4
  217. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  218. package/dist/Typeahead/BaseTypeahead.js +52 -9
  219. package/dist/Typeahead/Typeahead.d.ts +1 -1
  220. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  221. package/dist/Typeahead/Typeahead.js +43 -9
  222. package/dist/astryx.css +26 -5
  223. package/dist/gestures/GestureArena.d.ts +32 -1
  224. package/dist/gestures/GestureArena.d.ts.map +1 -1
  225. package/dist/gestures/GestureArena.js +110 -9
  226. package/dist/gestures/GestureHost.d.ts +351 -0
  227. package/dist/gestures/GestureHost.d.ts.map +1 -0
  228. package/dist/gestures/GestureHost.js +1773 -0
  229. package/dist/gestures/GestureRecognizer.d.ts +13 -1
  230. package/dist/gestures/GestureRecognizer.d.ts.map +1 -1
  231. package/dist/gestures/GestureRecognizer.js +19 -1
  232. package/dist/gestures/LongPressGestureRecognizer.d.ts +1 -0
  233. package/dist/gestures/LongPressGestureRecognizer.d.ts.map +1 -1
  234. package/dist/gestures/LongPressGestureRecognizer.js +3 -0
  235. package/dist/gestures/PanGestureRecognizer.d.ts +1 -0
  236. package/dist/gestures/PanGestureRecognizer.d.ts.map +1 -1
  237. package/dist/gestures/PanGestureRecognizer.js +3 -0
  238. package/dist/gestures/PinchGestureRecognizer.d.ts +31 -0
  239. package/dist/gestures/PinchGestureRecognizer.d.ts.map +1 -0
  240. package/dist/gestures/PinchGestureRecognizer.js +128 -0
  241. package/dist/gestures/PressTracker.d.ts +112 -0
  242. package/dist/gestures/PressTracker.d.ts.map +1 -0
  243. package/dist/gestures/PressTracker.js +267 -0
  244. package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts +71 -0
  245. package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts.map +1 -0
  246. package/dist/gestures/ScreenEdgePanGestureRecognizer.js +223 -0
  247. package/dist/gestures/SwipeGestureRecognizer.d.ts +37 -0
  248. package/dist/gestures/SwipeGestureRecognizer.d.ts.map +1 -0
  249. package/dist/gestures/SwipeGestureRecognizer.js +148 -0
  250. package/dist/gestures/TapGestureRecognizer.d.ts +1 -0
  251. package/dist/gestures/TapGestureRecognizer.d.ts.map +1 -1
  252. package/dist/gestures/TapGestureRecognizer.js +3 -0
  253. package/dist/gestures/VelocityTracker.d.ts +6 -2
  254. package/dist/gestures/VelocityTracker.d.ts.map +1 -1
  255. package/dist/gestures/VelocityTracker.js +7 -3
  256. package/dist/gestures/haptics.d.ts +65 -0
  257. package/dist/gestures/haptics.d.ts.map +1 -0
  258. package/dist/gestures/haptics.js +182 -0
  259. package/dist/gestures/index.d.ts +37 -0
  260. package/dist/gestures/index.d.ts.map +1 -0
  261. package/dist/gestures/index.js +25 -0
  262. package/dist/gestures/nativeScroll.d.ts +42 -0
  263. package/dist/gestures/nativeScroll.d.ts.map +1 -0
  264. package/dist/gestures/nativeScroll.js +228 -0
  265. package/dist/gestures/touchAction.d.ts +60 -0
  266. package/dist/gestures/touchAction.d.ts.map +1 -0
  267. package/dist/gestures/touchAction.js +157 -0
  268. package/dist/gestures/touchActionRule.d.ts +34 -0
  269. package/dist/gestures/touchActionRule.d.ts.map +1 -0
  270. package/dist/gestures/touchActionRule.js +140 -0
  271. package/dist/gestures/types.d.ts +18 -7
  272. package/dist/gestures/types.d.ts.map +1 -1
  273. package/dist/gestures/types.js +22 -2
  274. package/dist/gestures/useGestureRecognizer.d.ts +56 -0
  275. package/dist/gestures/useGestureRecognizer.d.ts.map +1 -0
  276. package/dist/gestures/useGestureRecognizer.js +226 -0
  277. package/dist/hooks/index.d.ts +1 -1
  278. package/dist/hooks/index.d.ts.map +1 -1
  279. package/dist/hooks/modalAnnounce.d.ts.map +1 -1
  280. package/dist/hooks/modalAnnounce.js +107 -61
  281. package/dist/hooks/scrollKeyboardDelegation.d.ts.map +1 -1
  282. package/dist/hooks/scrollKeyboardDelegation.js +7 -3
  283. package/dist/hooks/useAdaptivePresentation.d.ts.map +1 -1
  284. package/dist/hooks/useAdaptivePresentation.js +4 -1
  285. package/dist/hooks/useAnnounce.d.ts +101 -42
  286. package/dist/hooks/useAnnounce.d.ts.map +1 -1
  287. package/dist/hooks/useAnnounce.js +161 -75
  288. package/dist/hooks/useAnnounceRenderedText.d.ts +11 -3
  289. package/dist/hooks/useAnnounceRenderedText.d.ts.map +1 -1
  290. package/dist/hooks/useAnnounceRenderedText.js +5 -3
  291. package/dist/hooks/useBusyAnnouncement.d.ts.map +1 -1
  292. package/dist/hooks/useBusyAnnouncement.js +6 -12
  293. package/dist/hooks/useMenuHover.d.ts.map +1 -1
  294. package/dist/hooks/useMenuHover.js +12 -1
  295. package/dist/hooks/useScrollOverflow.d.ts +2 -1
  296. package/dist/hooks/useScrollOverflow.d.ts.map +1 -1
  297. package/dist/hooks/useScrollOverflow.js +56 -10
  298. package/dist/i18n/generated-locales/af-ZA.generated.d.ts.map +1 -1
  299. package/dist/i18n/generated-locales/af-ZA.generated.js +0 -5
  300. package/dist/i18n/generated-locales/ar-SA.generated.d.ts.map +1 -1
  301. package/dist/i18n/generated-locales/ar-SA.generated.js +0 -5
  302. package/dist/i18n/generated-locales/ca-ES.generated.d.ts.map +1 -1
  303. package/dist/i18n/generated-locales/ca-ES.generated.js +0 -5
  304. package/dist/i18n/generated-locales/cs-CZ.generated.d.ts.map +1 -1
  305. package/dist/i18n/generated-locales/cs-CZ.generated.js +0 -5
  306. package/dist/i18n/generated-locales/da-DK.generated.d.ts.map +1 -1
  307. package/dist/i18n/generated-locales/da-DK.generated.js +0 -5
  308. package/dist/i18n/generated-locales/de-DE.generated.d.ts.map +1 -1
  309. package/dist/i18n/generated-locales/de-DE.generated.js +0 -5
  310. package/dist/i18n/generated-locales/el-GR.generated.d.ts.map +1 -1
  311. package/dist/i18n/generated-locales/el-GR.generated.js +0 -5
  312. package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
  313. package/dist/i18n/generated-locales/en.generated.js +8 -5
  314. package/dist/i18n/generated-locales/es-ES.generated.d.ts.map +1 -1
  315. package/dist/i18n/generated-locales/es-ES.generated.js +0 -5
  316. package/dist/i18n/generated-locales/fi-FI.generated.d.ts.map +1 -1
  317. package/dist/i18n/generated-locales/fi-FI.generated.js +0 -5
  318. package/dist/i18n/generated-locales/fr-FR.generated.d.ts.map +1 -1
  319. package/dist/i18n/generated-locales/fr-FR.generated.js +0 -5
  320. package/dist/i18n/generated-locales/he-IL.generated.d.ts.map +1 -1
  321. package/dist/i18n/generated-locales/he-IL.generated.js +0 -5
  322. package/dist/i18n/generated-locales/hu-HU.generated.d.ts.map +1 -1
  323. package/dist/i18n/generated-locales/hu-HU.generated.js +0 -5
  324. package/dist/i18n/generated-locales/it-IT.generated.d.ts.map +1 -1
  325. package/dist/i18n/generated-locales/it-IT.generated.js +0 -5
  326. package/dist/i18n/generated-locales/ja-JP.generated.d.ts.map +1 -1
  327. package/dist/i18n/generated-locales/ja-JP.generated.js +0 -5
  328. package/dist/i18n/generated-locales/ko-KR.generated.d.ts.map +1 -1
  329. package/dist/i18n/generated-locales/ko-KR.generated.js +0 -5
  330. package/dist/i18n/generated-locales/nl-NL.generated.d.ts.map +1 -1
  331. package/dist/i18n/generated-locales/nl-NL.generated.js +0 -5
  332. package/dist/i18n/generated-locales/no-NO.generated.d.ts.map +1 -1
  333. package/dist/i18n/generated-locales/no-NO.generated.js +0 -5
  334. package/dist/i18n/generated-locales/pl-PL.generated.d.ts.map +1 -1
  335. package/dist/i18n/generated-locales/pl-PL.generated.js +0 -5
  336. package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
  337. package/dist/i18n/generated-locales/pseudo.generated.js +8 -5
  338. package/dist/i18n/generated-locales/pt-BR.generated.d.ts.map +1 -1
  339. package/dist/i18n/generated-locales/pt-BR.generated.js +0 -5
  340. package/dist/i18n/generated-locales/pt-PT.generated.d.ts.map +1 -1
  341. package/dist/i18n/generated-locales/pt-PT.generated.js +0 -5
  342. package/dist/i18n/generated-locales/ro-RO.generated.d.ts.map +1 -1
  343. package/dist/i18n/generated-locales/ro-RO.generated.js +0 -5
  344. package/dist/i18n/generated-locales/ru-RU.generated.d.ts.map +1 -1
  345. package/dist/i18n/generated-locales/ru-RU.generated.js +0 -5
  346. package/dist/i18n/generated-locales/sr-SP.generated.d.ts.map +1 -1
  347. package/dist/i18n/generated-locales/sr-SP.generated.js +0 -5
  348. package/dist/i18n/generated-locales/sv-SE.generated.d.ts.map +1 -1
  349. package/dist/i18n/generated-locales/sv-SE.generated.js +0 -5
  350. package/dist/i18n/generated-locales/tr-TR.generated.d.ts.map +1 -1
  351. package/dist/i18n/generated-locales/tr-TR.generated.js +0 -5
  352. package/dist/i18n/generated-locales/uk-UA.generated.d.ts.map +1 -1
  353. package/dist/i18n/generated-locales/uk-UA.generated.js +0 -5
  354. package/dist/i18n/generated-locales/vi-VN.generated.d.ts.map +1 -1
  355. package/dist/i18n/generated-locales/vi-VN.generated.js +0 -5
  356. package/dist/i18n/generated-locales/zh-CN.generated.d.ts.map +1 -1
  357. package/dist/i18n/generated-locales/zh-CN.generated.js +0 -5
  358. package/dist/i18n/generated-locales/zh-TW.generated.d.ts.map +1 -1
  359. package/dist/i18n/generated-locales/zh-TW.generated.js +0 -5
  360. package/dist/i18n/useListFormatter.d.ts +9 -0
  361. package/dist/i18n/useListFormatter.d.ts.map +1 -0
  362. package/dist/i18n/useListFormatter.js +41 -0
  363. package/dist/motion/animator.d.ts +83 -8
  364. package/dist/motion/animator.d.ts.map +1 -1
  365. package/dist/motion/animator.js +701 -119
  366. package/dist/motion/coast.d.ts +4 -1
  367. package/dist/motion/coast.d.ts.map +1 -1
  368. package/dist/motion/coast.js +4 -2
  369. package/dist/motion/reducedMotion.d.ts.map +1 -1
  370. package/dist/motion/reducedMotion.js +6 -2
  371. package/dist/motion/reducedMotionPlan.d.ts +7 -0
  372. package/dist/motion/reducedMotionPlan.d.ts.map +1 -1
  373. package/dist/motion/reducedMotionPlan.js +14 -1
  374. package/dist/motion/resolveMotion.d.ts +42 -0
  375. package/dist/motion/resolveMotion.d.ts.map +1 -0
  376. package/dist/motion/resolveMotion.js +43 -0
  377. package/dist/motion/roleValue.d.ts +2 -1
  378. package/dist/motion/roleValue.d.ts.map +1 -1
  379. package/dist/motion/roleValue.js +2 -1
  380. package/dist/motion/uikit/timing.d.ts +7 -1
  381. package/dist/motion/uikit/timing.d.ts.map +1 -1
  382. package/dist/motion/uikit/timing.js +19 -1
  383. package/dist/theme/defineTheme.d.ts +19 -5
  384. package/dist/theme/defineTheme.d.ts.map +1 -1
  385. package/dist/theme/defineTheme.js +64 -4
  386. package/dist/theme/domainTokens/domainTokenDefaults.d.ts +3 -0
  387. package/dist/theme/domainTokens/domainTokenDefaults.d.ts.map +1 -0
  388. package/dist/theme/domainTokens/domainTokenDefaults.js +19 -0
  389. package/dist/theme/domainTokens/index.d.ts +5 -4
  390. package/dist/theme/domainTokens/index.d.ts.map +1 -1
  391. package/dist/theme/domainTokens/index.js +5 -9
  392. package/dist/theme/index.d.ts +1 -0
  393. package/dist/theme/index.d.ts.map +1 -1
  394. package/dist/theme/motionKnobs.d.ts +56 -0
  395. package/dist/theme/motionKnobs.d.ts.map +1 -0
  396. package/dist/theme/motionKnobs.js +48 -0
  397. package/dist/theme/resolveThemeValues.d.ts +11 -4
  398. package/dist/theme/resolveThemeValues.d.ts.map +1 -1
  399. package/dist/theme/resolveThemeValues.js +40 -4
  400. package/dist/theme/themeAdaptations.d.ts +7 -3
  401. package/dist/theme/themeAdaptations.d.ts.map +1 -1
  402. package/dist/theme/themeAdaptations.js +36 -7
  403. package/dist/theme/themeMotion.d.ts +96 -0
  404. package/dist/theme/themeMotion.d.ts.map +1 -0
  405. package/dist/theme/themeMotion.js +177 -0
  406. package/dist/theme/tokenReferences.d.ts +31 -0
  407. package/dist/theme/tokenReferences.d.ts.map +1 -0
  408. package/dist/theme/tokenReferences.js +132 -0
  409. package/dist/theme/tokens.d.ts +1 -0
  410. package/dist/theme/tokens.d.ts.map +1 -1
  411. package/dist/theme/tokens.js +9 -129
  412. package/dist/theme/tokens.stylex.d.ts +12 -0
  413. package/dist/theme/tokens.stylex.d.ts.map +1 -1
  414. package/dist/theme/tokens.stylex.js +12 -0
  415. package/dist/utils/focusOutline.stylex.d.ts +6 -0
  416. package/dist/utils/focusOutline.stylex.d.ts.map +1 -1
  417. package/dist/utils/focusOutline.stylex.js +7 -0
  418. package/dist/utils/focusReturn.d.ts +17 -1
  419. package/dist/utils/focusReturn.d.ts.map +1 -1
  420. package/dist/utils/focusReturn.js +11 -4
  421. package/dist/utils/getNodeText.d.ts +8 -0
  422. package/dist/utils/getNodeText.d.ts.map +1 -0
  423. package/dist/utils/getNodeText.js +37 -0
  424. package/dist/utils/interactionModality.d.ts +11 -2
  425. package/dist/utils/interactionModality.d.ts.map +1 -1
  426. package/dist/utils/interactionModality.js +58 -5
  427. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
  428. package/dist/utils/interactionOverlay.stylex.js +17 -8
  429. package/dist/utils/plainDate.d.ts +2 -0
  430. package/dist/utils/plainDate.d.ts.map +1 -1
  431. package/dist/utils/plainDate.js +46 -3
  432. package/dist/utils/presentation.d.ts +50 -0
  433. package/dist/utils/presentation.d.ts.map +1 -0
  434. package/dist/utils/presentation.js +125 -0
  435. package/dist/utils/pressFeedback.d.ts.map +1 -1
  436. package/dist/utils/pressFeedback.js +20 -1
  437. package/dist/utils/primaryClick.d.ts +11 -0
  438. package/dist/utils/primaryClick.d.ts.map +1 -0
  439. package/dist/utils/primaryClick.js +25 -0
  440. package/dist/utils/sharedMutationObserver.d.ts +19 -11
  441. package/dist/utils/sharedMutationObserver.d.ts.map +1 -1
  442. package/dist/utils/sharedMutationObserver.js +66 -26
  443. package/dist/utils/timeFormat.d.ts +47 -0
  444. package/dist/utils/timeFormat.d.ts.map +1 -0
  445. package/dist/utils/timeFormat.js +240 -0
  446. package/dist/utils/touchPresentation.d.ts +2 -2
  447. package/dist/utils/touchPresentation.d.ts.map +1 -1
  448. package/dist/utils/touchPresentation.js +13 -8
  449. package/dist/utils/touchPresentation.stylex.d.ts +15 -0
  450. package/dist/utils/touchPresentation.stylex.d.ts.map +1 -0
  451. package/dist/utils/touchPresentation.stylex.js +33 -0
  452. package/dist/utils/touchQueries.d.ts +13 -0
  453. package/dist/utils/touchQueries.d.ts.map +1 -0
  454. package/dist/utils/touchQueries.js +15 -0
  455. package/dist/utils/unicodeDigits.d.ts +20 -0
  456. package/dist/utils/unicodeDigits.d.ts.map +1 -0
  457. package/dist/utils/unicodeDigits.js +70 -0
  458. package/dist/utils/useFocusAcrossSwap.d.ts +19 -0
  459. package/dist/utils/useFocusAcrossSwap.d.ts.map +1 -0
  460. package/dist/utils/useFocusAcrossSwap.js +41 -0
  461. package/locales/af-ZA.json +0 -21
  462. package/locales/ar-SA.json +0 -21
  463. package/locales/ca-ES.json +0 -21
  464. package/locales/cs-CZ.json +0 -21
  465. package/locales/da-DK.json +0 -21
  466. package/locales/de-DE.json +0 -21
  467. package/locales/el-GR.json +0 -21
  468. package/locales/en.json +35 -23
  469. package/locales/es-ES.json +0 -21
  470. package/locales/fi-FI.json +0 -21
  471. package/locales/fr-FR.json +0 -21
  472. package/locales/he-IL.json +0 -21
  473. package/locales/hu-HU.json +0 -21
  474. package/locales/it-IT.json +0 -21
  475. package/locales/ja-JP.json +0 -21
  476. package/locales/ko-KR.json +0 -21
  477. package/locales/nl-NL.json +0 -21
  478. package/locales/no-NO.json +0 -21
  479. package/locales/pl-PL.json +0 -21
  480. package/locales/pseudo.json +23 -14
  481. package/locales/pt-BR.json +0 -21
  482. package/locales/pt-PT.json +0 -21
  483. package/locales/ro-RO.json +0 -21
  484. package/locales/ru-RU.json +0 -21
  485. package/locales/sr-SP.json +0 -21
  486. package/locales/sv-SE.json +0 -21
  487. package/locales/tr-TR.json +0 -21
  488. package/locales/uk-UA.json +0 -21
  489. package/locales/vi-VN.json +0 -21
  490. package/locales/zh-CN.json +0 -21
  491. package/locales/zh-TW.json +0 -21
  492. package/package.json +19 -5
  493. package/src/AlertDialog/AlertDialog.tsx +6 -5
  494. package/src/AppShell/AppShell.doc.mjs +1 -1
  495. package/src/AppShell/AppShell.spec.md +9 -12
  496. package/src/AppShell/AppShell.tsx +225 -5
  497. package/src/AppShell/observeMainOverflow.ts +143 -0
  498. package/src/Avatar/Avatar.spec.md +22 -22
  499. package/src/Avatar/Avatar.tsx +18 -1
  500. package/src/Badge/Badge.doc.mjs +1 -1
  501. package/src/Badge/Badge.tsx +20 -2
  502. package/src/BottomSheet/BottomSheet.tsx +1 -1
  503. package/src/BottomSheet/BottomSheetPanel.tsx +2 -1
  504. package/src/BottomSheet/useSheetGestures.ts +37 -6
  505. package/src/Button/Button.tsx +4 -4
  506. package/src/Calendar/Calendar.spec.md +87 -48
  507. package/src/Carousel/Carousel.doc.mjs +1 -1
  508. package/src/Carousel/Carousel.spec.md +9 -9
  509. package/src/Carousel/Carousel.tsx +10 -2
  510. package/src/Chat/ChatComposer.spec.md +75 -59
  511. package/src/Chat/ChatComposerTokenElement.spec.md +45 -33
  512. package/src/Chat/ChatDictationButton.spec.md +126 -81
  513. package/src/Chat/ChatLayout.spec.md +41 -36
  514. package/src/Chat/ChatLayoutScrollButton.spec.md +87 -103
  515. package/src/Chat/ChatMessage.spec.md +64 -65
  516. package/src/Chat/ChatSendButton.spec.md +78 -67
  517. package/src/CheckboxInput/CheckboxInput.tsx +6 -5
  518. package/src/Citation/Citation.spec.md +60 -47
  519. package/src/ClickableCard/ClickableCard.tsx +48 -4
  520. package/src/Collapsible/Collapsible.spec.md +2 -0
  521. package/src/Collapsible/CollapsibleGroup.spec.md +57 -29
  522. package/src/ComplexSelector/ComplexSelector.tsx +60 -6
  523. package/src/ContextMenu/ContextMenu.spec.md +84 -56
  524. package/src/ContextMenu/ContextMenuItem.spec.md +132 -0
  525. package/src/DateInput/DateInput.spec.md +74 -57
  526. package/src/DateInput/DateInput.tsx +29 -14
  527. package/src/DateInput/MonthScroller.tsx +108 -24
  528. package/src/DateInput/TouchDateField.tsx +14 -3
  529. package/src/DateInput/Wheel.tsx +9 -6
  530. package/src/DateInput/usePointerDragScroll.ts +34 -10
  531. package/src/DateInput/useScrollSettle.ts +38 -7
  532. package/src/DateRangeInput/DateRangeInput.tsx +34 -15
  533. package/src/DateTimeInput/DateTimeInput.doc.mjs +10 -8
  534. package/src/DateTimeInput/DateTimeInput.spec.md +75 -51
  535. package/src/DateTimeInput/DateTimeInput.tsx +46 -24
  536. package/src/DateTimeInput/NativeTimeSegment.tsx +4 -6
  537. package/src/DateTimeInput/TouchDateTimeField.tsx +3 -7
  538. package/src/Dialog/Dialog.tsx +42 -9
  539. package/src/Dialog/DialogHeader.tsx +5 -4
  540. package/src/Divider/Divider.tsx +2 -1
  541. package/src/Drawer/Drawer.spec.md +111 -80
  542. package/src/Drawer/Drawer.tsx +13 -2
  543. package/src/Drawer/DrawerHeader.spec.md +181 -0
  544. package/src/DropdownMenu/DropdownMenu.spec.md +198 -218
  545. package/src/DropdownMenu/DropdownMenu.tsx +43 -21
  546. package/src/DropdownMenu/DropdownMenuCheckboxItem.spec.md +192 -0
  547. package/src/DropdownMenu/DropdownMenuDivider.spec.md +25 -31
  548. package/src/DropdownMenu/DropdownMenuGroup.spec.md +145 -0
  549. package/src/DropdownMenu/DropdownMenuGroup.tsx +2 -1
  550. package/src/DropdownMenu/DropdownMenuItem.spec.md +48 -42
  551. package/src/DropdownMenu/DropdownMenuRadioGroup.spec.md +34 -37
  552. package/src/DropdownMenu/DropdownMenuRadioItem.spec.md +54 -53
  553. package/src/DropdownMenu/DropdownMenuSubMenu.spec.md +47 -41
  554. package/src/DropdownMenu/MenuBottomSheetActionList.tsx +6 -5
  555. package/src/DropdownMenu/lazyMenuBottomSheet.ts +36 -7
  556. package/src/DropdownMenu/renderDropdownItems.tsx +24 -19
  557. package/src/EmptyState/EmptyState.spec.md +35 -29
  558. package/src/EmptyState/EmptyState.tsx +2 -1
  559. package/src/Field/Field.doc.mjs +2 -1
  560. package/src/Field/FieldLabel.doc.mjs +4 -2
  561. package/src/Field/FieldLabel.spec.md +30 -21
  562. package/src/Field/FieldLabel.tsx +42 -7
  563. package/src/Field/InputClearButton.tsx +3 -3
  564. package/src/Field/PanelSearchInput.tsx +2 -2
  565. package/src/FieldStatus/FieldStatus.tsx +9 -2
  566. package/src/FileInput/FileInput.tsx +73 -29
  567. package/src/FormLayout/FormLayout.spec.md +11 -20
  568. package/src/Heading/Heading.tsx +1 -1
  569. package/src/Icon/Icon.tsx +1 -1
  570. package/src/Indicator/CheckIndicator.spec.md +47 -42
  571. package/src/Indicator/CheckIndicator.tsx +2 -1
  572. package/src/Indicator/CheckboxIndicator.spec.md +40 -37
  573. package/src/Indicator/CheckboxIndicator.tsx +3 -1
  574. package/src/Indicator/Indicator.spec.md +188 -0
  575. package/src/Indicator/RadioIndicator.tsx +3 -1
  576. package/src/Item/Item.tsx +16 -8
  577. package/src/Item/ItemSwipeLayer.tsx +1 -1
  578. package/src/Kbd/Kbd.spec.md +81 -38
  579. package/src/Layer/popoverOperations.ts +172 -0
  580. package/src/Layer/useLayer.tsx +145 -77
  581. package/src/Layer/useTouchTrigger.ts +1 -1
  582. package/src/Layout/Layout.spec.md +127 -131
  583. package/src/Layout/Layout.tsx +1 -1
  584. package/src/Layout/LayoutContent.spec.md +205 -0
  585. package/src/Layout/LayoutContent.tsx +1 -1
  586. package/src/Layout/LayoutFooter.spec.md +190 -0
  587. package/src/Layout/LayoutFooter.tsx +1 -1
  588. package/src/Layout/LayoutHeader.spec.md +193 -0
  589. package/src/Layout/LayoutHeader.tsx +1 -1
  590. package/src/Layout/LayoutPanel.spec.md +194 -0
  591. package/src/Lightbox/Lightbox.spec.md +249 -61
  592. package/src/Lightbox/Lightbox.tsx +5 -0
  593. package/src/Link/Link.spec.md +3 -2
  594. package/src/Link/Link.tsx +20 -2
  595. package/src/List/List.tsx +1 -1
  596. package/src/List/ListItem.spec.md +205 -0
  597. package/src/List/ListItem.tsx +3 -3
  598. package/src/MetadataList/MetadataList.spec.md +187 -0
  599. package/src/MetadataList/MetadataListItem.spec.md +165 -0
  600. package/src/MobileNav/MobileNav.tsx +9 -1
  601. package/src/MultiSelector/MultiSelector.spec.md +124 -114
  602. package/src/MultiSelector/MultiSelector.tsx +44 -15
  603. package/src/NavMenu/NavHeadingMenu.spec.md +1 -5
  604. package/src/NavMenu/NavHeadingMenuItem.tsx +5 -39
  605. package/src/NumberInput/NumberInput.doc.mjs +13 -7
  606. package/src/NumberInput/NumberInput.spec.md +59 -37
  607. package/src/NumberInput/NumberInput.tsx +37 -4
  608. package/src/NumberInput/numberParser.ts +7 -45
  609. package/src/Outline/Outline.spec.md +165 -69
  610. package/src/Outline/Outline.tsx +23 -0
  611. package/src/Outline/modules/parseOutlineFromMarkdown.spec.md +3 -4
  612. package/src/OverflowList/OverflowList.spec.md +102 -55
  613. package/src/Pagination/Pagination.spec.md +158 -84
  614. package/src/Popover/Popover.tsx +34 -14
  615. package/src/Popover/usePopover.tsx +10 -3
  616. package/src/PowerSearch/PowerSearch.tsx +42 -31
  617. package/src/ProgressBar/ProgressBar.spec.md +143 -119
  618. package/src/ProgressBar/ProgressBar.tsx +58 -10
  619. package/src/RadioList/RadioList.spec.md +1 -1
  620. package/src/RadioList/RadioListItem.tsx +11 -2
  621. package/src/Resizable/Resizable.spec.md +144 -124
  622. package/src/Resizable/useResizable.ts +82 -16
  623. package/src/SegmentedControl/SegmentedControlItem.tsx +11 -5
  624. package/src/Selector/Selector.tsx +16 -6
  625. package/src/Selector/hooks.ts +2 -2
  626. package/src/Selector/useSelectorPresentation.ts +31 -3
  627. package/src/SideNav/SideNavItem.spec.md +14 -24
  628. package/src/SideNav/SideNavItem.tsx +27 -10
  629. package/src/Skeleton/Skeleton.tsx +3 -1
  630. package/src/Slider/Slider.spec.md +18 -16
  631. package/src/Slider/Slider.tsx +117 -12
  632. package/src/Spinner/Spinner.tsx +5 -3
  633. package/src/Stack/Stack.tsx +1 -1
  634. package/src/Stack/StackItem.tsx +1 -1
  635. package/src/Stepper/Step.spec.md +36 -42
  636. package/src/Stepper/Step.tsx +33 -6
  637. package/src/Stepper/Stepper.doc.mjs +1 -1
  638. package/src/Switch/Switch.spec.md +1 -1
  639. package/src/Switch/Switch.tsx +11 -3
  640. package/src/TabList/TabList.tsx +16 -1
  641. package/src/Table/Table.spec.md +1 -1
  642. package/src/Table/Table.tsx +43 -11
  643. package/src/Table/plugins/columnResize/useTableColumnResize.tsx +8 -4
  644. package/src/Table/plugins/sortable/useTableSortable.tsx +44 -73
  645. package/src/Text/Text.tsx +1 -1
  646. package/src/Text/useTruncation.ts +23 -5
  647. package/src/TextArea/TextArea.spec.md +10 -13
  648. package/src/TextArea/TextArea.tsx +15 -1
  649. package/src/TextInput/TextInput.tsx +3 -1
  650. package/src/TimeInput/TimeInput.doc.mjs +8 -8
  651. package/src/TimeInput/TimeInput.spec.md +58 -61
  652. package/src/TimeInput/TimeInput.tsx +36 -18
  653. package/src/TimeInput/TouchTimeField.tsx +4 -6
  654. package/src/Timestamp/Timestamp.spec.md +6 -12
  655. package/src/Timestamp/Timestamp.tsx +6 -2
  656. package/src/Timestamp/TimestampHoverCard.tsx +4 -4
  657. package/src/Toast/Toast.spec.md +15 -24
  658. package/src/Toast/Toast.tsx +104 -36
  659. package/src/Toast/ToastViewport.tsx +121 -53
  660. package/src/ToggleButton/ToggleButtonGroup.tsx +20 -1
  661. package/src/Token/Token.doc.mjs +2 -2
  662. package/src/Token/Token.spec.md +52 -61
  663. package/src/Token/Token.tsx +75 -5
  664. package/src/Token/TokenLink.tsx +21 -7
  665. package/src/Tokenizer/Tokenizer.spec.md +18 -4
  666. package/src/Tokenizer/Tokenizer.tsx +102 -60
  667. package/src/Tokenizer/TokenizerBottomSheet.tsx +11 -17
  668. package/src/Tokenizer/TokenizerClearAllMessageContext.ts +21 -0
  669. package/src/Toolbar/Toolbar.spec.md +5 -6
  670. package/src/Toolbar/Toolbar.tsx +2 -1
  671. package/src/TopNav/TopNavMegaMenu.tsx +4 -1
  672. package/src/TopNav/TopNavMenu.tsx +1 -0
  673. package/src/TreeList/TreeListItem.tsx +26 -4
  674. package/src/Typeahead/BaseTypeahead.doc.mjs +3 -3
  675. package/src/Typeahead/BaseTypeahead.spec.md +45 -45
  676. package/src/Typeahead/BaseTypeahead.tsx +66 -11
  677. package/src/Typeahead/Typeahead.tsx +51 -9
  678. package/src/gestures/GestureArena.ts +111 -11
  679. package/src/gestures/GestureHost.ts +2064 -0
  680. package/src/gestures/GestureRecognizer.ts +21 -1
  681. package/src/gestures/LongPressGestureRecognizer.ts +4 -0
  682. package/src/gestures/PanGestureRecognizer.ts +4 -0
  683. package/src/gestures/PinchGestureRecognizer.ts +148 -0
  684. package/src/gestures/PressTracker.ts +386 -0
  685. package/src/gestures/README.md +420 -0
  686. package/src/gestures/ScreenEdgePanGestureRecognizer.ts +256 -0
  687. package/src/gestures/SwipeGestureRecognizer.ts +197 -0
  688. package/src/gestures/TapGestureRecognizer.ts +4 -0
  689. package/src/gestures/VelocityTracker.ts +10 -3
  690. package/src/gestures/haptics.ts +203 -0
  691. package/src/gestures/index.ts +79 -0
  692. package/src/gestures/nativeScroll.ts +277 -0
  693. package/src/gestures/touchAction.ts +191 -0
  694. package/src/gestures/touchActionRule.ts +157 -0
  695. package/src/gestures/types.ts +30 -9
  696. package/src/gestures/useGestureRecognizer.ts +305 -0
  697. package/src/hooks/index.ts +5 -1
  698. package/src/hooks/modalAnnounce.ts +129 -72
  699. package/src/hooks/scrollKeyboardDelegation.ts +9 -3
  700. package/src/hooks/useAdaptivePresentation.ts +4 -1
  701. package/src/hooks/useAnnounce.doc.mjs +35 -3
  702. package/src/hooks/useAnnounce.ts +209 -102
  703. package/src/hooks/useAnnounceRenderedText.ts +17 -3
  704. package/src/hooks/useBusyAnnouncement.ts +7 -10
  705. package/src/hooks/useMenuHover.ts +15 -1
  706. package/src/hooks/useScrollOverflow.doc.mjs +1 -1
  707. package/src/hooks/useScrollOverflow.ts +59 -10
  708. package/src/i18n/generated-locales/af-ZA.generated.ts +0 -7
  709. package/src/i18n/generated-locales/ar-SA.generated.ts +0 -6
  710. package/src/i18n/generated-locales/ca-ES.generated.ts +0 -7
  711. package/src/i18n/generated-locales/cs-CZ.generated.ts +0 -6
  712. package/src/i18n/generated-locales/da-DK.generated.ts +0 -6
  713. package/src/i18n/generated-locales/de-DE.generated.ts +0 -6
  714. package/src/i18n/generated-locales/el-GR.generated.ts +0 -7
  715. package/src/i18n/generated-locales/en.generated.ts +9 -6
  716. package/src/i18n/generated-locales/es-ES.generated.ts +0 -7
  717. package/src/i18n/generated-locales/fi-FI.generated.ts +0 -6
  718. package/src/i18n/generated-locales/fr-FR.generated.ts +0 -7
  719. package/src/i18n/generated-locales/he-IL.generated.ts +0 -6
  720. package/src/i18n/generated-locales/hu-HU.generated.ts +0 -6
  721. package/src/i18n/generated-locales/it-IT.generated.ts +0 -7
  722. package/src/i18n/generated-locales/ja-JP.generated.ts +0 -6
  723. package/src/i18n/generated-locales/ko-KR.generated.ts +0 -6
  724. package/src/i18n/generated-locales/nl-NL.generated.ts +0 -6
  725. package/src/i18n/generated-locales/no-NO.generated.ts +0 -6
  726. package/src/i18n/generated-locales/pl-PL.generated.ts +0 -7
  727. package/src/i18n/generated-locales/pseudo.generated.ts +9 -6
  728. package/src/i18n/generated-locales/pt-BR.generated.ts +0 -7
  729. package/src/i18n/generated-locales/pt-PT.generated.ts +0 -7
  730. package/src/i18n/generated-locales/ro-RO.generated.ts +0 -6
  731. package/src/i18n/generated-locales/ru-RU.generated.ts +0 -7
  732. package/src/i18n/generated-locales/sr-SP.generated.ts +0 -6
  733. package/src/i18n/generated-locales/sv-SE.generated.ts +0 -6
  734. package/src/i18n/generated-locales/tr-TR.generated.ts +0 -7
  735. package/src/i18n/generated-locales/uk-UA.generated.ts +0 -7
  736. package/src/i18n/generated-locales/vi-VN.generated.ts +0 -6
  737. package/src/i18n/generated-locales/zh-CN.generated.ts +0 -6
  738. package/src/i18n/generated-locales/zh-TW.generated.ts +0 -6
  739. package/src/i18n/useListFormatter.ts +42 -0
  740. package/src/motion/MEASUREMENTS.md +2 -1
  741. package/src/motion/README.md +113 -33
  742. package/src/motion/animator.ts +932 -130
  743. package/src/motion/coast.ts +10 -3
  744. package/src/motion/reducedMotion.ts +12 -2
  745. package/src/motion/reducedMotionPlan.ts +20 -1
  746. package/src/motion/resolveMotion.ts +68 -0
  747. package/src/motion/roleValue.ts +2 -1
  748. package/src/motion/uikit/timing.ts +15 -1
  749. package/src/theme/Theme.doc.mjs +1 -1
  750. package/src/theme/defineTheme.ts +117 -8
  751. package/src/theme/domainTokens/domainTokenDefaults.ts +19 -0
  752. package/src/theme/domainTokens/index.ts +6 -10
  753. package/src/theme/index.ts +5 -0
  754. package/src/theme/motionKnobs.ts +82 -0
  755. package/src/theme/resolveThemeValues.ts +68 -6
  756. package/src/theme/themeAdaptations.ts +52 -12
  757. package/src/theme/themeMotion.ts +221 -0
  758. package/src/theme/tokenReferences.ts +149 -0
  759. package/src/theme/tokens.stylex.ts +10 -0
  760. package/src/theme/tokens.ts +15 -158
  761. package/src/utils/focusOutline.stylex.ts +28 -0
  762. package/src/utils/focusReturn.ts +17 -6
  763. package/src/utils/getNodeText.ts +37 -0
  764. package/src/utils/interactionModality.ts +64 -5
  765. package/src/utils/interactionOverlay.stylex.ts +12 -3
  766. package/src/utils/plainDate.ts +58 -3
  767. package/src/utils/presentation.ts +180 -0
  768. package/src/utils/pressFeedback.ts +34 -11
  769. package/src/utils/primaryClick.ts +28 -0
  770. package/src/utils/sharedMutationObserver.ts +87 -29
  771. package/src/utils/timeFormat.ts +314 -0
  772. package/src/utils/touchPresentation.stylex.ts +43 -0
  773. package/src/utils/touchPresentation.ts +13 -8
  774. package/src/utils/touchQueries.ts +15 -0
  775. package/src/utils/unicodeDigits.ts +71 -0
  776. package/src/utils/useFocusAcrossSwap.ts +55 -0
  777. package/dist/Item/ItemMarkerColumns.a11y.chromium.spec.d.ts +0 -2
  778. package/dist/Item/ItemMarkerColumns.a11y.chromium.spec.js +0 -132
  779. package/dist/Lightbox/LightboxKeyboard.a11y.browser.spec.d.ts +0 -2
  780. package/dist/Lightbox/LightboxKeyboard.a11y.browser.spec.js +0 -78
  781. package/dist/Lightbox/LightboxViewport.a11y.browser.spec.d.ts +0 -2
  782. package/dist/Lightbox/LightboxViewport.a11y.browser.spec.js +0 -65
  783. package/dist/List/ListMarkers.a11y.chromium.spec.d.ts +0 -2
  784. package/dist/List/ListMarkers.a11y.chromium.spec.js +0 -677
  785. package/dist/Markdown/Markdown.fr23.bench.d.ts +0 -2
  786. package/dist/Markdown/Markdown.fr23.bench.d.ts.map +0 -1
  787. package/dist/Markdown/Markdown.fr23.bench.js +0 -152
  788. package/dist/Markdown/MarkdownTable.a11y.chromium.spec.d.ts +0 -2
  789. package/dist/Markdown/MarkdownTable.a11y.chromium.spec.js +0 -590
  790. package/dist/Markdown/plugins/headingLinks.a11y.chromium.spec.d.ts +0 -2
  791. package/dist/Markdown/plugins/headingLinks.a11y.chromium.spec.js +0 -657
  792. package/dist/MobileNav/MobileNavPinchZoom.a11y.chromium.spec.d.ts +0 -2
  793. package/dist/MobileNav/MobileNavPinchZoom.a11y.chromium.spec.js +0 -153
  794. package/dist/MultiSelector/CreateRow.a11y.chromium.spec.d.ts +0 -2
  795. package/dist/MultiSelector/CreateRow.a11y.chromium.spec.js +0 -116
  796. package/dist/MultiSelector/MultiSelector.disabledFocus.a11y.chromium.spec.d.ts +0 -2
  797. package/dist/MultiSelector/MultiSelector.disabledFocus.a11y.chromium.spec.js +0 -49
  798. package/dist/MultiSelector/OptionActions.a11y.chromium.spec.d.ts +0 -2
  799. package/dist/MultiSelector/OptionActions.a11y.chromium.spec.js +0 -273
  800. package/dist/Outline/OutlineFocus.a11y.chromium.spec.d.ts +0 -2
  801. package/dist/Outline/OutlineFocus.a11y.chromium.spec.js +0 -421
  802. package/dist/Typeahead/BaseTypeahead.emptyState.a11y.chromium.spec.d.ts +0 -2
  803. package/dist/Typeahead/BaseTypeahead.emptyState.a11y.chromium.spec.js +0 -118
  804. package/dist/reset.a11y.chromium.spec.d.ts +0 -2
  805. package/dist/reset.a11y.chromium.spec.js +0 -231
  806. package/dist/reset.until-found.a11y.browser.spec.d.ts +0 -2
  807. package/dist/reset.until-found.a11y.browser.spec.js +0 -72
  808. package/src/AlertDialog/AlertDialog.test.tsx +0 -519
  809. package/src/AlertDialog/__tests__/AlertDialog.a11y.chromium.spec.ts +0 -116
  810. package/src/AlertDialog/__tests__/AlertDialog.a11y.renders.tsx +0 -52
  811. package/src/AlertDialog/__tests__/AlertDialog.a11y.states.ts +0 -68
  812. package/src/AlertDialog/__tests__/AlertDialog.a11y.test.tsx +0 -144
  813. package/src/AlertDialog/useImperativeAlertDialog.test.tsx +0 -163
  814. package/src/AppShell/AppShell.test.tsx +0 -1148
  815. package/src/AspectRatio/AspectRatio.test.tsx +0 -398
  816. package/src/AspectRatio/__tests__/AspectRatioFitLayers.a11y.browser.spec.ts +0 -158
  817. package/src/Avatar/Avatar.test.tsx +0 -867
  818. package/src/Avatar/AvatarStatusDot.test.tsx +0 -306
  819. package/src/AvatarGroup/AvatarGroup.test.tsx +0 -313
  820. package/src/AvatarGroup/AvatarGroupOverflow.test.tsx +0 -263
  821. package/src/Badge/Badge.test.tsx +0 -125
  822. package/src/Banner/Banner.test.tsx +0 -879
  823. package/src/Blockquote/Blockquote.test.tsx +0 -121
  824. package/src/BottomSheet/BottomSheet.test.tsx +0 -3108
  825. package/src/BottomSheet/BottomSheetEdgeTint.test.tsx +0 -248
  826. package/src/BottomSheet/BottomSheetKeyboard.test.tsx +0 -195
  827. package/src/BottomSheet/BottomSheetPanel.test.tsx +0 -549
  828. package/src/BottomSheet/BottomSheetReplace.test.tsx +0 -1638
  829. package/src/BottomSheet/BottomSheetStacking.announce.test.tsx +0 -246
  830. package/src/BottomSheet/BottomSheetStacking.test.tsx +0 -3184
  831. package/src/BottomSheet/BottomSheetSwitcher.test.tsx +0 -2010
  832. package/src/BottomSheet/__tests__/BottomSheetDrag.a11y.chromium.spec.ts +0 -129
  833. package/src/BottomSheet/__tests__/BottomSheetFocusReturn.a11y.browser.spec.ts +0 -97
  834. package/src/BottomSheet/__tests__/BottomSheetKeyboard.a11y.browser.spec.ts +0 -415
  835. package/src/BottomSheet/__tests__/BottomSheetNativeModal.a11y.browser.spec.ts +0 -462
  836. package/src/BottomSheet/__tests__/BottomSheetPinchZoom.a11y.chromium.spec.ts +0 -247
  837. package/src/BottomSheet/__tests__/BottomSheetToastOutlet.a11y.chromium.spec.ts +0 -83
  838. package/src/BottomSheet/snapOffsets.test.ts +0 -254
  839. package/src/BottomSheet/useSheetGestures.test.ts +0 -1638
  840. package/src/Breadcrumbs/Breadcrumbs.test.tsx +0 -921
  841. package/src/Breadcrumbs/__tests__/Breadcrumbs.a11y.chromium.spec.ts +0 -120
  842. package/src/Breadcrumbs/__tests__/Breadcrumbs.a11y.renders.tsx +0 -45
  843. package/src/Breadcrumbs/__tests__/Breadcrumbs.a11y.states.ts +0 -81
  844. package/src/Breadcrumbs/__tests__/Breadcrumbs.a11y.test.tsx +0 -125
  845. package/src/Button/Button.test.tsx +0 -864
  846. package/src/Button/__tests__/Button.a11y.chromium.spec.ts +0 -355
  847. package/src/Button/__tests__/Button.a11y.harnesses.tsx +0 -47
  848. package/src/Button/__tests__/Button.a11y.known-failures.ts +0 -25
  849. package/src/Button/__tests__/Button.a11y.renders.tsx +0 -139
  850. package/src/Button/__tests__/Button.a11y.states.ts +0 -317
  851. package/src/Button/__tests__/Button.a11y.test.tsx +0 -187
  852. package/src/ButtonGroup/ButtonGroup.test.tsx +0 -1025
  853. package/src/Calendar/Calendar.test.tsx +0 -2186
  854. package/src/Calendar/__tests__/Calendar.a11y.chromium.spec.ts +0 -127
  855. package/src/Calendar/__tests__/Calendar.a11y.known-failures.ts +0 -12
  856. package/src/Calendar/__tests__/Calendar.a11y.renders.tsx +0 -57
  857. package/src/Calendar/__tests__/Calendar.a11y.states.ts +0 -139
  858. package/src/Calendar/__tests__/Calendar.a11y.test.tsx +0 -137
  859. package/src/Calendar/dayCellUtils.test.ts +0 -520
  860. package/src/Calendar/getInitialFocusDate.test.ts +0 -94
  861. package/src/Calendar/getStandaloneShortWeekdayNames.test.ts +0 -54
  862. package/src/Calendar/hooks/useCalendarConstraints.test.ts +0 -153
  863. package/src/Calendar/hooks/useCalendarDays.test.ts +0 -265
  864. package/src/Calendar/hooks/useCalendarNavigation.test.ts +0 -252
  865. package/src/Card/Card.test.tsx +0 -202
  866. package/src/Carousel/Carousel.test.tsx +0 -915
  867. package/src/Carousel/__tests__/Carousel.a11y.chromium.spec.ts +0 -193
  868. package/src/Carousel/__tests__/Carousel.a11y.known-failures.ts +0 -27
  869. package/src/Carousel/__tests__/Carousel.a11y.renders.tsx +0 -39
  870. package/src/Carousel/__tests__/Carousel.a11y.states.ts +0 -139
  871. package/src/Carousel/__tests__/Carousel.a11y.test.tsx +0 -127
  872. package/src/Center/Center.test.tsx +0 -406
  873. package/src/Chat/ChatComposer.test.tsx +0 -364
  874. package/src/Chat/ChatComposerDrawer.test.tsx +0 -130
  875. package/src/Chat/ChatComposerInput.test.tsx +0 -2136
  876. package/src/Chat/ChatComposerTokenElement.test.tsx +0 -85
  877. package/src/Chat/ChatDictationButton.test.tsx +0 -108
  878. package/src/Chat/ChatLayout.test.tsx +0 -311
  879. package/src/Chat/ChatLayoutScrollButton.test.tsx +0 -99
  880. package/src/Chat/ChatMessage.test.tsx +0 -344
  881. package/src/Chat/ChatMessageBubble.test.tsx +0 -294
  882. package/src/Chat/ChatMessageList.test.tsx +0 -198
  883. package/src/Chat/ChatMessageMetadata.test.tsx +0 -66
  884. package/src/Chat/ChatPastedTextToken.test.tsx +0 -71
  885. package/src/Chat/ChatSendButton.test.tsx +0 -309
  886. package/src/Chat/ChatSystemMessage.test.tsx +0 -189
  887. package/src/Chat/ChatTokenizedText.test.tsx +0 -163
  888. package/src/Chat/ChatToolCalls.test.tsx +0 -413
  889. package/src/Chat/__tests__/ChatLayoutScrollButton.a11y.chromium.spec.ts +0 -577
  890. package/src/Chat/__tests__/ChatLayoutScrollButtonSurface.a11y.chromium.spec.ts +0 -740
  891. package/src/Chat/__tests__/ChatMessageBubble.a11y.chromium.spec.ts +0 -457
  892. package/src/Chat/__tests__/ChatMessageBubble.auditProvenance.test.ts +0 -91
  893. package/src/Chat/__tests__/ChatMessageBubble.auditProvenance.ts +0 -91
  894. package/src/Chat/__tests__/ChatMessageList.a11y.chromium.spec.ts +0 -465
  895. package/src/Chat/__tests__/ChatMessageMetadata.a11y.chromium.spec.ts +0 -416
  896. package/src/Chat/__tests__/ChatSendButton.a11y.chromium.spec.ts +0 -1523
  897. package/src/Chat/__tests__/ChatSystemMessage.a11y.chromium.spec.ts +0 -1004
  898. package/src/Chat/__tests__/ChatTokenizedText.a11y.chromium.spec.ts +0 -574
  899. package/src/Chat/__tests__/useChatStreamScroll.a11y.chromium.spec.ts +0 -263
  900. package/src/Chat/__tests__/useChatStreamScroll.fixture.tsx +0 -61
  901. package/src/Chat/useChatDictation.test.tsx +0 -369
  902. package/src/Chat/useChatNewMessages.test.tsx +0 -209
  903. package/src/Chat/useChatPasteAsToken.test.ts +0 -191
  904. package/src/Chat/useChatStreamScroll.test.tsx +0 -381
  905. package/src/Chat/useTriggerMenu.test.tsx +0 -994
  906. package/src/CheckboxInput/CheckboxInput.test.tsx +0 -926
  907. package/src/CheckboxInput/__tests__/Checkbox.a11y.chromium.spec.ts +0 -354
  908. package/src/CheckboxInput/__tests__/Checkbox.a11y.known-failures.ts +0 -54
  909. package/src/CheckboxInput/__tests__/Checkbox.a11y.renders.tsx +0 -310
  910. package/src/CheckboxInput/__tests__/Checkbox.a11y.states.ts +0 -404
  911. package/src/CheckboxInput/__tests__/Checkbox.a11y.test.tsx +0 -128
  912. package/src/CheckboxList/CheckboxList.fr10.test.tsx +0 -51
  913. package/src/CheckboxList/CheckboxList.test.tsx +0 -1159
  914. package/src/CheckboxList/__tests__/CheckboxList.a11y.chromium.spec.ts +0 -1998
  915. package/src/Citation/Citation.test.tsx +0 -361
  916. package/src/ClickableCard/ClickableCard.test.tsx +0 -286
  917. package/src/Code/Code.test.tsx +0 -75
  918. package/src/CodeBlock/CodeBlock.highlightStyles.test.tsx +0 -87
  919. package/src/CodeBlock/CodeBlock.test.tsx +0 -752
  920. package/src/CodeBlock/CodeLanguage.test.tsx +0 -173
  921. package/src/CodeBlock/__tests__/CodeBlockCopyClearance.a11y.chromium.spec.ts +0 -290
  922. package/src/CodeBlock/__tests__/CodeBlockLanguages.a11y.chromium.spec.ts +0 -64
  923. package/src/CodeBlock/__tests__/CodeBlockOverflowStop.a11y.chromium.spec.ts +0 -126
  924. package/src/CodeBlock/__tests__/DiffRowPaint.a11y.chromium.spec.ts +0 -94
  925. package/src/CodeBlock/highlightRanges.test.ts +0 -253
  926. package/src/CodeBlock/languages.test.ts +0 -402
  927. package/src/CodeBlock/tokenizer.test.ts +0 -280
  928. package/src/CodeBlock/tokenizerBudget.test.ts +0 -112
  929. package/src/Collapsible/Collapsible.test.tsx +0 -620
  930. package/src/Collapsible/CollapsibleGroup.test.tsx +0 -656
  931. package/src/Collapsible/__tests__/Collapsible.a11y.chromium.spec.ts +0 -183
  932. package/src/Collapsible/__tests__/Collapsible.a11y.states.ts +0 -117
  933. package/src/Collapsible/__tests__/Collapsible.a11y.test.tsx +0 -140
  934. package/src/Collapsible/__tests__/CollapsibleGroup.a11y.chromium.spec.ts +0 -559
  935. package/src/Collapsible/__tests__/CollapsibleGroup.a11y.renders.tsx +0 -45
  936. package/src/Collapsible/__tests__/CollapsibleGroup.a11y.states.ts +0 -139
  937. package/src/Collapsible/__tests__/CollapsibleGroup.a11y.test.tsx +0 -135
  938. package/src/Collapsible/__tests__/CollapsibleGroupAccordion.a11y.chromium.spec.ts +0 -129
  939. package/src/Collapsible/useCollapsible.test.tsx +0 -236
  940. package/src/CommandPalette/CommandPalette.perf.test.ts +0 -100
  941. package/src/CommandPalette/CommandPalette.test.tsx +0 -750
  942. package/src/CommandPalette/CommandPaletteEmpty.test.tsx +0 -101
  943. package/src/CommandPalette/CommandPaletteFooter.test.tsx +0 -122
  944. package/src/CommandPalette/CommandPaletteGroup.test.tsx +0 -129
  945. package/src/CommandPalette/CommandPaletteInput.test.tsx +0 -539
  946. package/src/CommandPalette/CommandPaletteItem.test.tsx +0 -417
  947. package/src/CommandPalette/CommandPaletteList.test.tsx +0 -184
  948. package/src/CommandPalette/__tests__/CommandPalette.a11y.chromium.spec.ts +0 -600
  949. package/src/CommandPalette/__tests__/CommandPaletteEmptyAudit.a11y.chromium.spec.ts +0 -715
  950. package/src/CommandPalette/__tests__/CommandPaletteFooter.a11y.chromium.spec.ts +0 -582
  951. package/src/CommandPalette/__tests__/CommandPaletteInputAudit.a11y.chromium.spec.ts +0 -336
  952. package/src/CommandPalette/__tests__/CommandPaletteItemAudit.a11y.chromium.spec.ts +0 -523
  953. package/src/ComplexSelector/ComplexSelector.focusableDisabled.test.tsx +0 -76
  954. package/src/ComplexSelector/ComplexSelector.fr10.test.tsx +0 -262
  955. package/src/ComplexSelector/ComplexSelector.test.tsx +0 -1023
  956. package/src/ComplexSelector/__tests__/ComplexSelector.a11y.chromium.spec.ts +0 -965
  957. package/src/ContextMenu/ContextMenu.test.tsx +0 -1582
  958. package/src/ContextMenu/ContextMenu.triggerProps.test.tsx +0 -54
  959. package/src/ContextMenu/__tests__/ContextMenuAudit.a11y.chromium.spec.ts +0 -439
  960. package/src/ContextMenu/__tests__/ContextMenuCursorAnchor.a11y.browser.spec.ts +0 -154
  961. package/src/ContextMenu/__tests__/ContextMenuLongPress.a11y.chromium.spec.ts +0 -117
  962. package/src/DateInput/DateInput.fr10.test.tsx +0 -283
  963. package/src/DateInput/DateInput.test.tsx +0 -1459
  964. package/src/DateInput/DateInputTouch.test.tsx +0 -2828
  965. package/src/DateInput/NativeDateField.test.tsx +0 -741
  966. package/src/DateInput/Presentation.test.tsx +0 -121
  967. package/src/DateInput/__tests__/DateInputAudit.a11y.chromium.spec.ts +0 -577
  968. package/src/DateInput/__tests__/WheelPinchZoom.a11y.chromium.spec.ts +0 -171
  969. package/src/DateRangeInput/DateRangeInput.fr10.test.tsx +0 -165
  970. package/src/DateRangeInput/DateRangeInput.test.tsx +0 -1108
  971. package/src/DateTimeInput/DateTimeInput.fr10.test.tsx +0 -319
  972. package/src/DateTimeInput/DateTimeInput.test.tsx +0 -2575
  973. package/src/DateTimeInput/DateTimeInputTouch.test.tsx +0 -1071
  974. package/src/DateTimeInput/NativePickerSegments.test.tsx +0 -657
  975. package/src/DateTimeInput/Presentation.test.tsx +0 -89
  976. package/src/Dialog/Dialog.source-build.test.mjs +0 -43
  977. package/src/Dialog/Dialog.test.tsx +0 -1385
  978. package/src/Dialog/DialogHeader.test.tsx +0 -477
  979. package/src/Dialog/__tests__/Dialog.a11y.browser.spec.ts +0 -111
  980. package/src/Dialog/__tests__/Dialog.a11y.chromium.spec.ts +0 -218
  981. package/src/Dialog/__tests__/Dialog.a11y.known-failures.ts +0 -28
  982. package/src/Dialog/__tests__/Dialog.a11y.renders.tsx +0 -107
  983. package/src/Dialog/__tests__/Dialog.a11y.states.ts +0 -104
  984. package/src/Dialog/__tests__/Dialog.a11y.test.tsx +0 -102
  985. package/src/Dialog/__tests__/Dialog.reduced-motion.a11y.browser.spec.ts +0 -252
  986. package/src/Dialog/useImperativeDialog.test.tsx +0 -78
  987. package/src/Divider/Divider.test.tsx +0 -155
  988. package/src/Drawer/Drawer.test.tsx +0 -1300
  989. package/src/Drawer/DrawerDirection.test.tsx +0 -127
  990. package/src/Drawer/DrawerHeader.test.tsx +0 -102
  991. package/src/Drawer/__tests__/DrawerAudit.a11y.chromium.spec.ts +0 -402
  992. package/src/Drawer/__tests__/DrawerHeaderAudit.a11y.chromium.spec.ts +0 -298
  993. package/src/DropdownMenu/DropdownMenu.ssr.test.tsx +0 -93
  994. package/src/DropdownMenu/DropdownMenu.test.tsx +0 -4340
  995. package/src/DropdownMenu/DropdownMenuContext.public.test.ts +0 -22
  996. package/src/DropdownMenu/DropdownMenuLazySheet.test.tsx +0 -126
  997. package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +0 -635
  998. package/src/DropdownMenu/DropdownMenuSheetFirstOpen.test.tsx +0 -72
  999. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +0 -2408
  1000. package/src/DropdownMenu/__tests__/DropdownMenuDividerAudit.a11y.chromium.spec.ts +0 -281
  1001. package/src/DropdownMenu/__tests__/DropdownMenuDrillIn.a11y.chromium.spec.ts +0 -175
  1002. package/src/DropdownMenu/__tests__/DropdownMenuFocusReturn.a11y.browser.spec.ts +0 -74
  1003. package/src/DropdownMenu/__tests__/DropdownMenuGroupAudit.a11y.chromium.spec.ts +0 -335
  1004. package/src/DropdownMenu/__tests__/DropdownMenuItemAudit.a11y.chromium.spec.ts +0 -367
  1005. package/src/DropdownMenu/__tests__/DropdownMenuRadioGroupAudit.a11y.chromium.spec.ts +0 -328
  1006. package/src/DropdownMenu/__tests__/DropdownMenuRadioItemAudit.a11y.chromium.spec.ts +0 -540
  1007. package/src/DropdownMenu/__tests__/DropdownMenuSubMenuAudit.a11y.chromium.spec.ts +0 -671
  1008. package/src/DropdownMenu/__tests__/Menu.a11y.chromium.spec.ts +0 -146
  1009. package/src/DropdownMenu/__tests__/Menu.a11y.known-failures.ts +0 -26
  1010. package/src/DropdownMenu/__tests__/Menu.a11y.renders.tsx +0 -65
  1011. package/src/DropdownMenu/__tests__/Menu.a11y.states.ts +0 -138
  1012. package/src/DropdownMenu/__tests__/Menu.a11y.test.tsx +0 -136
  1013. package/src/DropdownMenu/__tests__/MenuButton.a11y.chromium.spec.ts +0 -137
  1014. package/src/DropdownMenu/__tests__/MenuButton.a11y.known-failures.ts +0 -12
  1015. package/src/DropdownMenu/__tests__/MenuButton.a11y.renders.tsx +0 -67
  1016. package/src/DropdownMenu/__tests__/MenuButton.a11y.states.ts +0 -141
  1017. package/src/DropdownMenu/__tests__/MenuButton.a11y.test.tsx +0 -138
  1018. package/src/DropdownMenu/__tests__/MenuHeaderFooter.a11y.chromium.spec.ts +0 -231
  1019. package/src/DropdownMenu/__tests__/MenuHoverFocus.a11y.chromium.spec.ts +0 -238
  1020. package/src/DropdownMenu/__tests__/MenuPinchZoom.a11y.chromium.spec.ts +0 -173
  1021. package/src/DropdownMenu/__tests__/MenuPress.a11y.chromium.spec.ts +0 -503
  1022. package/src/DropdownMenu/__tests__/SubMenuHeaderFooter.a11y.chromium.spec.ts +0 -268
  1023. package/src/DropdownMenu/__tests__/warmMenuBottomSheet.tsx +0 -43
  1024. package/src/EmptyState/EmptyState.announce.test.tsx +0 -227
  1025. package/src/EmptyState/EmptyState.test.tsx +0 -284
  1026. package/src/Field/Field.test.tsx +0 -800
  1027. package/src/Field/FieldLabel.test.tsx +0 -244
  1028. package/src/Field/InputClearButton.test.tsx +0 -395
  1029. package/src/Field/__tests__/FieldLabelAudit.a11y.chromium.spec.ts +0 -297
  1030. package/src/Field/fieldInputFamily.test.tsx +0 -160
  1031. package/src/FieldStatus/FieldStatus.test.tsx +0 -482
  1032. package/src/FieldStatus/__tests__/StatusMessage.a11y.chromium.spec.ts +0 -206
  1033. package/src/FieldStatus/__tests__/StatusMessage.a11y.known-failures.ts +0 -13
  1034. package/src/FieldStatus/__tests__/StatusMessage.a11y.renders.tsx +0 -287
  1035. package/src/FieldStatus/__tests__/StatusMessage.a11y.states.ts +0 -302
  1036. package/src/FieldStatus/__tests__/StatusMessage.a11y.test.tsx +0 -154
  1037. package/src/FileInput/FileInput.fr10.test.tsx +0 -21
  1038. package/src/FileInput/FileInput.test.tsx +0 -1270
  1039. package/src/FormLayout/FormLayout.test.tsx +0 -444
  1040. package/src/FormLayout/__snapshots__/FormLayout.test.tsx.snap +0 -46
  1041. package/src/Grid/Grid.test.tsx +0 -509
  1042. package/src/HStack/HStack.test.tsx +0 -129
  1043. package/src/Heading/Heading.test.tsx +0 -328
  1044. package/src/HoverCard/HoverCard.test.tsx +0 -1339
  1045. package/src/Icon/Icon.test.tsx +0 -990
  1046. package/src/Icon/globalIconRegistry.test.tsx +0 -613
  1047. package/src/IconButton/IconButton.test.tsx +0 -156
  1048. package/src/Indicator/Indicator.test.tsx +0 -389
  1049. package/src/Indicator/indicatorRegistry.test.tsx +0 -106
  1050. package/src/InputGroup/InputGroup.test.tsx +0 -502
  1051. package/src/InteractiveRoleContext/InteractiveRoleContext.test.tsx +0 -185
  1052. package/src/Item/Item.source-build.test.mjs +0 -88
  1053. package/src/Item/Item.swipeLayer.test.tsx +0 -74
  1054. package/src/Item/Item.test.tsx +0 -1455
  1055. package/src/Item/ItemMarkerColumns.a11y.chromium.spec.ts +0 -211
  1056. package/src/Item/__tests__/ItemSwipeActions.a11y.chromium.spec.ts +0 -337
  1057. package/src/Item/__tests__/ItemSwipePinchZoom.a11y.chromium.spec.ts +0 -186
  1058. package/src/Kbd/Kbd.test.tsx +0 -299
  1059. package/src/Layer/LayerProvider.test.tsx +0 -143
  1060. package/src/Layer/__tests__/LayerReducedMotion.a11y.chromium.spec.ts +0 -176
  1061. package/src/Layer/__tests__/TouchTrigger.a11y.chromium.spec.ts +0 -200
  1062. package/src/Layer/anchorName.test.ts +0 -146
  1063. package/src/Layer/layerDismissalFamilies.test.tsx +0 -487
  1064. package/src/Layer/layerDismissalInvariants.test.tsx +0 -501
  1065. package/src/Layer/layerHost.test.ts +0 -117
  1066. package/src/Layer/layerScopedContext.test.tsx +0 -499
  1067. package/src/Layer/layerViewportInset.source-build.test.mjs +0 -90
  1068. package/src/Layer/layerViewportInset.test.ts +0 -120
  1069. package/src/Layer/useLayer.test.tsx +0 -2423
  1070. package/src/Layer/useLayerDismissal.test.tsx +0 -580
  1071. package/src/Layer/useTouchTrigger.test.ts +0 -70
  1072. package/src/Layout/Layout.test.tsx +0 -375
  1073. package/src/Layout/LayoutSlots.test.tsx +0 -376
  1074. package/src/Layout/__tests__/Layout.a11y.chromium.spec.ts +0 -122
  1075. package/src/Layout/__tests__/Layout.a11y.renders.tsx +0 -110
  1076. package/src/Layout/__tests__/Layout.a11y.states.ts +0 -93
  1077. package/src/Layout/__tests__/Layout.a11y.test.tsx +0 -142
  1078. package/src/Layout/__tests__/childrenAsContent.test.tsx +0 -59
  1079. package/src/Layout/__tests__/contentWidth.test.tsx +0 -303
  1080. package/src/Layout/__tests__/edgeCompensation.test.tsx +0 -191
  1081. package/src/Layout/__tests__/nestedPadding.test.tsx +0 -264
  1082. package/src/Layout/overlayPaddingReset.test.tsx +0 -224
  1083. package/src/Lightbox/Lightbox.test.tsx +0 -819
  1084. package/src/Lightbox/LightboxKeyboard.a11y.browser.spec.ts +0 -78
  1085. package/src/Lightbox/LightboxViewport.a11y.browser.spec.ts +0 -70
  1086. package/src/Lightbox/useLightbox.test.tsx +0 -263
  1087. package/src/Link/Link.test.tsx +0 -457
  1088. package/src/Link/__tests__/Link.a11y.chromium.spec.ts +0 -143
  1089. package/src/Link/__tests__/Link.a11y.renders.tsx +0 -97
  1090. package/src/Link/__tests__/Link.a11y.states.ts +0 -104
  1091. package/src/Link/__tests__/Link.a11y.test.tsx +0 -127
  1092. package/src/Link/__tests__/Link.navigation.a11y.chromium.spec.ts +0 -262
  1093. package/src/Link/useLinkComponent.test.tsx +0 -572
  1094. package/src/Link/useLinkify.test.tsx +0 -146
  1095. package/src/List/List.test.tsx +0 -1052
  1096. package/src/List/ListItem.source-build.test.mjs +0 -41
  1097. package/src/List/ListMarkers.a11y.chromium.spec.ts +0 -904
  1098. package/src/Markdown/Markdown.codeLanguages.test.tsx +0 -137
  1099. package/src/Markdown/Markdown.fr23.bench.ts +0 -176
  1100. package/src/Markdown/Markdown.fr23.perf.test.ts +0 -484
  1101. package/src/Markdown/Markdown.helpers.perf.test.ts +0 -495
  1102. package/src/Markdown/Markdown.public.test.ts +0 -309
  1103. package/src/Markdown/Markdown.renderBoundary.test.tsx +0 -72
  1104. package/src/Markdown/Markdown.rerender.test.tsx +0 -143
  1105. package/src/Markdown/Markdown.test.tsx +0 -1383
  1106. package/src/Markdown/MarkdownTable.a11y.chromium.spec.ts +0 -727
  1107. package/src/Markdown/__tests__/MarkdownNesting.a11y.chromium.spec.ts +0 -102
  1108. package/src/Markdown/angleDestinations.test.tsx +0 -104
  1109. package/src/Markdown/ast.test.ts +0 -374
  1110. package/src/Markdown/atxHeadingIndentation.test.tsx +0 -53
  1111. package/src/Markdown/blockNesting.test.tsx +0 -124
  1112. package/src/Markdown/blockquoteMarkers.test.tsx +0 -69
  1113. package/src/Markdown/characterReferences.test.ts +0 -47
  1114. package/src/Markdown/codeSpans.test.tsx +0 -65
  1115. package/src/Markdown/emphasis.test.tsx +0 -214
  1116. package/src/Markdown/fenceInfo.test.tsx +0 -47
  1117. package/src/Markdown/imageAlt.test.tsx +0 -84
  1118. package/src/Markdown/incremental.test.ts +0 -1198
  1119. package/src/Markdown/incrementalIndentation.test.tsx +0 -36
  1120. package/src/Markdown/indentedFences.test.tsx +0 -374
  1121. package/src/Markdown/indentedTables.test.tsx +0 -53
  1122. package/src/Markdown/linkBrackets.test.tsx +0 -116
  1123. package/src/Markdown/linkDestinationLinear.test.tsx +0 -54
  1124. package/src/Markdown/linkDestinations.test.tsx +0 -127
  1125. package/src/Markdown/linkTextCode.test.tsx +0 -65
  1126. package/src/Markdown/listBullets.test.tsx +0 -55
  1127. package/src/Markdown/listContinuation.test.tsx +0 -94
  1128. package/src/Markdown/listThematicBreak.test.tsx +0 -49
  1129. package/src/Markdown/longLinkLabels.test.tsx +0 -49
  1130. package/src/Markdown/openFenceFinalNewline.test.tsx +0 -85
  1131. package/src/Markdown/parser.perf.test.ts +0 -398
  1132. package/src/Markdown/parser.public.test.ts +0 -144
  1133. package/src/Markdown/parser.test.ts +0 -1925
  1134. package/src/Markdown/plugin-renderer/MarkdownPluginNodeRenderer.test.tsx +0 -300
  1135. package/src/Markdown/plugins/frontmatter.test.tsx +0 -150
  1136. package/src/Markdown/plugins/headingLinks.a11y.chromium.spec.ts +0 -856
  1137. package/src/Markdown/plugins/headingLinks.ssr.test.tsx +0 -143
  1138. package/src/Markdown/plugins/headingLinks.test.tsx +0 -637
  1139. package/src/Markdown/plugins/protocol.test.tsx +0 -1083
  1140. package/src/Markdown/plugins/semanticFence.test.tsx +0 -655
  1141. package/src/Markdown/plugins/softBreaks.test.tsx +0 -172
  1142. package/src/Markdown/plugins/sourceDecoration.test.tsx +0 -799
  1143. package/src/Markdown/plugins/sourceLines.test.tsx +0 -715
  1144. package/src/Markdown/plugins/textTransform.test.ts +0 -467
  1145. package/src/Markdown/remark.test.tsx +0 -1877
  1146. package/src/Markdown/streaming.test.ts +0 -148
  1147. package/src/Markdown/streamingListShapes.test.tsx +0 -93
  1148. package/src/Markdown/trailingSpaces.test.tsx +0 -45
  1149. package/src/MetadataList/MetadataList.test.tsx +0 -383
  1150. package/src/MobileNav/MobileNav.test.tsx +0 -281
  1151. package/src/MobileNav/MobileNavCloseEdgeCases.test.tsx +0 -584
  1152. package/src/MobileNav/MobileNavCloseTiming.test.ts +0 -58
  1153. package/src/MobileNav/MobileNavCloseVisibility.test.tsx +0 -172
  1154. package/src/MobileNav/MobileNavEntryAnimation.test.tsx +0 -212
  1155. package/src/MobileNav/MobileNavFocus.test.tsx +0 -553
  1156. package/src/MobileNav/MobileNavPinchZoom.a11y.chromium.spec.ts +0 -147
  1157. package/src/MobileNav/MobileNavReopen.test.tsx +0 -118
  1158. package/src/MobileNav/MobileNavScrollbarGutter.test.tsx +0 -109
  1159. package/src/MobileNav/MobileNavToggle.test.tsx +0 -179
  1160. package/src/MobileNav/__tests__/MobileNavWidth.a11y.chromium.spec.ts +0 -103
  1161. package/src/MoreMenu/MoreMenu.test.tsx +0 -356
  1162. package/src/MultiSelector/CreateRow.a11y.chromium.spec.ts +0 -149
  1163. package/src/MultiSelector/MultiSelector.disabledFocus.a11y.chromium.spec.ts +0 -72
  1164. package/src/MultiSelector/MultiSelector.focusableDisabled.test.tsx +0 -121
  1165. package/src/MultiSelector/MultiSelector.fr10.test.tsx +0 -221
  1166. package/src/MultiSelector/MultiSelector.test.tsx +0 -4702
  1167. package/src/MultiSelector/OptionActions.a11y.chromium.spec.ts +0 -310
  1168. package/src/MultiSelector/__tests__/MultiSelector.a11y.chromium.spec.ts +0 -46
  1169. package/src/MultiSelector/__tests__/MultiSelector.listbox.a11y.test.tsx +0 -128
  1170. package/src/NavIcon/NavIcon.test.tsx +0 -41
  1171. package/src/NavMenu/NavHeadingMenu.test.tsx +0 -714
  1172. package/src/NavMenu/__tests__/NavMenusSlideSelection.a11y.chromium.spec.ts +0 -137
  1173. package/src/NumberInput/NumberInput.fr10.test.tsx +0 -21
  1174. package/src/NumberInput/NumberInput.test.tsx +0 -2636
  1175. package/src/NumberInput/__tests__/NumberInput.a11y.chromium.spec.ts +0 -124
  1176. package/src/NumberInput/__tests__/NumberInput.a11y.known-failures.ts +0 -26
  1177. package/src/NumberInput/__tests__/NumberInput.a11y.renders.tsx +0 -77
  1178. package/src/NumberInput/__tests__/NumberInput.a11y.states.ts +0 -116
  1179. package/src/NumberInput/__tests__/NumberInput.a11y.test.tsx +0 -154
  1180. package/src/NumberInput/numberInputCommit.test.ts +0 -72
  1181. package/src/NumberInput/numberParser.docblock.test.ts +0 -234
  1182. package/src/NumberInput/numberParser.test.ts +0 -222
  1183. package/src/Outline/Outline.test.tsx +0 -1069
  1184. package/src/Outline/OutlineFocus.a11y.chromium.spec.ts +0 -551
  1185. package/src/Outline/parseOutlineFromMarkdown.test.ts +0 -104
  1186. package/src/OverflowList/OverflowList.test.tsx +0 -1073
  1187. package/src/Overlay/Overlay.test.tsx +0 -424
  1188. package/src/Pagination/Pagination.test.tsx +0 -1754
  1189. package/src/Popover/Popover.test.tsx +0 -1424
  1190. package/src/Popover/PopoverPresentation.test.tsx +0 -952
  1191. package/src/Popover/__tests__/PopoverSecondDocument.a11y.chromium.spec.ts +0 -205
  1192. package/src/PowerSearch/PowerSearch.test.tsx +0 -1003
  1193. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +0 -1190
  1194. package/src/PowerSearch/PowerSearchFilterEditor.test.tsx +0 -377
  1195. package/src/PowerSearch/PowerSearchToken.test.tsx +0 -230
  1196. package/src/PowerSearch/PowerSearchValueEditor.test.tsx +0 -754
  1197. package/src/PowerSearch/formatFilterValue.test.ts +0 -339
  1198. package/src/PowerSearch/resolveDateTimeRangePart.test.ts +0 -40
  1199. package/src/PowerSearch/usePowerSearchConfig.test.ts +0 -832
  1200. package/src/PowerSearch/usePowerSearchSource.test.ts +0 -621
  1201. package/src/ProgressBar/ProgressBar.test.tsx +0 -852
  1202. package/src/ProgressBar/__tests__/ProgressBar.a11y.chromium.spec.ts +0 -115
  1203. package/src/ProgressBar/__tests__/ProgressBar.a11y.known-failures.ts +0 -12
  1204. package/src/ProgressBar/__tests__/ProgressBar.a11y.renders.tsx +0 -38
  1205. package/src/ProgressBar/__tests__/ProgressBar.a11y.states.ts +0 -123
  1206. package/src/ProgressBar/__tests__/ProgressBar.a11y.test.tsx +0 -107
  1207. package/src/RadioList/RadioList.fr10.test.tsx +0 -67
  1208. package/src/RadioList/RadioList.test.tsx +0 -967
  1209. package/src/RadioList/RadioListItem.press.source-build.test.mjs +0 -80
  1210. package/src/RadioList/__tests__/RadioGroup.a11y.chromium.spec.ts +0 -274
  1211. package/src/RadioList/__tests__/RadioGroup.a11y.known-failures.ts +0 -12
  1212. package/src/RadioList/__tests__/RadioGroup.a11y.renders.tsx +0 -232
  1213. package/src/RadioList/__tests__/RadioGroup.a11y.states.ts +0 -503
  1214. package/src/RadioList/__tests__/RadioGroup.a11y.test.tsx +0 -217
  1215. package/src/Resizable/ResizeHandle.test.tsx +0 -1067
  1216. package/src/Resizable/__tests__/ResizeHandle.a11y.chromium.spec.ts +0 -120
  1217. package/src/Resizable/__tests__/ResizeHandle.a11y.known-failures.ts +0 -39
  1218. package/src/Resizable/__tests__/ResizeHandle.a11y.renders.tsx +0 -80
  1219. package/src/Resizable/__tests__/ResizeHandle.a11y.states.ts +0 -197
  1220. package/src/Resizable/__tests__/ResizeHandle.a11y.test.tsx +0 -123
  1221. package/src/Resizable/shippedDirections.test.ts +0 -462
  1222. package/src/Resizable/useResizable.test.ts +0 -1682
  1223. package/src/Resizable/utils.test.ts +0 -74
  1224. package/src/ScrollableArea/ScrollableArea.test.tsx +0 -304
  1225. package/src/Section/Section.test.tsx +0 -376
  1226. package/src/SegmentedControl/SegmentedControl.test.tsx +0 -897
  1227. package/src/SelectableCard/SelectableCard.test.tsx +0 -216
  1228. package/src/Selector/Selector.focusableDisabled.test.tsx +0 -127
  1229. package/src/Selector/Selector.fr10.test.tsx +0 -149
  1230. package/src/Selector/Selector.sheetActiveDescendant.test.tsx +0 -95
  1231. package/src/Selector/Selector.source-build.test.mjs +0 -79
  1232. package/src/Selector/Selector.test.tsx +0 -5028
  1233. package/src/Selector/__tests__/Combobox.a11y.known-failures.ts +0 -27
  1234. package/src/Selector/__tests__/Combobox.a11y.states.ts +0 -145
  1235. package/src/Selector/__tests__/ComboboxField.a11y.chromium.spec.ts +0 -458
  1236. package/src/Selector/__tests__/EmptyStateAnnouncement.a11y.chromium.spec.ts +0 -91
  1237. package/src/Selector/__tests__/Listbox.a11y.chromium.spec.ts +0 -131
  1238. package/src/Selector/__tests__/Listbox.a11y.dom.ts +0 -38
  1239. package/src/Selector/__tests__/Listbox.a11y.inventory.test.ts +0 -63
  1240. package/src/Selector/__tests__/Listbox.a11y.known-failures.ts +0 -12
  1241. package/src/Selector/__tests__/Listbox.a11y.states.ts +0 -232
  1242. package/src/Selector/__tests__/Selector.a11y.chromium.spec.ts +0 -46
  1243. package/src/Selector/__tests__/Selector.combobox.a11y.chromium.spec.ts +0 -109
  1244. package/src/Selector/__tests__/Selector.combobox.a11y.test.tsx +0 -126
  1245. package/src/Selector/__tests__/Selector.listbox.a11y.test.tsx +0 -121
  1246. package/src/Selector/useCombobox.public.test.tsx +0 -89
  1247. package/src/Selector/useCombobox.test.tsx +0 -444
  1248. package/src/SideNav/SideNav.test.tsx +0 -4128
  1249. package/src/SideNav/SideNavRailMotion.test.tsx +0 -620
  1250. package/src/SideNav/__tests__/SideNavRailMotion.interaction.browser.spec.ts +0 -417
  1251. package/src/SizeContext/SizeContext.test.tsx +0 -226
  1252. package/src/Skeleton/Skeleton.test.tsx +0 -148
  1253. package/src/Slider/Slider.fr10.test.tsx +0 -93
  1254. package/src/Slider/Slider.test.tsx +0 -1630
  1255. package/src/Slider/__tests__/Slider.a11y.chromium.spec.ts +0 -113
  1256. package/src/Slider/__tests__/Slider.a11y.known-failures.ts +0 -12
  1257. package/src/Slider/__tests__/Slider.a11y.renders.tsx +0 -42
  1258. package/src/Slider/__tests__/Slider.a11y.states.ts +0 -106
  1259. package/src/Slider/__tests__/Slider.a11y.test.tsx +0 -105
  1260. package/src/Spinner/Spinner.test.tsx +0 -484
  1261. package/src/Stack/Stack.test.tsx +0 -473
  1262. package/src/Stack/StackItem.test.tsx +0 -105
  1263. package/src/StatusDot/StatusDot.test.tsx +0 -213
  1264. package/src/Stepper/Stepper.public.test.ts +0 -91
  1265. package/src/Stepper/Stepper.test.tsx +0 -2068
  1266. package/src/Switch/Switch.focusRing.source-build.test.mjs +0 -81
  1267. package/src/Switch/Switch.test.tsx +0 -1071
  1268. package/src/Switch/__tests__/Switch.a11y.chromium.spec.ts +0 -211
  1269. package/src/Switch/__tests__/Switch.a11y.known-failures.ts +0 -28
  1270. package/src/Switch/__tests__/Switch.a11y.states.ts +0 -275
  1271. package/src/Switch/__tests__/Switch.a11y.test.tsx +0 -144
  1272. package/src/TabList/TabList.test.tsx +0 -1701
  1273. package/src/TabList/__tests__/TabListOverflow.interaction.browser.spec.ts +0 -99
  1274. package/src/TabList/__tests__/Tabs.a11y.chromium.spec.ts +0 -199
  1275. package/src/TabList/__tests__/Tabs.a11y.known-failures.ts +0 -12
  1276. package/src/TabList/__tests__/Tabs.a11y.renders.tsx +0 -92
  1277. package/src/TabList/__tests__/Tabs.a11y.states.ts +0 -247
  1278. package/src/TabList/__tests__/Tabs.a11y.test.tsx +0 -153
  1279. package/src/Table/Table.perf.test.tsx +0 -569
  1280. package/src/Table/Table.test.tsx +0 -1851
  1281. package/src/Table/TableHeaderCell.test.tsx +0 -291
  1282. package/src/Table/TableSelectionToolbar.test.tsx +0 -109
  1283. package/src/Table/__tests__/Table.a11y.chromium.spec.ts +0 -129
  1284. package/src/Table/__tests__/Table.a11y.contracts.ts +0 -35
  1285. package/src/Table/__tests__/Table.a11y.renders.tsx +0 -112
  1286. package/src/Table/__tests__/Table.a11y.states.ts +0 -140
  1287. package/src/Table/__tests__/Table.a11y.test.tsx +0 -198
  1288. package/src/Table/__tests__/TableMinWidth.a11y.chromium.spec.ts +0 -75
  1289. package/src/Table/__tests__/TableRowGlide.a11y.browser.spec.ts +0 -382
  1290. package/src/Table/__tests__/TableScroll.a11y.chromium.spec.ts +0 -138
  1291. package/src/Table/__tests__/TableStickyDividers.a11y.browser.spec.ts +0 -560
  1292. package/src/Table/plugins/columnResize/useTableColumnResize.test.tsx +0 -919
  1293. package/src/Table/plugins/columnSettings/useTableColumnSettings.test.tsx +0 -175
  1294. package/src/Table/plugins/columnSettings/useTableColumnSettingsState.test.tsx +0 -296
  1295. package/src/Table/plugins/filtering/useTableFilterState.test.tsx +0 -143
  1296. package/src/Table/plugins/filtering/useTableFiltering.test.tsx +0 -357
  1297. package/src/Table/plugins/groupedRows/useTableGroupedRows-perf.test.tsx +0 -112
  1298. package/src/Table/plugins/groupedRows/useTableGroupedRows.test.tsx +0 -409
  1299. package/src/Table/plugins/pagination/useTablePagination-perf.test.tsx +0 -232
  1300. package/src/Table/plugins/pagination/useTablePagination.test.tsx +0 -666
  1301. package/src/Table/plugins/rowExpansion/useTableRowExpansion.glide.test.tsx +0 -280
  1302. package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +0 -681
  1303. package/src/Table/plugins/rowIndex/useTableRowIndex.test.tsx +0 -132
  1304. package/src/Table/plugins/rowStatus/useTableRowStatus.public.test.ts +0 -92
  1305. package/src/Table/plugins/rowStatus/useTableRowStatus.test.tsx +0 -519
  1306. package/src/Table/plugins/selection/useTableSelection-perf.test.tsx +0 -258
  1307. package/src/Table/plugins/selection/useTableSelection.test.tsx +0 -424
  1308. package/src/Table/plugins/selection/useTableSelectionState.test.tsx +0 -451
  1309. package/src/Table/plugins/sortable/__tests__/useTableSortable.a11y.test.tsx +0 -174
  1310. package/src/Table/plugins/sortable/__tests__/useTableSortable.a11y.ts +0 -86
  1311. package/src/Table/plugins/sortable/useTableSortable.test.tsx +0 -857
  1312. package/src/Table/plugins/sortable/useTableSortableState.test.tsx +0 -592
  1313. package/src/Table/plugins/stickyColumns/useTableStickyColumns.test.tsx +0 -334
  1314. package/src/Table/plugins/tree/useTableTreeData-perf.test.tsx +0 -163
  1315. package/src/Table/plugins/tree/useTableTreeData.test.tsx +0 -992
  1316. package/src/Table/plugins/tree/useTableTreeState.test.tsx +0 -740
  1317. package/src/Table/tableContextMenu.test.tsx +0 -208
  1318. package/src/Text/Text.test.tsx +0 -405
  1319. package/src/Text/useTruncation.test.tsx +0 -69
  1320. package/src/TextArea/TextArea.fr10.test.tsx +0 -21
  1321. package/src/TextArea/TextArea.test.tsx +0 -1257
  1322. package/src/TextInput/TextInput.fr10.test.tsx +0 -21
  1323. package/src/TextInput/TextInput.test.tsx +0 -1259
  1324. package/src/TextInput/__tests__/TextInput.a11y.chromium.spec.ts +0 -214
  1325. package/src/TextInput/__tests__/TextInput.a11y.known-failures.ts +0 -40
  1326. package/src/TextInput/__tests__/TextInput.a11y.renders.tsx +0 -202
  1327. package/src/TextInput/__tests__/TextInput.a11y.states.ts +0 -384
  1328. package/src/TextInput/__tests__/TextInput.a11y.test.tsx +0 -130
  1329. package/src/Thumbnail/Thumbnail.test.tsx +0 -384
  1330. package/src/TimeInput/NativeTimeInput.test.tsx +0 -326
  1331. package/src/TimeInput/Presentation.test.tsx +0 -171
  1332. package/src/TimeInput/TimeInput.fr10.test.tsx +0 -312
  1333. package/src/TimeInput/TimeInput.test.tsx +0 -831
  1334. package/src/Timer/Timer.test.tsx +0 -302
  1335. package/src/Timestamp/Timestamp.test.tsx +0 -1636
  1336. package/src/Timestamp/tooltipEntries.test.ts +0 -566
  1337. package/src/Toast/ToastViewport.modalHost.test.tsx +0 -891
  1338. package/src/Toast/ToastViewport.test.tsx +0 -2333
  1339. package/src/Toast/useToast.test.tsx +0 -258
  1340. package/src/ToggleButton/ToggleButton.test.tsx +0 -973
  1341. package/src/ToggleButton/__tests__/ToggleButton.a11y.chromium.spec.ts +0 -177
  1342. package/src/ToggleButton/__tests__/ToggleButton.a11y.renders.tsx +0 -133
  1343. package/src/ToggleButton/__tests__/ToggleButton.a11y.states.ts +0 -167
  1344. package/src/ToggleButton/__tests__/ToggleButton.a11y.test.tsx +0 -103
  1345. package/src/Token/Token.test.tsx +0 -640
  1346. package/src/Token/__tests__/TokenRemoveTarget.a11y.chromium.spec.ts +0 -87
  1347. package/src/Tokenizer/Tokenizer.fr10.test.tsx +0 -28
  1348. package/src/Tokenizer/Tokenizer.props-type.test.tsx +0 -126
  1349. package/src/Tokenizer/Tokenizer.ssr.test.tsx +0 -196
  1350. package/src/Tokenizer/Tokenizer.test.tsx +0 -2121
  1351. package/src/Tokenizer/TokenizerBottomSheet.test.tsx +0 -2719
  1352. package/src/Tokenizer/__tests__/TokenizerEndLane.a11y.chromium.spec.ts +0 -505
  1353. package/src/Toolbar/Toolbar.test.tsx +0 -570
  1354. package/src/Toolbar/__tests__/Toolbar.a11y.chromium.spec.ts +0 -164
  1355. package/src/Toolbar/__tests__/Toolbar.a11y.renders.tsx +0 -63
  1356. package/src/Toolbar/__tests__/Toolbar.a11y.states.ts +0 -142
  1357. package/src/Toolbar/__tests__/Toolbar.a11y.test.tsx +0 -126
  1358. package/src/Tooltip/Tooltip.test.tsx +0 -819
  1359. package/src/Tooltip/__tests__/Tooltip.a11y.chromium.spec.ts +0 -130
  1360. package/src/Tooltip/__tests__/Tooltip.a11y.renders.tsx +0 -86
  1361. package/src/Tooltip/__tests__/Tooltip.a11y.states.ts +0 -132
  1362. package/src/Tooltip/__tests__/Tooltip.a11y.test.tsx +0 -126
  1363. package/src/Tooltip/__tests__/TooltipFocusReturn.a11y.chromium.spec.ts +0 -130
  1364. package/src/Tooltip/__tests__/TooltipHoverBridge.a11y.chromium.spec.ts +0 -75
  1365. package/src/Tooltip/__tests__/TooltipTallContent.a11y.browser.spec.ts +0 -673
  1366. package/src/Tooltip/__tests__/TooltipTallContentTracking.a11y.browser.spec.ts +0 -1162
  1367. package/src/Tooltip/useTooltip.test.tsx +0 -483
  1368. package/src/TopNav/TopNav.test.tsx +0 -836
  1369. package/src/TopNav/TopNavMegaMenu.reduced-motion.source-build.test.mjs +0 -83
  1370. package/src/TopNav/TopNavMegaMenu.test.tsx +0 -1132
  1371. package/src/TopNav/TopNavMenu.test.tsx +0 -485
  1372. package/src/TopNav/__tests__/TopNavMobileLongHeading.a11y.chromium.spec.ts +0 -75
  1373. package/src/TreeList/TreeList.test.tsx +0 -1711
  1374. package/src/TreeList/__tests__/TreeList.a11y.chromium.spec.ts +0 -138
  1375. package/src/TreeList/__tests__/TreeList.a11y.renders.tsx +0 -44
  1376. package/src/TreeList/__tests__/TreeList.a11y.states.ts +0 -164
  1377. package/src/TreeList/__tests__/TreeList.a11y.test.tsx +0 -138
  1378. package/src/TreeList/__tests__/TreeListGuideAlignment.interaction.browser.spec.ts +0 -127
  1379. package/src/TreeList/__tests__/TreeListRowNames.a11y.chromium.spec.ts +0 -83
  1380. package/src/Typeahead/BaseTypeahead.emptyState.a11y.chromium.spec.ts +0 -138
  1381. package/src/Typeahead/BaseTypeahead.test.tsx +0 -553
  1382. package/src/Typeahead/Typeahead.fr10.test.tsx +0 -28
  1383. package/src/Typeahead/Typeahead.test.tsx +0 -2824
  1384. package/src/Typeahead/TypeaheadItem.test.tsx +0 -134
  1385. package/src/VStack/VStack.test.tsx +0 -128
  1386. package/src/VisuallyHidden/VisuallyHidden.test.tsx +0 -115
  1387. package/src/__tests__/BusyOwnerAnnouncement.test.tsx +0 -853
  1388. package/src/__tests__/CardPress.a11y.chromium.spec.ts +0 -353
  1389. package/src/__tests__/DisabledTriggerFocus.a11y.chromium.spec.ts +0 -87
  1390. package/src/__tests__/PressModality.a11y.chromium.spec.ts +0 -392
  1391. package/src/__tests__/PressedState.a11y.chromium.spec.ts +0 -814
  1392. package/src/__tests__/TestIcon.tsx +0 -26
  1393. package/src/__tests__/babelPluginAddExtensions.test.ts +0 -190
  1394. package/src/__tests__/fastRoleQueries.ts +0 -66
  1395. package/src/__tests__/forcedColors.ts +0 -60
  1396. package/src/__tests__/pressState.ts +0 -212
  1397. package/src/__tests__/stubMatchMedia.test.ts +0 -79
  1398. package/src/__tests__/stubMatchMedia.ts +0 -95
  1399. package/src/__tests__/stylexDeclarations.ts +0 -51
  1400. package/src/__tests__/unthemedLength.ts +0 -34
  1401. package/src/docPropLiterals.test.ts +0 -964
  1402. package/src/docPropReferences.test.ts +0 -178
  1403. package/src/docs-script.test.mjs +0 -55
  1404. package/src/gestures/__tests__/LongPressGestureRecognizer.test.ts +0 -141
  1405. package/src/gestures/__tests__/PanGestureRecognizer.test.ts +0 -327
  1406. package/src/gestures/__tests__/TapGestureRecognizer.test.ts +0 -154
  1407. package/src/gestures/__tests__/VelocityTracker.streams.test.ts +0 -243
  1408. package/src/gestures/__tests__/VelocityTracker.test.ts +0 -261
  1409. package/src/gestures/__tests__/arena.test.ts +0 -824
  1410. package/src/gestures/__tests__/arenaContinuous.test.ts +0 -207
  1411. package/src/gestures/__tests__/arenaTapLongPress.test.ts +0 -211
  1412. package/src/gestures/__tests__/fixtures/pointer-streams/README.md +0 -82
  1413. package/src/gestures/__tests__/fixtures/pointer-streams/android-chromium-fling.json +0 -130
  1414. package/src/gestures/__tests__/fixtures/pointer-streams/android-chromium-slow.json +0 -860
  1415. package/src/gestures/__tests__/fixtures/pointer-streams/android-chromium-stop-release.json +0 -357
  1416. package/src/gestures/__tests__/fixtures/pointer-streams/android-firefox-fling.json +0 -66
  1417. package/src/gestures/__tests__/fixtures/pointer-streams/android-firefox-slow.json +0 -268
  1418. package/src/gestures/__tests__/fixtures/pointer-streams/android-firefox-stop-release.json +0 -128
  1419. package/src/gestures/__tests__/fixtures/pointer-streams/capture.html +0 -123
  1420. package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-mouse-fling.json +0 -64
  1421. package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-mouse-slow.json +0 -268
  1422. package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-mouse-stop-release.json +0 -124
  1423. package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-pen-fling.json +0 -64
  1424. package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-pen-slow.json +0 -268
  1425. package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-pen-stop-release.json +0 -124
  1426. package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-touch-fling.json +0 -84
  1427. package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-touch-slow.json +0 -381
  1428. package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-touch-stop-release.json +0 -171
  1429. package/src/gestures/__tests__/fixtures/pointer-streams/ios-safari-fling.json +0 -45
  1430. package/src/gestures/__tests__/fixtures/pointer-streams/ios-safari-slow.json +0 -101
  1431. package/src/gestures/__tests__/fixtures/pointer-streams/ios-safari-stop-release.json +0 -130
  1432. package/src/gestures/__tests__/harness.ts +0 -204
  1433. package/src/hooks/__tests__/MenuPressShadowRoot.a11y.chromium.spec.ts +0 -144
  1434. package/src/hooks/__tests__/menuLinkClicks.ts +0 -71
  1435. package/src/hooks/actionGroupTracker.exports.test.ts +0 -28
  1436. package/src/hooks/actionGroupTracker.test.ts +0 -510
  1437. package/src/hooks/computeOverflow.test.ts +0 -422
  1438. package/src/hooks/deprecatedApis.public.test.ts +0 -33
  1439. package/src/hooks/menuPressGesture.test.ts +0 -253
  1440. package/src/hooks/scrollKeyboardDelegation.test.ts +0 -155
  1441. package/src/hooks/scrollbarGutter.test.ts +0 -167
  1442. package/src/hooks/useAnnounce.modal.test.tsx +0 -1291
  1443. package/src/hooks/useAnnounce.test.tsx +0 -293
  1444. package/src/hooks/useAnnounceRenderedText.adopters.test.tsx +0 -226
  1445. package/src/hooks/useAutoMediaMode.test.ts +0 -109
  1446. package/src/hooks/useBusyAnnouncement.adopters.test.tsx +0 -69
  1447. package/src/hooks/useBusyAnnouncement.test.tsx +0 -112
  1448. package/src/hooks/useClickableContainer.test.tsx +0 -236
  1449. package/src/hooks/useClipboard.test.tsx +0 -151
  1450. package/src/hooks/useContainerReveal.test.tsx +0 -163
  1451. package/src/hooks/useDevWarning.test.tsx +0 -45
  1452. package/src/hooks/useEntryAnimation.ssr.test.tsx +0 -143
  1453. package/src/hooks/useFocusTrap.test.tsx +0 -635
  1454. package/src/hooks/useFocusTrapEscapeShim.test.tsx +0 -166
  1455. package/src/hooks/useGridFocus.test.tsx +0 -165
  1456. package/src/hooks/useHotkeys.test.ts +0 -265
  1457. package/src/hooks/useImageMode.test.ts +0 -133
  1458. package/src/hooks/useInputContainer.test.tsx +0 -180
  1459. package/src/hooks/useInputStatusIcon.test.tsx +0 -240
  1460. package/src/hooks/useIsHydrating.test.tsx +0 -70
  1461. package/src/hooks/useKeyboardHint.test.tsx +0 -92
  1462. package/src/hooks/useListFocus.test.tsx +0 -664
  1463. package/src/hooks/useLongPress.test.tsx +0 -152
  1464. package/src/hooks/useMediaQuery.test.ts +0 -165
  1465. package/src/hooks/useMenuHover.test.tsx +0 -536
  1466. package/src/hooks/useMenuPress.test.tsx +0 -565
  1467. package/src/hooks/useMergedRefs.test.tsx +0 -62
  1468. package/src/hooks/useOverflow.test.ts +0 -504
  1469. package/src/hooks/useRenamedProp.test.tsx +0 -95
  1470. package/src/hooks/useScrollLock.test.ts +0 -248
  1471. package/src/hooks/useScrollOverflow.test.tsx +0 -222
  1472. package/src/hooks/useScrollableArea.test.tsx +0 -836
  1473. package/src/hooks/useStreamingText.test.ts +0 -237
  1474. package/src/hooks/useTreeFocus.test.tsx +0 -351
  1475. package/src/hooks/useTypeahead.test.tsx +0 -351
  1476. package/src/i18n/__tests__/InternationalizationProvider.test.tsx +0 -128
  1477. package/src/i18n/__tests__/e2e-pagination.test.tsx +0 -172
  1478. package/src/i18n/__tests__/e2e-powersearch.test.tsx +0 -166
  1479. package/src/i18n/__tests__/getLocaleDirection.test.ts +0 -40
  1480. package/src/i18n/__tests__/resolve.test.ts +0 -325
  1481. package/src/i18n/__tests__/useCollator.test.tsx +0 -115
  1482. package/src/i18n/__tests__/useDirection.test.tsx +0 -66
  1483. package/src/i18n/__tests__/useLocale.test.tsx +0 -52
  1484. package/src/i18n/useTranslator.test.tsx +0 -267
  1485. package/src/inputFontFloor.test.ts +0 -106
  1486. package/src/internal/tokenizer-presentation.test.ts +0 -29
  1487. package/src/internal/touch.test.ts +0 -44
  1488. package/src/motion/__tests__/animatedLayout.interaction.browser.spec.ts +0 -1613
  1489. package/src/motion/__tests__/animatedLayoutAdopters.interaction.browser.spec.ts +0 -217
  1490. package/src/motion/__tests__/animatedLayoutBundle.ts +0 -17
  1491. package/src/motion/animatedLayout.boundary.test.ts +0 -155
  1492. package/src/motion/animatedLayout.swap.test.ts +0 -827
  1493. package/src/motion/animatedLayout.test.ts +0 -1154
  1494. package/src/motion/animatedLayoutAdopters.test.tsx +0 -500
  1495. package/src/motion/animator.test.ts +0 -2653
  1496. package/src/motion/bezier.test.ts +0 -52
  1497. package/src/motion/coast.test.ts +0 -99
  1498. package/src/motion/decay.test.ts +0 -120
  1499. package/src/motion/projection.test.ts +0 -107
  1500. package/src/motion/reducedMotion.test.ts +0 -129
  1501. package/src/motion/reducedMotionPlan.test.ts +0 -182
  1502. package/src/motion/resolveSnapPoint.test.ts +0 -189
  1503. package/src/motion/roles.test.ts +0 -256
  1504. package/src/motion/rubberBand.test.ts +0 -88
  1505. package/src/motion/selectPage.test.ts +0 -31
  1506. package/src/motion/spring.test.ts +0 -650
  1507. package/src/motion/uikit/gestures.test.ts +0 -89
  1508. package/src/motion/uikit/springRows.test.ts +0 -71
  1509. package/src/motion/uikit/uikit.test.ts +0 -364
  1510. package/src/motion/uikit/values.test.ts +0 -110
  1511. package/src/naming.test.ts +0 -44
  1512. package/src/postinstall.test.mjs +0 -216
  1513. package/src/reset.a11y.chromium.spec.ts +0 -238
  1514. package/src/reset.test.ts +0 -205
  1515. package/src/reset.until-found.a11y.browser.spec.ts +0 -76
  1516. package/src/reset.until-found.test.ts +0 -32
  1517. package/src/serverSafeComponents.test.ts +0 -675
  1518. package/src/stylexValidation.source-build.test.mjs +0 -42
  1519. package/src/tailwind-theme.test.ts +0 -153
  1520. package/src/theme/MediaTheme.dom.test.tsx +0 -97
  1521. package/src/theme/Theme.test.tsx +0 -337
  1522. package/src/theme/__tests__/SpacingRootFontSize.a11y.chromium.spec.ts +0 -199
  1523. package/src/theme/contrast.test.ts +0 -94
  1524. package/src/theme/declarationBoundary.test.ts +0 -126
  1525. package/src/theme/defineTheme.test.ts +0 -2028
  1526. package/src/theme/derivedVarRegistry.test.ts +0 -588
  1527. package/src/theme/expandColorScale.test.ts +0 -651
  1528. package/src/theme/expandMotionScale.test.ts +0 -145
  1529. package/src/theme/expandRadiusScale.test.ts +0 -59
  1530. package/src/theme/expandTypeScale.test.ts +0 -351
  1531. package/src/theme/extensibleAxes.test.ts +0 -432
  1532. package/src/theme/generateThemeRules.test.ts +0 -1870
  1533. package/src/theme/hct.test.ts +0 -93
  1534. package/src/theme/onMediaTokens.test.ts +0 -431
  1535. package/src/theme/publicThemeHelperContract.test.ts +0 -67
  1536. package/src/theme/syntax/defineSyntaxTheme.diff.test.ts +0 -91
  1537. package/src/theme/syntax/serverSafeSyntax.test.ts +0 -68
  1538. package/src/theme/syntax/useSyntaxTheme.diff.test.tsx +0 -40
  1539. package/src/theme/themeAdaptations.test.ts +0 -1795
  1540. package/src/theme/themeRegistry.test.ts +0 -59
  1541. package/src/theme/themingTargets.test.ts +0 -589
  1542. package/src/theme/tokenValueCompat.test.ts +0 -204
  1543. package/src/theme/tokens.test.ts +0 -441
  1544. package/src/theme/useTheme.test.tsx +0 -322
  1545. package/src/unicodePropertyEscapes.source-build.test.mjs +0 -69
  1546. package/src/utils/chainEventHandlers.test.ts +0 -39
  1547. package/src/utils/characters.test.ts +0 -141
  1548. package/src/utils/color.test.ts +0 -233
  1549. package/src/utils/composeEventHandlers.test.ts +0 -71
  1550. package/src/utils/customPropertyArmLayering.test.ts +0 -131
  1551. package/src/utils/dateParser.test.ts +0 -402
  1552. package/src/utils/dateTypes.test.ts +0 -40
  1553. package/src/utils/devWarning.test.ts +0 -56
  1554. package/src/utils/edgeAutoscroll.test.ts +0 -192
  1555. package/src/utils/focusReturn.test.ts +0 -119
  1556. package/src/utils/getKey.test.ts +0 -25
  1557. package/src/utils/hitArea.test.ts +0 -628
  1558. package/src/utils/ime.test.ts +0 -32
  1559. package/src/utils/inputAria.test.ts +0 -39
  1560. package/src/utils/interactionModality.test.ts +0 -100
  1561. package/src/utils/isApplePlatform.test.ts +0 -61
  1562. package/src/utils/mergeProps.test.ts +0 -166
  1563. package/src/utils/mergeRefs.test.ts +0 -48
  1564. package/src/utils/parseStyleKey.test.ts +0 -56
  1565. package/src/utils/plainDate.test.ts +0 -848
  1566. package/src/utils/pressFeedback.test.ts +0 -874
  1567. package/src/utils/pressGesture.test.ts +0 -323
  1568. package/src/utils/pressPaintSource.test.ts +0 -65
  1569. package/src/utils/pressableCoverage.test.ts +0 -192
  1570. package/src/utils/safeUrl.test.ts +0 -101
  1571. package/src/utils/sharedMutationObserver.test.ts +0 -53
  1572. package/src/utils/sharedResizeObserver.test.ts +0 -283
  1573. package/src/utils/themeProps.test.ts +0 -62
  1574. package/src/utils/timeParser.test.ts +0 -295
  1575. package/src/utils/touchPresentation.test.ts +0 -323
@@ -1,2828 +0,0 @@
1
- // Copyright (c) Meta Platforms, Inc. and affiliates.
2
-
3
- /**
4
- * @file DateInputTouch.test.tsx
5
- * @input Uses vitest, @testing-library/react, DateInput and its helpers
6
- * @output Behavior coverage for the responsive date picker
7
- * @position Test file for /packages/core/src/DateInput/
8
- *
9
- * What jsdom can and cannot see here matters, and the split is deliberate:
10
- *
11
- * - The month math is pure, so it is tested directly and exhaustively.
12
- * - Which surface is chosen, and the field contract each one honors, are
13
- * tested through the DOM with `matchMedia` stubbed per test.
14
- * - Snapping, momentum and the scroll-driven falloff are CSS the browser
15
- * resolves and jsdom does not implement at all. Those are asserted on the
16
- * style DEFINITION instead (the last describe block), which at least fails
17
- * loudly if someone deletes the property; the real verification is a
18
- * browser, and the values it produced are recorded in the doc file.
19
- */
20
-
21
- import {
22
- describe,
23
- it,
24
- expect,
25
- vi,
26
- beforeAll,
27
- afterAll,
28
- beforeEach,
29
- afterEach,
30
- } from 'vitest';
31
- import {
32
- render,
33
- screen,
34
- fireEvent,
35
- within,
36
- waitFor,
37
- } from '@testing-library/react';
38
- import {readFileSync} from 'node:fs';
39
- import path from 'node:path';
40
- import {fileURLToPath} from 'node:url';
41
- import {useState} from 'react';
42
- import type {ISODateString} from '../utils';
43
- import {InputGroup} from '../InputGroup';
44
- import {InternationalizationProvider} from '../i18n';
45
- import {DateInput} from './DateInput';
46
- import {
47
- toMonthIndex,
48
- monthIndexOf,
49
- fromMonthIndex,
50
- clampIndex,
51
- rowAtScrollOffset,
52
- scrollOffsetForRow,
53
- paneWindow,
54
- rowsIn,
55
- DEFAULT_MONTH_REACH,
56
- } from './monthGeometry';
57
- import {SWIPE_DISTANCE} from './useOwnScrollGesture';
58
- import {DRAG_SLOP} from './usePointerDragScroll';
59
- import {SCROLL_QUIET_MS} from './useScrollSettle';
60
-
61
- // ---------------------------------------------------------------------------
62
- // jsdom scaffolding
63
- // ---------------------------------------------------------------------------
64
-
65
- class MockResizeObserver {
66
- observe() {}
67
- unobserve() {}
68
- disconnect() {}
69
- }
70
-
71
- /** An arbitrary pane size for the pure geometry tests. */
72
- const PANE = 264;
73
- /**
74
- * What the month scrollport measures as. The scroller pages along the INLINE
75
- * axis, so its pane size is a WIDTH — a phone's worth, since the value only
76
- * has to be non-zero and consistent for the virtualization to mount panes.
77
- */
78
- const SCROLLPORT_WIDTH = 360;
79
-
80
- /** Matches the repo-wide setup polyfill, so hover-gated behavior still works. */
81
- const HOVER_CAPABLE = /\(\s*hover\s*:\s*hover\s*\)/;
82
-
83
- /**
84
- * Answer media queries the way a given device would.
85
- *
86
- * Width queries are answered HONESTLY against `width`, so a width bound
87
- * creeping back into the surface switch fails a test rather than passing
88
- * silently on a stub that ignores it.
89
- */
90
- function stubMedia({
91
- pointer,
92
- anyPointer,
93
- width,
94
- }: {
95
- pointer: 'coarse' | 'fine';
96
- anyPointer?: 'coarse' | 'fine';
97
- width: number;
98
- }): void {
99
- vi.stubGlobal('matchMedia', (query: string) => {
100
- let matches: boolean;
101
- const maxWidth = /\(\s*max-width:\s*(\d+)px\s*\)/.exec(query);
102
- const minWidth = /\(\s*min-width:\s*(\d+)px\s*\)/.exec(query);
103
- if (/any-pointer:\s*coarse/.test(query)) {
104
- matches = (anyPointer ?? pointer) === 'coarse';
105
- } else if (/pointer:\s*coarse/.test(query)) {
106
- matches = pointer === 'coarse';
107
- } else if (/pointer:\s*fine/.test(query)) {
108
- matches = pointer === 'fine';
109
- } else if (maxWidth) {
110
- matches = width <= Number(maxWidth[1]);
111
- } else if (minWidth) {
112
- matches = width >= Number(minWidth[1]);
113
- } else {
114
- matches = HOVER_CAPABLE.test(query);
115
- }
116
- // A compound query is only true when every part of it is.
117
- if (matches && maxWidth && query.includes('pointer:')) {
118
- matches = width <= Number(maxWidth[1]);
119
- }
120
- return {
121
- matches,
122
- media: query,
123
- onchange: null,
124
- addListener: () => {},
125
- removeListener: () => {},
126
- addEventListener: () => {},
127
- removeEventListener: () => {},
128
- dispatchEvent: () => false,
129
- };
130
- });
131
- }
132
-
133
- function setViewport(kind: 'mobile' | 'desktop'): void {
134
- stubMedia(
135
- kind === 'mobile'
136
- ? {pointer: 'coarse', width: 393}
137
- : {pointer: 'fine', width: 1280},
138
- );
139
- }
140
-
141
- /**
142
- * Run `fn` with the month scrollport reporting the height its CSS gives it.
143
- *
144
- * jsdom lays nothing out, so `clientHeight` is 0 and the scroller mounts no
145
- * panes at all. The override is installed only around the work that needs it
146
- * and torn down immediately: a getter left on `HTMLElement.prototype` makes
147
- * EVERY later DOM read take a slow path, measured at ~2.4s per test here.
148
- */
149
- /** One animation frame, for the rAF-throttled scroll handlers. */
150
- async function frame(): Promise<void> {
151
- return new Promise(resolve => requestAnimationFrame(() => resolve()));
152
- }
153
-
154
- function withLayout<T>(fn: () => T): T {
155
- // jsdom defines clientWidth on Element.prototype; shadowing it on
156
- // HTMLElement.prototype and deleting the shadow afterwards restores the
157
- // original getter without having to copy its descriptor.
158
- Object.defineProperty(HTMLElement.prototype, 'clientWidth', {
159
- configurable: true,
160
- get(this: HTMLElement) {
161
- return this.dataset?.scroller === 'months' ? SCROLLPORT_WIDTH : 0;
162
- },
163
- });
164
- try {
165
- return fn();
166
- } finally {
167
- delete (HTMLElement.prototype as {clientWidth?: unknown}).clientWidth;
168
- }
169
- }
170
-
171
- beforeAll(() => {
172
- Element.prototype.scrollTo = vi.fn();
173
- // jsdom's <dialog> implements none of these.
174
- HTMLDialogElement.prototype.showModal = vi.fn(function (
175
- this: HTMLDialogElement,
176
- ) {
177
- this.open = true;
178
- });
179
- HTMLDialogElement.prototype.show = vi.fn(function (this: HTMLDialogElement) {
180
- this.open = true;
181
- });
182
- HTMLDialogElement.prototype.close = vi.fn(function (this: HTMLDialogElement) {
183
- this.open = false;
184
- });
185
- });
186
-
187
- afterAll(() => {
188
- vi.useRealTimers();
189
- });
190
-
191
- beforeEach(() => {
192
- vi.setSystemTime(new Date(2026, 2, 15)); // 15 March 2026, local
193
- // Re-stubbed per test, not once at module scope: the afterEach below clears
194
- // every stub, and matchMedia has to be re-pointed for each test anyway.
195
- vi.stubGlobal('ResizeObserver', MockResizeObserver);
196
- setViewport('mobile');
197
- });
198
-
199
- afterEach(() => {
200
- vi.unstubAllGlobals();
201
- });
202
-
203
- /**
204
- * Bounded by default. Unbounded, the scroller mounts seven month panes — 294
205
- * day buttons — for every render, and under jsdom with StyleX's dev runtime
206
- * that is seconds a test. Three months exercises the same paths; the tests
207
- * that are actually about the range pass their own.
208
- */
209
- const DEFAULT_RANGE = {min: '2026-02-01', max: '2026-04-30'} as const;
210
-
211
- function Controlled({
212
- initial,
213
- onChange,
214
- ...props
215
- }: {initial?: ISODateString} & Partial<
216
- React.ComponentProps<typeof DateInput>
217
- >) {
218
- const [value, setValue] = useState<ISODateString | undefined>(initial);
219
- return (
220
- <DateInput
221
- label="Event date"
222
- // This suite is about Astryx's own touch surface, which is now opt-out:
223
- // `nativePicker` defaults to 'touch', so a coarse pointer gets the
224
- // platform's picker unless a field says otherwise. Tests that assert on
225
- // the surface selection itself pass their own value over this.
226
- nativePicker="never"
227
- {...DEFAULT_RANGE}
228
- {...props}
229
- value={value}
230
- // Composed, not overridden: spreading a test's `onChange` over this one
231
- // used to replace the state setter, so the field silently stopped
232
- // updating in exactly the tests that were watching it most closely.
233
- onChange={next => {
234
- setValue(next);
235
- onChange?.(next);
236
- }}
237
- />
238
- );
239
- }
240
-
241
- /** The closed field — a real input on both surfaces. */
242
- const field = (): HTMLInputElement => screen.getByRole('combobox');
243
-
244
- /** Render, then open the picker. Both mount panes, so both need the layout. */
245
- function renderAndOpen(
246
- ui: React.ReactElement = <Controlled initial="2026-03-21" />,
247
- ): void {
248
- withLayout(() => {
249
- render(ui);
250
- fireEvent.click(field());
251
- });
252
- }
253
-
254
- /**
255
- * One month's grid. Panes for neighbouring months are mounted too, so every
256
- * day query has to say which month it means.
257
- */
258
- function pane(label: string): HTMLElement {
259
- const grid = screen
260
- .getAllByRole('grid')
261
- .find(g => g.getAttribute('aria-label') === label);
262
- if (grid == null) {
263
- throw new Error(`no pane for ${label}`);
264
- }
265
- return grid;
266
- }
267
-
268
- /** The decorative weekday row: the only 7-cell aria-hidden block. */
269
- function weekdayRow(): HTMLElement {
270
- const row = [...document.querySelectorAll('[aria-hidden="true"]')].find(
271
- el => el.children.length === 7,
272
- );
273
- if (row == null) {
274
- throw new Error('no weekday row');
275
- }
276
- return row as HTMLElement;
277
- }
278
-
279
- // ---------------------------------------------------------------------------
280
- // Which surface, and why
281
- // ---------------------------------------------------------------------------
282
-
283
- describe('DateInput — surface selection', () => {
284
- it('hands a touch device to the platform picker by default', () => {
285
- // `nativePicker` defaults to 'touch': the OS draws the picker unless a
286
- // field opts out. Everything else in this file passes 'never', so this is
287
- // the one place the default itself is asserted.
288
- stubMedia({pointer: 'coarse', width: 393});
289
- render(<DateInput label="Event date" onChange={() => {}} />);
290
- const input = document.querySelector('input');
291
- expect(input).toHaveAttribute('type', 'date');
292
- });
293
-
294
- it('switches on the pointer alone, so a tablet gets the picker too', () => {
295
- // `pointer` is the PRIMARY device, which is what makes it the whole test:
296
- // a touchscreen laptop reports `fine` (its trackpad) and keeps the
297
- // typable field, and a narrowed desktop window is still a mouse. A width
298
- // bound would only re-exclude tablets — the clearest case for a thumb
299
- // picker there is — so there deliberately is not one.
300
- //
301
- // An 1194px tablet in landscape: coarse pointer, far wider than any
302
- // handset breakpoint. It answers width queries honestly, so a width bound
303
- // creeping back in would fail here rather than pass silently.
304
- stubMedia({pointer: 'coarse', width: 1194});
305
- render(<Controlled initial="2026-03-21" />);
306
- expect(field()).toHaveAttribute('readonly');
307
- });
308
-
309
- it('keeps the typable field for a touchscreen laptop', () => {
310
- // Touch available, but the trackpad is primary — so `pointer` is `fine`
311
- // and only `any-pointer` is coarse. The keyboard is right there, and
312
- // typing a date beats scrolling to it.
313
- stubMedia({pointer: 'fine', anyPointer: 'coarse', width: 1366});
314
- render(<Controlled initial="2026-03-21" />);
315
- expect(field()).not.toHaveAttribute('readonly');
316
- });
317
-
318
- it('keeps the typable field in a narrowed desktop window', () => {
319
- stubMedia({pointer: 'fine', width: 500});
320
- render(<Controlled initial="2026-03-21" />);
321
- expect(field()).not.toHaveAttribute('readonly');
322
- });
323
-
324
- it('renders the desktop DateInput when the query does not match', () => {
325
- setViewport('desktop');
326
- render(<Controlled initial="2026-03-21" />);
327
- // The desktop control is a text field you can type into...
328
- expect(field()).not.toHaveAttribute('readonly');
329
- expect(field()).not.toHaveAttribute('inputmode');
330
- // ...and it opens a popover, not a sheet.
331
- expect(document.querySelector('dialog')).toBeNull();
332
- });
333
-
334
- it('accepts typed input on the desktop surface', () => {
335
- setViewport('desktop');
336
- const onChange = vi.fn();
337
- render(
338
- <DateInput
339
- nativePicker="never"
340
- label="Event date"
341
- onChange={onChange}
342
- min={undefined}
343
- />,
344
- );
345
- fireEvent.change(field(), {target: {value: '2026-03-25'}});
346
- expect(onChange).toHaveBeenCalledWith('2026-03-25');
347
- });
348
-
349
- it('renders the touch field when the query matches', () => {
350
- render(<Controlled initial="2026-03-21" />);
351
- const input = field();
352
- // Still an input — same element, same role, so `ref` stays honest and the
353
- // label associates natively — but the picker is the only way to change it.
354
- expect(input.tagName).toBe('INPUT');
355
- expect(input).toHaveAttribute('readonly');
356
- // What actually keeps the virtual keyboard from covering the sheet.
357
- expect(input).toHaveAttribute('inputmode', 'none');
358
- });
359
-
360
- it('updates the field and open picker when the provider locale changes', () => {
361
- const renderDateInput = (locale: 'en-US' | 'es-ES') => (
362
- <InternationalizationProvider locale={locale}>
363
- <Controlled initial="2026-03-21" />
364
- </InternationalizationProvider>
365
- );
366
-
367
- withLayout(() => {
368
- const {rerender} = render(renderDateInput('en-US'));
369
- expect(field()).toHaveValue('March 21, 2026');
370
-
371
- fireEvent.click(field());
372
- expect(
373
- document.querySelector('[data-title="month-year"]'),
374
- ).toHaveTextContent('March 2026');
375
- expect(pane('March 2026')).toBeInTheDocument();
376
-
377
- rerender(renderDateInput('es-ES'));
378
- expect(field()).toHaveValue('21 de marzo de 2026');
379
- expect(
380
- document.querySelector('[data-title="month-year"]'),
381
- ).toHaveTextContent('marzo de 2026');
382
- expect(pane('marzo de 2026')).toBeInTheDocument();
383
-
384
- const nextButton = document.querySelector<HTMLButtonElement>(
385
- '[data-arrows="months"] button:last-child',
386
- );
387
- expect(nextButton).not.toBeNull();
388
- fireEvent.click(nextButton!);
389
- expect(
390
- document.querySelector('[data-title="month-year"]'),
391
- ).toHaveTextContent('abril de 2026');
392
- });
393
- });
394
-
395
- it('forwards ref to the input on both surfaces', () => {
396
- const desktopRef = {current: null as HTMLInputElement | null};
397
- setViewport('desktop');
398
- const {unmount} = render(
399
- <Controlled initial="2026-03-21" ref={desktopRef} />,
400
- );
401
- expect(desktopRef.current).toBeInstanceOf(HTMLInputElement);
402
- unmount();
403
-
404
- const mobileRef = {current: null as HTMLInputElement | null};
405
- setViewport('mobile');
406
- render(<Controlled initial="2026-03-21" ref={mobileRef} />);
407
- expect(mobileRef.current).toBeInstanceOf(HTMLInputElement);
408
- });
409
- });
410
-
411
- // ---------------------------------------------------------------------------
412
- // The field contract, honored identically on the touch surface
413
- // ---------------------------------------------------------------------------
414
-
415
- describe('DateInput — field parity', () => {
416
- it('shows a placeholder until a date is chosen, then the formatted value', () => {
417
- const {rerender} = render(
418
- <DateInput nativePicker="never" label="Ship date" onChange={() => {}} />,
419
- );
420
- expect(field()).toHaveValue('');
421
- expect(field()).toHaveAttribute('placeholder', 'Select a date');
422
- rerender(
423
- <DateInput
424
- nativePicker="never"
425
- label="Ship date"
426
- value="2026-03-21"
427
- onChange={() => {}}
428
- />,
429
- );
430
- expect(field()).toHaveValue('March 21, 2026');
431
- });
432
-
433
- it('honors a named format', () => {
434
- render(
435
- <DateInput
436
- nativePicker="never"
437
- label="Ship date"
438
- value="2026-03-21"
439
- format="system_date"
440
- onChange={() => {}}
441
- />,
442
- );
443
- expect(field()).toHaveValue('2026-03-21');
444
- });
445
-
446
- it('honors a function format', () => {
447
- render(
448
- <DateInput
449
- nativePicker="never"
450
- label="Ship date"
451
- value="2026-03-21"
452
- format={iso => `ISO:${iso}`}
453
- onChange={() => {}}
454
- />,
455
- );
456
- expect(field()).toHaveValue('ISO:2026-03-21');
457
- });
458
-
459
- it('honors a custom placeholder', () => {
460
- render(
461
- <DateInput
462
- nativePicker="never"
463
- label="Ship date"
464
- placeholder="Pick a day"
465
- onChange={() => {}}
466
- />,
467
- );
468
- expect(field()).toHaveAttribute('placeholder', 'Pick a day');
469
- });
470
-
471
- it('clears from the field', () => {
472
- const onChange = vi.fn();
473
- render(
474
- <DateInput
475
- nativePicker="never"
476
- label="Ship date"
477
- value="2026-03-21"
478
- hasClear
479
- onChange={onChange}
480
- />,
481
- );
482
- fireEvent.click(screen.getByRole('button', {name: /Clear Ship date/}));
483
- expect(onChange).toHaveBeenCalledWith(undefined);
484
- });
485
-
486
- it('returns focus to the field without letting the page scroll', async () => {
487
- // Clearing unmounts the clear button, and focusing another element in the
488
- // same task as that unmount makes iOS Safari scroll the document to the
489
- // top. Measured on the iOS 26 simulator against the live docsite, field at
490
- // scrollY 2055: synchronous focus lands at 0, deferred focus stays at
491
- // 2055. `preventScroll` alone does not fix it, so both halves are
492
- // asserted: the focus is deferred past the unmount, and it is passed
493
- // preventScroll. jsdom implements no scrolling, so the guard is asserted
494
- // at the call.
495
- vi.useFakeTimers();
496
- try {
497
- render(
498
- <DateInput
499
- nativePicker="never"
500
- label="Ship date"
501
- value="2026-03-21"
502
- hasClear
503
- onChange={() => {}}
504
- />,
505
- );
506
- const input = field();
507
- const focus = vi.spyOn(input, 'focus');
508
-
509
- fireEvent.click(screen.getByRole('button', {name: /Clear Ship date/}));
510
-
511
- // Not synchronous — that is the whole point.
512
- expect(focus).not.toHaveBeenCalled();
513
-
514
- vi.runAllTimers();
515
-
516
- expect(focus).toHaveBeenCalledWith({preventScroll: true});
517
- focus.mockRestore();
518
- } finally {
519
- vi.useRealTimers();
520
- }
521
- });
522
-
523
- it('does not open the picker until the field is tapped', () => {
524
- withLayout(() => {
525
- render(
526
- <DateInput
527
- nativePicker="never"
528
- label="Ship date"
529
- onChange={() => {}}
530
- />,
531
- );
532
- expect(field()).toHaveAttribute('aria-expanded', 'false');
533
- expect(screen.queryByRole('grid')).not.toBeInTheDocument();
534
- fireEvent.click(field());
535
- expect(field()).toHaveAttribute('aria-expanded', 'true');
536
- expect(screen.getAllByRole('grid').length).toBeGreaterThan(0);
537
- });
538
- });
539
-
540
- it('opens from the keyboard, APG combobox style', () => {
541
- withLayout(() => {
542
- render(<Controlled initial="2026-03-21" />);
543
- fireEvent.keyDown(field(), {key: 'ArrowDown'});
544
- expect(field()).toHaveAttribute('aria-expanded', 'true');
545
- });
546
- });
547
-
548
- it('is not openable while disabled', () => {
549
- render(
550
- <DateInput
551
- nativePicker="never"
552
- label="Ship date"
553
- isDisabled
554
- onChange={() => {}}
555
- />,
556
- );
557
- // Focusable, never natively disabled (AST-085 FR1), and still inert.
558
- expect(field()).not.toHaveAttribute('disabled');
559
- expect(field()).toHaveAttribute('aria-disabled', 'true');
560
- field().focus();
561
- expect(field()).toHaveFocus();
562
- fireEvent.click(field());
563
- fireEvent.keyDown(field(), {key: 'Enter'});
564
- expect(field()).toHaveAttribute('aria-expanded', 'false');
565
- expect(screen.queryByRole('grid')).not.toBeInTheDocument();
566
- });
567
-
568
- it('does not call a caller onClick while disabled (AST-085 FR2)', () => {
569
- const onClick = vi.fn();
570
- render(
571
- <DateInput
572
- nativePicker="never"
573
- label="Ship date"
574
- isDisabled
575
- onClick={onClick}
576
- onChange={() => {}}
577
- />,
578
- );
579
- fireEvent.click(field());
580
- expect(onClick).not.toHaveBeenCalled();
581
- });
582
-
583
- it('stays focusable and explains itself when disabled with a reason', () => {
584
- render(
585
- <DateInput
586
- nativePicker="never"
587
- label="Ship date"
588
- isDisabled
589
- disabledMessage="You need the Editor role"
590
- onChange={() => {}}
591
- />,
592
- );
593
- // aria-disabled, not disabled: the reason has to be reachable by keyboard.
594
- expect(field()).not.toBeDisabled();
595
- expect(field()).toHaveAttribute('aria-disabled', 'true');
596
- fireEvent.click(field());
597
- expect(screen.queryByRole('grid')).not.toBeInTheDocument();
598
- });
599
-
600
- it('renders label, description and status through Field', () => {
601
- render(
602
- <DateInput
603
- nativePicker="never"
604
- label="Ship date"
605
- description="When it leaves the warehouse"
606
- status={{type: 'error', message: 'Pick a date'}}
607
- onChange={() => {}}
608
- />,
609
- );
610
- expect(screen.getByText('Ship date')).toBeInTheDocument();
611
- expect(
612
- screen.getByText('When it leaves the warehouse'),
613
- ).toBeInTheDocument();
614
- expect(screen.getByText('Pick a date')).toBeInTheDocument();
615
- expect(field()).toHaveAttribute('aria-invalid', 'true');
616
- expect(field().getAttribute('aria-describedby')).toBeTruthy();
617
- });
618
-
619
- it('marks required for assistive technology', () => {
620
- render(
621
- <DateInput
622
- nativePicker="never"
623
- label="Ship date"
624
- isRequired
625
- onChange={() => {}}
626
- />,
627
- );
628
- expect(field()).toHaveAttribute('aria-required', 'true');
629
- });
630
-
631
- it('associates the label natively, so the field is named without ARIA', () => {
632
- render(
633
- <DateInput nativePicker="never" label="Ship date" onChange={() => {}} />,
634
- );
635
- expect(screen.getByLabelText('Ship date')).toBe(field());
636
- });
637
-
638
- it('runs changeAction and shows a busy state', async () => {
639
- let resolve: () => void = () => {};
640
- const changeAction = vi.fn(
641
- async () =>
642
- new Promise<void>(r => {
643
- resolve = r;
644
- }),
645
- );
646
- withLayout(() => {
647
- render(
648
- <DateInput
649
- nativePicker="never"
650
- label="Ship date"
651
- value="2026-03-10"
652
- min="2026-03-01"
653
- max="2026-03-31"
654
- onChange={() => {}}
655
- changeAction={changeAction}
656
- />,
657
- );
658
- fireEvent.click(field());
659
- fireEvent.click(
660
- within(pane('March 2026')).getByRole('button', {
661
- name: /March 25, 2026/,
662
- }),
663
- );
664
- });
665
- expect(changeAction).toHaveBeenCalledWith('2026-03-25');
666
- resolve();
667
- });
668
-
669
- it('announces a busy start from a pick inside the open sheet, not behind it (spec:AST-086 FR8, Platform support)', async () => {
670
- // The stubbed showModal() opens the dialog but jsdom cannot match
671
- // `:modal`; stand in for the sheet the browser presents modally.
672
- const matches = Element.prototype.matches;
673
- const modalSpy = vi
674
- .spyOn(Element.prototype, 'matches')
675
- .mockImplementation(function (this: Element, selector: string) {
676
- return selector === ':modal'
677
- ? this instanceof HTMLDialogElement && this.open
678
- : matches.call(this, selector);
679
- });
680
- const changeAction = vi.fn(async () => new Promise<void>(() => {}));
681
- withLayout(() => {
682
- render(
683
- <DateInput
684
- nativePicker="never"
685
- label="Ship date"
686
- value="2026-03-10"
687
- min="2026-03-01"
688
- max="2026-03-31"
689
- onChange={() => {}}
690
- changeAction={changeAction}
691
- />,
692
- );
693
- fireEvent.click(field());
694
- fireEvent.click(
695
- within(pane('March 2026')).getByRole('button', {
696
- name: /March 25, 2026/,
697
- }),
698
- );
699
- });
700
- const sheet = document.querySelector('dialog[open]');
701
- expect(sheet).not.toBeNull();
702
- await waitFor(() => {
703
- expect(
704
- sheet!.querySelector('[data-astryx-modal-live-region="polite"]'),
705
- ).toHaveTextContent('Loading');
706
- });
707
- expect(
708
- document.querySelector('[data-astryx-live-region="polite"]')
709
- ?.textContent ?? '',
710
- ).toBe('');
711
- modalSpy.mockRestore();
712
- });
713
-
714
- it('drops the Field wrapper inside an InputGroup', () => {
715
- render(
716
- <InputGroup label="Range">
717
- <DateInput nativePicker="never" label="Start" onChange={() => {}} />
718
- </InputGroup>,
719
- );
720
- // Named by the group label plus its own, the way core's inputs are.
721
- expect(field().getAttribute('aria-labelledby')).toBeTruthy();
722
- });
723
- });
724
-
725
- // ---------------------------------------------------------------------------
726
- // The picker surface
727
- // ---------------------------------------------------------------------------
728
-
729
- describe('DateInput — calendar surface', () => {
730
- it('opens on the selected month', () => {
731
- renderAndOpen();
732
- expect(pane('March 2026')).toBeInTheDocument();
733
- });
734
-
735
- it('opens on the current month when there is no value', () => {
736
- renderAndOpen(<Controlled />);
737
- expect(pane('March 2026')).toBeInTheDocument();
738
- });
739
-
740
- it('mounts a window of months around the visible one, not the whole century', () => {
741
- // The one test that wants the full default reach.
742
- renderAndOpen(
743
- <Controlled initial="2026-03-21" min={undefined} max={undefined} />,
744
- );
745
- const grids = screen.getAllByRole('grid');
746
- expect(grids.length).toBeGreaterThan(1);
747
- expect(grids.length).toBeLessThanOrEqual(7);
748
- expect(grids.map(g => g.getAttribute('aria-label'))).toContain(
749
- 'March 2026',
750
- );
751
- });
752
-
753
- it('renders every month as six rows, so panes cannot differ in height', () => {
754
- renderAndOpen(<Controlled initial="2026-02-01" />);
755
- // February 2026 needs only five rows; the pane still has six.
756
- const february = within(pane('February 2026'));
757
- expect(february.getAllByRole('row')).toHaveLength(6);
758
- expect(february.getAllByRole('gridcell')).toHaveLength(42);
759
- });
760
-
761
- it('commits the tapped day and LEAVES the sheet open', () => {
762
- const onChange = vi.fn();
763
- renderAndOpen(<Controlled initial="2026-03-21" onChange={onChange} />);
764
- fireEvent.click(
765
- within(pane('March 2026')).getByRole('button', {name: /March 25, 2026/}),
766
- );
767
- // The tap is the commit. Staying open lets a mistake be corrected in
768
- // place, and a nearby date reconsidered, without reopening.
769
- expect(onChange).toHaveBeenCalledWith('2026-03-25');
770
- expect(field()).toHaveAttribute('aria-expanded', 'true');
771
- });
772
-
773
- it('lets a second tap correct the first, still without closing', () => {
774
- const onChange = vi.fn();
775
- renderAndOpen(<Controlled initial="2026-03-21" onChange={onChange} />);
776
- const march = within(pane('March 2026'));
777
- fireEvent.click(march.getByRole('button', {name: /March 25, 2026/}));
778
- fireEvent.click(march.getByRole('button', {name: /March 26, 2026/}));
779
- expect(onChange).toHaveBeenLastCalledWith('2026-03-26');
780
- expect(field()).toHaveAttribute('aria-expanded', 'true');
781
- });
782
-
783
- it('Save closes the sheet without touching the value', () => {
784
- const onChange = vi.fn();
785
- renderAndOpen(<Controlled initial="2026-03-21" onChange={onChange} />);
786
- fireEvent.click(
787
- within(pane('March 2026')).getByRole('button', {name: /March 25, 2026/}),
788
- );
789
- onChange.mockClear();
790
- fireEvent.click(screen.getByRole('button', {name: 'Save'}));
791
- expect(field()).toHaveAttribute('aria-expanded', 'false');
792
- // Named for what it means to someone finishing a form, not for what it
793
- // does internally: the value was already committed by the tap that chose
794
- // it, so this fires nothing of its own.
795
- expect(onChange).not.toHaveBeenCalled();
796
- expect(field()).toHaveValue('March 25, 2026');
797
- });
798
-
799
- it('Save closes even with no date chosen, committing nothing', () => {
800
- const onChange = vi.fn();
801
- withLayout(() => {
802
- render(
803
- <DateInput
804
- nativePicker="never"
805
- label="Ship date"
806
- onChange={onChange}
807
- />,
808
- );
809
- fireEvent.click(field());
810
- fireEvent.click(screen.getByRole('button', {name: 'Save'}));
811
- });
812
- expect(field()).toHaveAttribute('aria-expanded', 'false');
813
- expect(onChange).not.toHaveBeenCalled();
814
- });
815
-
816
- it('has Save in the footer and no Today button', () => {
817
- renderAndOpen();
818
- expect(screen.getByRole('button', {name: 'Save'})).toBeInTheDocument();
819
- // "Today" moved the calendar to the current month WITHOUT selecting it,
820
- // which read as broken — the one thing the name promises is the thing it
821
- // did not do. Removed until it can be navigate-or-select on purpose.
822
- expect(screen.queryByRole('button', {name: 'Today'})).toBeNull();
823
- });
824
-
825
- it('marks the selection and today', () => {
826
- renderAndOpen();
827
- const march = within(pane('March 2026'));
828
- expect(
829
- march
830
- .getByRole('button', {name: /March 21, 2026/})
831
- .closest('[role="gridcell"]'),
832
- ).toHaveAttribute('aria-selected', 'true');
833
- expect(march.getByRole('button', {name: /March 15, 2026/})).toHaveAttribute(
834
- 'aria-current',
835
- 'date',
836
- );
837
- });
838
-
839
- it('leaves exactly one day per month tab-reachable', () => {
840
- renderAndOpen();
841
- const tabbable = within(pane('March 2026'))
842
- .getAllByRole('button')
843
- .filter(b => b.getAttribute('tabindex') === '0');
844
- expect(tabbable).toHaveLength(1);
845
- // The selected day, when the month holds one.
846
- expect(tabbable[0]).toHaveAttribute('data-date', '2026-03-21');
847
- });
848
-
849
- it('pages a month with the header arrows', () => {
850
- renderAndOpen();
851
- const header = () =>
852
- document.querySelector<HTMLElement>('[data-title="month-year"]')!;
853
- expect(header()).toHaveTextContent('March 2026');
854
- fireEvent.click(screen.getByRole('button', {name: 'Next month'}));
855
- expect(header()).toHaveTextContent('April 2026');
856
- fireEvent.click(screen.getByRole('button', {name: 'Previous month'}));
857
- expect(header()).toHaveTextContent('March 2026');
858
- });
859
-
860
- /**
861
- * A programmatic scroll must not report its own arrival as if the user had
862
- * scrolled there. Nothing needs the report — whatever asked for the scroll
863
- * already knows the month — and trusting it turns a steer into a cycle.
864
- *
865
- * The case that bit: a wheel commit steers this scroller while it is hidden
866
- * behind the wheels, and a hidden scroller does not reliably stay put. On
867
- * iOS the position is re-snapped when the panel becomes visible again,
868
- * firing a scroll just as the wheels close and reports start being trusted
869
- * again — so the month drifted on the way back to the calendar.
870
- */
871
- it('does not report a scroll it was told to make', async () => {
872
- await withLayout(async () => {
873
- render(
874
- <Controlled initial="2026-03-21" min="2026-01-01" max="2026-12-31" />,
875
- );
876
- fireEvent.click(field());
877
- const header = () =>
878
- document.querySelector<HTMLElement>('[data-title="month-year"]')!;
879
- const scroller = document.querySelector<HTMLElement>(
880
- '[data-scroller="months"]',
881
- )!;
882
-
883
- // An arrow steers it to April. The scroll that lands there is our own
884
- // doing, so whatever it reports must not move the month again.
885
- fireEvent.click(screen.getByRole('button', {name: 'Next month'}));
886
- expect(header()).toHaveTextContent('April 2026');
887
- // Row 3 of a range starting in January is April: the month the steer
888
- // was aiming at, arriving.
889
- scroller.scrollLeft = 3 * SCROLLPORT_WIDTH;
890
- fireEvent.scroll(scroller);
891
- await frame();
892
- expect(header()).toHaveTextContent('April 2026');
893
-
894
- // A finger ends the steering: from here the months it passes are the
895
- // user's, and every one of them counts.
896
- // jsdom has no constructible TouchEvent, and a bare Event carries no
897
- // `touches` — which crashes the gesture hook that reads `touches[0]`.
898
- // That crash is the fake event's fault, not the hook's: a browser's
899
- // touchstart always has the list.
900
- const touchStart = new Event('touchstart', {bubbles: true});
901
- const point = {identifier: 1, clientX: 100, clientY: 100};
902
- Object.defineProperties(touchStart, {
903
- touches: {value: [point]},
904
- targetTouches: {value: [point]},
905
- changedTouches: {value: [point]},
906
- });
907
- scroller.dispatchEvent(touchStart);
908
- scroller.scrollLeft = 5 * SCROLLPORT_WIDTH;
909
- fireEvent.scroll(scroller);
910
- // The report is made from inside a rAF callback, so the state update
911
- // lands outside the act() that fireEvent wraps.
912
- await waitFor(() => expect(header()).toHaveTextContent('June 2026'));
913
- });
914
- });
915
-
916
- /**
917
- * An arrow with nowhere to go is hidden, not greyed. A disabled control
918
- * still says "this is a thing you could do", and at the edge of a range it
919
- * is not — there is no state the user can reach where it becomes
920
- * available, so a permanently greyed chevron just reads as broken.
921
- *
922
- * It keeps its box, though: `visibility: hidden` rather than unmounting,
923
- * so the remaining arrow does not slide sideways as an edge is reached.
924
- */
925
- it('hides an arrow at the end of the reachable range', () => {
926
- renderAndOpen(
927
- <Controlled initial="2026-03-10" min="2026-03-01" max="2026-03-31" />,
928
- );
929
- // Queried by attribute, not by role: `visibility: hidden` is exactly what
930
- // strips an element of its accessible name, so a role query cannot see
931
- // these — which is the point of the assertion below.
932
- const arrow = (name: string) =>
933
- document.querySelector<HTMLElement>(
934
- `dialog[open] button[aria-label="${name}"]`,
935
- );
936
- for (const name of ['Previous month', 'Next month']) {
937
- // Still mounted, so the header cannot reflow...
938
- expect(arrow(name)).toBeInTheDocument();
939
- expect(arrow(name)).toBeDisabled();
940
- // ...but gone from the accessibility tree, and so unreachable.
941
- expect(screen.queryByRole('button', {name})).toBeNull();
942
- }
943
- });
944
-
945
- it('shows both arrows when there is somewhere to go in each direction', () => {
946
- renderAndOpen(
947
- <Controlled initial="2026-03-10" min="2026-01-01" max="2026-12-31" />,
948
- );
949
- expect(
950
- screen.getByRole('button', {name: 'Previous month'}),
951
- ).toBeInTheDocument();
952
- expect(
953
- screen.getByRole('button', {name: 'Next month'}),
954
- ).toBeInTheDocument();
955
- });
956
-
957
- it('does not change the selection when paging', () => {
958
- const onChange = vi.fn();
959
- renderAndOpen(<Controlled initial="2026-03-21" onChange={onChange} />);
960
- fireEvent.click(screen.getByRole('button', {name: 'Next month'}));
961
- // Navigating is not selecting — the mistake the old Today button made.
962
- expect(onChange).not.toHaveBeenCalled();
963
- expect(field()).toHaveValue('March 21, 2026');
964
- });
965
-
966
- it('disables days outside min/max and refuses to commit them', () => {
967
- const onChange = vi.fn();
968
- renderAndOpen(
969
- <Controlled
970
- initial="2026-03-10"
971
- min="2026-03-05"
972
- max="2026-03-20"
973
- onChange={onChange}
974
- />,
975
- );
976
- const outOfRange = within(pane('March 2026')).getByRole('button', {
977
- name: /March 25, 2026/,
978
- });
979
- expect(outOfRange).toHaveAttribute('aria-disabled', 'true');
980
- fireEvent.click(outOfRange);
981
- expect(onChange).not.toHaveBeenCalled();
982
- });
983
-
984
- it('honors custom date constraints', () => {
985
- renderAndOpen(
986
- <Controlled
987
- initial="2026-03-10"
988
- dateConstraints={[date => date.getDay() !== 0]}
989
- />,
990
- );
991
- // 2026-03-01 is a Sunday.
992
- expect(
993
- within(pane('March 2026')).getByRole('button', {name: /March 1, 2026/}),
994
- ).toHaveAttribute('aria-disabled', 'true');
995
- });
996
-
997
- /**
998
- * Spill days, the way the desktop calendar has them.
999
- *
1000
- * These were left out at first, on the theory that a horizontal scroller
1001
- * would show the same date twice — greyed at the foot of one pane and
1002
- * again at the head of the next. Measured, that cannot happen: both panes
1003
- * are exactly the scrollport wide and share one 7-column grid, so a given
1004
- * weekday column is only ever visible in ONE pane at a time, and a date
1005
- * always sits in its weekday's column. Swept across a full pane boundary
1006
- * in 10% steps — 42 dates on screen throughout, zero duplicated.
1007
- */
1008
- it('renders adjacent-month days, muted, like the desktop calendar', () => {
1009
- renderAndOpen();
1010
- const march = within(pane('March 2026'));
1011
- // Every cell in the 6x7 grid is now a real day.
1012
- expect(march.getAllByRole('gridcell')).toHaveLength(42);
1013
- expect(march.getAllByRole('button')).toHaveLength(42);
1014
- // March 2026 begins on a Sunday, so it spills only forwards.
1015
- expect(
1016
- march.getByRole('button', {name: /April 1, 2026/}),
1017
- ).toBeInTheDocument();
1018
- });
1019
-
1020
- it('spills backwards too, on a month that does not start the week', () => {
1021
- renderAndOpen(
1022
- <Controlled initial="2026-04-15" min="2026-01-01" max="2026-12-31" />,
1023
- );
1024
- const april = within(pane('April 2026'));
1025
- // April 2026 starts on a Wednesday: the first row opens with late March.
1026
- expect(
1027
- april.getByRole('button', {name: /March 29, 2026/}),
1028
- ).toBeInTheDocument();
1029
- expect(april.getAllByRole('button')).toHaveLength(42);
1030
- });
1031
-
1032
- /**
1033
- * A spilled day is shown, not offered.
1034
- *
1035
- * It was pickable at first, on the reasoning that a date you can see is a
1036
- * date you should be able to tap. The desktop calendar disagrees — it makes
1037
- * its own outside days unselectable — and on a pane that IS the month, so
1038
- * does the interaction: committing April 1 from March's pane would move the
1039
- * calendar out from under the thumb that just tapped it. The swipe and the
1040
- * arrows say "next month" without that ambiguity.
1041
- */
1042
- it('does not commit an adjacent-month day', () => {
1043
- const onChange = vi.fn();
1044
- renderAndOpen(<Controlled initial="2026-03-21" onChange={onChange} />);
1045
- const april1 = within(pane('March 2026')).getByRole('button', {
1046
- name: /April 1, 2026/,
1047
- });
1048
- expect(april1).toHaveAttribute('aria-disabled', 'true');
1049
- fireEvent.click(april1);
1050
- expect(onChange).not.toHaveBeenCalled();
1051
- });
1052
-
1053
- /**
1054
- * Being outside is enough on its own — a spill day inside the allowed range
1055
- * is still not a choice. Worth its own case because `isDateDisabled` says
1056
- * nothing about April 1 here, so only the outside test can be what disables
1057
- * it.
1058
- */
1059
- it('disables a spilled day the range would otherwise allow', () => {
1060
- renderAndOpen(
1061
- <Controlled initial="2026-03-21" min="2026-01-01" max="2026-12-31" />,
1062
- );
1063
- const march = within(pane('March 2026'));
1064
- // In range, and in its own pane it is perfectly pickable.
1065
- expect(
1066
- within(pane('April 2026')).getByRole('button', {name: /April 1, 2026/}),
1067
- ).not.toHaveAttribute('aria-disabled');
1068
- // Borrowed by March, it is not.
1069
- expect(march.getByRole('button', {name: /April 1, 2026/})).toHaveAttribute(
1070
- 'aria-disabled',
1071
- 'true',
1072
- );
1073
- });
1074
-
1075
- /**
1076
- * The selection and today's ring belong to the month that owns the date.
1077
- * Calendar guards both on `!isOutside`; without the same guard a date would
1078
- * wear its puck twice, once in its own pane and once in the neighbour that
1079
- * only borrows it.
1080
- */
1081
- it('leaves the puck and the today ring with the month that owns the day', () => {
1082
- renderAndOpen(
1083
- <Controlled initial="2026-04-01" min="2026-01-01" max="2026-12-31" />,
1084
- );
1085
- const spilled = within(pane('March 2026')).getByRole('button', {
1086
- name: /April 1, 2026/,
1087
- });
1088
- const owned = within(pane('April 2026')).getByRole('button', {
1089
- name: /April 1, 2026/,
1090
- });
1091
- // Same date, same label — and only one of them is dressed as selected.
1092
- expect(owned.className).not.toBe(spilled.className);
1093
- expect(
1094
- within(pane('April 2026')).getAllByRole('gridcell', {selected: true}),
1095
- ).toHaveLength(1);
1096
- expect(
1097
- within(pane('March 2026')).queryAllByRole('gridcell', {selected: true}),
1098
- ).toHaveLength(0);
1099
- });
1100
-
1101
- /**
1102
- * A date shown in two panes must not be two tab stops — the pane that owns
1103
- * it, and the neighbour that merely spills it. That holds because
1104
- * `tabbableISO` is resolved per pane and only names dates in that pane's
1105
- * own month, so it is worth pinning: the case below is the one that would
1106
- * break if it ever became global, since April 1 is both the selection and
1107
- * a spill day in March's pane.
1108
- */
1109
- it('gives a spilled date no tab stop in the pane that borrows it', () => {
1110
- renderAndOpen(
1111
- <Controlled initial="2026-04-01" min="2026-01-01" max="2026-12-31" />,
1112
- );
1113
- const tabbableIn = (label: string) =>
1114
- within(pane(label))
1115
- .getAllByRole('button')
1116
- .filter(b => b.getAttribute('tabindex') === '0')
1117
- .map(b => b.getAttribute('aria-label'));
1118
-
1119
- // April owns the date, so its stop is the date itself.
1120
- expect(tabbableIn('April 2026')).toHaveLength(1);
1121
- expect(tabbableIn('April 2026')[0]).toMatch(/April 1, 2026/);
1122
- // March shows the same date, but its stop falls back to a March date —
1123
- // every pane keeps exactly one, and never on a day it does not own.
1124
- expect(tabbableIn('March 2026')).toHaveLength(1);
1125
- expect(tabbableIn('March 2026')[0]).toMatch(/March/);
1126
- });
1127
-
1128
- const weekdayNames = () =>
1129
- [...weekdayRow().children].map(c => c.textContent?.trim());
1130
-
1131
- /**
1132
- * Three letters, where Calendar's own header uses two.
1133
- *
1134
- * The sheet is full width — ~51px a column against Calendar's popover — so
1135
- * there is room for the form people actually read, and a picker driven by
1136
- * thumb should not make anyone decode "Tu" against "Th".
1137
- *
1138
- * Exact equality, not `toHaveTextContent`: that matches substrings, so it
1139
- * passes against "Sun" while asserting "Su" and would not have noticed this
1140
- * change at all.
1141
- */
1142
- it('labels the columns with three-letter weekday names', () => {
1143
- renderAndOpen();
1144
- expect(weekdayNames()).toEqual([
1145
- 'Sun',
1146
- 'Mon',
1147
- 'Tue',
1148
- 'Wed',
1149
- 'Thu',
1150
- 'Fri',
1151
- 'Sat',
1152
- ]);
1153
- });
1154
-
1155
- it('rotates the weekday header with weekStartsOn', () => {
1156
- renderAndOpen(<Controlled initial="2026-03-21" weekStartsOn={1} />);
1157
- expect(weekdayNames()).toEqual([
1158
- 'Mon',
1159
- 'Tue',
1160
- 'Wed',
1161
- 'Thu',
1162
- 'Fri',
1163
- 'Sat',
1164
- 'Sun',
1165
- ]);
1166
- });
1167
-
1168
- it('accepts weekStartsOn as a day name, like Calendar and DateInput', () => {
1169
- renderAndOpen(<Controlled initial="2026-03-21" weekStartsOn="sat" />);
1170
- expect(weekdayNames()[0]).toBe('Sat');
1171
- // The columns rotate with the header, or the grid would be mislabelled.
1172
- expect(
1173
- within(pane('March 2026'))
1174
- .getAllByRole('button')[0]
1175
- .getAttribute('aria-label'),
1176
- ).toMatch(/February 28, 2026|March/);
1177
- });
1178
-
1179
- it('moves keyboard focus by date, across the month boundary', () => {
1180
- renderAndOpen(<Controlled initial="2026-03-31" />);
1181
- const last = within(pane('March 2026')).getByRole('button', {
1182
- name: /March 31, 2026/,
1183
- });
1184
- last.focus();
1185
- fireEvent.keyDown(last, {key: 'ArrowRight'});
1186
- expect(document.activeElement).toHaveAttribute('data-date', '2026-04-01');
1187
- // The real April 1, not its dimmed spill copy at the foot of the March
1188
- // pane (which is disabled and selects nothing).
1189
- expect(pane('April 2026')).toContainElement(
1190
- document.activeElement as HTMLElement,
1191
- );
1192
- expect(document.activeElement).not.toHaveAttribute('aria-disabled');
1193
- });
1194
-
1195
- it('follows the reading direction under RTL: ArrowLeft moves to the next day', () => {
1196
- renderAndOpen(
1197
- <InternationalizationProvider locale="en-US" dir="rtl">
1198
- <Controlled initial="2026-03-10" />
1199
- </InternationalizationProvider>,
1200
- );
1201
- const day = within(pane('March 2026')).getByRole('button', {
1202
- name: /March 10, 2026/,
1203
- });
1204
- day.focus();
1205
- fireEvent.keyDown(day, {key: 'ArrowLeft'});
1206
- expect(document.activeElement).toHaveAttribute('data-date', '2026-03-11');
1207
- fireEvent.keyDown(document.activeElement!, {key: 'ArrowRight'});
1208
- expect(document.activeElement).toHaveAttribute('data-date', '2026-03-10');
1209
- });
1210
-
1211
- it('moves a week at a time with the vertical arrows', () => {
1212
- renderAndOpen(<Controlled initial="2026-03-10" />);
1213
- const day = within(pane('March 2026')).getByRole('button', {
1214
- name: /March 10, 2026/,
1215
- });
1216
- day.focus();
1217
- fireEvent.keyDown(day, {key: 'ArrowDown'});
1218
- expect(document.activeElement).toHaveAttribute('data-date', '2026-03-17');
1219
- });
1220
- });
1221
-
1222
- // ---------------------------------------------------------------------------
1223
- // Resting between two months — the iOS snap failure
1224
- // ---------------------------------------------------------------------------
1225
-
1226
- /**
1227
- * `scroll-snap-type: mandatory` is supposed to make all of this unnecessary,
1228
- * and on a static list it does. This list is virtualized: seven panes exist
1229
- * out of twelve hundred, and THE PANES ARE THE SNAP AREAS — so every month
1230
- * the finger crosses mounts one and unmounts another, mid-fling.
1231
- *
1232
- * iOS scrolls off the main thread. It picks a landing place from the snap
1233
- * points it knows about at the time, and a React re-render that lands after
1234
- * that decision moves them; the scroller comes to rest where no snap point
1235
- * exists any more and nothing re-snaps it. Reported from a device as the
1236
- * calendar sitting between two months with the weekday header still square —
1237
- * which is exactly the shape of it: the grid is not skewed, the scrollport is
1238
- * parked a couple of columns into a pane, so the left of March and the right
1239
- * of April are on screen under one Sun-to-Sat header.
1240
- *
1241
- * Chrome never shows it, because it snaps again after the mutation. jsdom
1242
- * implements no snapping at all, which makes it a fine place to test the
1243
- * correction: the scroller can simply be PUT at a bad offset, exactly as iOS
1244
- * leaves it, and the settle has to fix it.
1245
- */
1246
- describe('DateInput — a rest position between two months', () => {
1247
- /** The row March 2026 occupies in a range that opens in January 2024. */
1248
- const MARCH_2026_ROW = 26;
1249
- const FIVE_YEARS = {min: '2024-01-01', max: '2028-12-31'} as const;
1250
-
1251
- /** A touchstart carrying the list a real one always has. */
1252
- const touchEvent = (type: string) => {
1253
- const event = new Event(type, {bubbles: true});
1254
- const point = {identifier: 1, clientX: 100, clientY: 100};
1255
- Object.defineProperties(event, {
1256
- touches: {value: type === 'touchend' ? [] : [point]},
1257
- targetTouches: {value: type === 'touchend' ? [] : [point]},
1258
- changedTouches: {value: [point]},
1259
- });
1260
- return event;
1261
- };
1262
-
1263
- /** Drag, release, and let the quiet period elapse. */
1264
- const swipeTo = async (scroller: HTMLElement, offset: number) => {
1265
- scroller.dispatchEvent(touchEvent('touchstart'));
1266
- scroller.scrollLeft = offset;
1267
- fireEvent.scroll(scroller);
1268
- scroller.dispatchEvent(touchEvent('touchend'));
1269
- };
1270
-
1271
- const openCalendar = () => {
1272
- render(<Controlled initial="2026-03-21" {...FIVE_YEARS} />);
1273
- fireEvent.click(screen.getByLabelText('Event date'));
1274
- const scroller = document.querySelector<HTMLElement>(
1275
- '[data-scroller="months"]',
1276
- )!;
1277
- const scrollTo = vi.mocked(Element.prototype.scrollTo);
1278
- scrollTo.mockClear();
1279
- return {scroller, scrollTo};
1280
- };
1281
-
1282
- it('puts the calendar back on a pane once the swipe is over', async () => {
1283
- await withLayout(async () => {
1284
- const {scroller, scrollTo} = openCalendar();
1285
- // Two columns in — what the device screenshot showed.
1286
- const stray = Math.round((SCROLLPORT_WIDTH * 2) / 7);
1287
- await swipeTo(scroller, MARCH_2026_ROW * SCROLLPORT_WIDTH + stray);
1288
-
1289
- await waitFor(() =>
1290
- expect(scrollTo).toHaveBeenCalledWith(
1291
- expect.objectContaining({left: MARCH_2026_ROW * SCROLLPORT_WIDTH}),
1292
- ),
1293
- );
1294
- });
1295
- });
1296
-
1297
- it('goes to the nearer pane, not back the way it came', async () => {
1298
- await withLayout(async () => {
1299
- const {scroller, scrollTo} = openCalendar();
1300
- // Three quarters of the way to April: April is the honest answer, and a
1301
- // correction that always rounded down would drag the user backwards.
1302
- await swipeTo(
1303
- scroller,
1304
- MARCH_2026_ROW * SCROLLPORT_WIDTH + SCROLLPORT_WIDTH * 0.75,
1305
- );
1306
-
1307
- await waitFor(() =>
1308
- expect(scrollTo).toHaveBeenCalledWith(
1309
- expect.objectContaining({
1310
- left: (MARCH_2026_ROW + 1) * SCROLLPORT_WIDTH,
1311
- }),
1312
- ),
1313
- );
1314
- });
1315
- });
1316
-
1317
- /**
1318
- * A scroller the browser snapped for itself must be left alone. Correcting
1319
- * it anyway would mean every swipe on Chrome — where snapping works — ended
1320
- * with a second, pointless scroll.
1321
- */
1322
- it('leaves a scroller that snapped properly alone', async () => {
1323
- await withLayout(async () => {
1324
- const {scroller, scrollTo} = openCalendar();
1325
- await swipeTo(scroller, (MARCH_2026_ROW + 2) * SCROLLPORT_WIDTH);
1326
-
1327
- // Long enough that the settle has certainly run.
1328
- await new Promise(resolve => setTimeout(resolve, SCROLL_QUIET_MS * 2));
1329
- expect(scrollTo).not.toHaveBeenCalled();
1330
- });
1331
- });
1332
-
1333
- /**
1334
- * Sub-pixel drift is the browser's own rounding on a fractional viewport,
1335
- * not a failed snap. Correcting it would fire a scroll after every gesture
1336
- * on any device whose width is not a whole number of pixels.
1337
- */
1338
- it('ignores sub-pixel drift', async () => {
1339
- await withLayout(async () => {
1340
- const {scroller, scrollTo} = openCalendar();
1341
- await swipeTo(scroller, MARCH_2026_ROW * SCROLLPORT_WIDTH + 0.4);
1342
-
1343
- await new Promise(resolve => setTimeout(resolve, SCROLL_QUIET_MS * 2));
1344
- expect(scrollTo).not.toHaveBeenCalled();
1345
- });
1346
- });
1347
-
1348
- /**
1349
- * The correction waits for the finger. Firing it mid-drag would fight the
1350
- * hand that is still moving the scroller — the same mistake that made the
1351
- * wheels climb a month at a time on iOS, and the reason `useScrollSettle`
1352
- * waits for a release rather than for quiet alone.
1353
- */
1354
- it('does not correct while the finger is still down', async () => {
1355
- await withLayout(async () => {
1356
- const {scroller, scrollTo} = openCalendar();
1357
- scroller.dispatchEvent(touchEvent('touchstart'));
1358
- scroller.scrollLeft = MARCH_2026_ROW * SCROLLPORT_WIDTH + 120;
1359
- fireEvent.scroll(scroller);
1360
-
1361
- await new Promise(resolve => setTimeout(resolve, SCROLL_QUIET_MS * 2));
1362
- expect(scrollTo).not.toHaveBeenCalled();
1363
-
1364
- // And on release it does the correction it was holding back.
1365
- scroller.dispatchEvent(touchEvent('touchend'));
1366
- await waitFor(() => expect(scrollTo).toHaveBeenCalled());
1367
- });
1368
- });
1369
-
1370
- /**
1371
- * The one that actually reverses a swipe, and the reason the correction
1372
- * re-checks stillness rather than trusting the quiet period.
1373
- *
1374
- * iOS runs its own snap animation for ~150-300ms after the finger lifts,
1375
- * and fires scroll events irregularly while it does — a gap longer than the
1376
- * quiet period is routine in the slow tail. The settle lands mid-animation,
1377
- * reads an offset still travelling toward April, rounds THAT to the nearest
1378
- * pane (still March, since the animation is not yet halfway), and drags the
1379
- * calendar back where it came from. Swipe forward, get pulled backward.
1380
- *
1381
- * Simulated by moving the scroller between the two samples, which is what
1382
- * an animation in flight looks like from here.
1383
- */
1384
- it('does not correct a scroller that is still travelling', async () => {
1385
- await withLayout(async () => {
1386
- const {scroller, scrollTo} = openCalendar();
1387
- // A quarter of the way to April, and still going.
1388
- let offset = MARCH_2026_ROW * SCROLLPORT_WIDTH + SCROLLPORT_WIDTH * 0.25;
1389
- Object.defineProperty(scroller, 'scrollLeft', {
1390
- configurable: true,
1391
- get: () => {
1392
- // Every read advances it, the way an in-flight animation does.
1393
- offset += 8;
1394
- return offset;
1395
- },
1396
- set: (value: number) => {
1397
- offset = value;
1398
- },
1399
- });
1400
-
1401
- await swipeTo(scroller, offset);
1402
- await new Promise(resolve => setTimeout(resolve, SCROLL_QUIET_MS * 3));
1403
- // Nothing. Correcting here would have sent it back to March, undoing a
1404
- // swipe the browser was already completing.
1405
- expect(scrollTo).not.toHaveBeenCalled();
1406
- });
1407
- });
1408
- });
1409
-
1410
- // ---------------------------------------------------------------------------
1411
- // Month / year wheels
1412
- // ---------------------------------------------------------------------------
1413
-
1414
- describe('DateInput — month/year wheels', () => {
1415
- /**
1416
- * The header title. Queried by attribute rather than by role and accessible
1417
- * name: every role query in here walks a tree of ~150 elements and computes
1418
- * a name for each, which dominates the runtime of these tests.
1419
- */
1420
- const title = () =>
1421
- document.querySelector<HTMLElement>('[data-title="month-year"]')!;
1422
-
1423
- const openWheels = () => fireEvent.click(title());
1424
-
1425
- /** The swap panel holding the calendar, or the one holding the wheels. */
1426
- const panel = (which: 'calendar' | 'wheels') =>
1427
- document.querySelector(`[data-panel="${which}"]`)!;
1428
-
1429
- const ONE_YEAR = {min: '2026-01-01', max: '2026-12-31'} as const;
1430
- const FIVE_YEARS = {min: '2024-01-01', max: '2028-12-31'} as const;
1431
-
1432
- it('the header title opens them, and says so', () => {
1433
- renderAndOpen();
1434
- expect(title()).toHaveAttribute('aria-expanded', 'false');
1435
- expect(panel('wheels')).toHaveAttribute('inert');
1436
- expect(panel('calendar')).not.toHaveAttribute('inert');
1437
- openWheels();
1438
- expect(title()).toHaveAttribute('aria-expanded', 'true');
1439
- expect(panel('wheels')).not.toHaveAttribute('inert');
1440
- expect(panel('calendar')).toHaveAttribute('inert');
1441
- expect(screen.getByRole('listbox', {name: 'Month'})).toBeInTheDocument();
1442
- expect(screen.getByRole('listbox', {name: 'Year'})).toBeInTheDocument();
1443
- });
1444
-
1445
- /**
1446
- * The arrows step the calendar, and the calendar is not on screen. They
1447
- * keep their layout box rather than unmounting: they are the tallest thing
1448
- * in the header on a coarse pointer (44px against the title's 36), so
1449
- * dropping them would shorten it and shift the sheet mid-cross-fade.
1450
- */
1451
- it('hides the month arrows while the wheels are up', () => {
1452
- renderAndOpen();
1453
- const arrows = document.querySelector<HTMLElement>(
1454
- '[data-arrows="months"]',
1455
- )!;
1456
- expect(arrows).not.toHaveAttribute('inert');
1457
-
1458
- openWheels();
1459
- expect(arrows).toHaveAttribute('inert');
1460
- // Still in the layout, so the header cannot change height.
1461
- expect(arrows).toBeInTheDocument();
1462
-
1463
- fireEvent.click(title());
1464
- expect(arrows).not.toHaveAttribute('inert');
1465
- });
1466
-
1467
- it('offers twelve months, with the current one selected', () => {
1468
- renderAndOpen();
1469
- openWheels();
1470
- const options = within(
1471
- screen.getByRole('listbox', {name: 'Month'}),
1472
- ).getAllByRole('option');
1473
- expect(options).toHaveLength(12);
1474
- expect(options[2]).toHaveTextContent('March');
1475
- expect(options[2]).toHaveAttribute('aria-selected', 'true');
1476
- });
1477
-
1478
- it('tapping a wheel row moves the calendar to that month', () => {
1479
- renderAndOpen(<Controlled initial="2026-03-21" {...ONE_YEAR} />);
1480
- openWheels();
1481
- fireEvent.click(
1482
- within(screen.getByRole('listbox', {name: 'Month'})).getByText(
1483
- 'September',
1484
- ),
1485
- );
1486
- expect(title()).toHaveTextContent('September 2026');
1487
- });
1488
-
1489
- /**
1490
- * A wheel commit steers the hidden calendar, and the calendar reports the
1491
- * month it lands on. Taking that report back while the wheels are open
1492
- * closes a cycle: commit -> echo -> the echo moves the wheel's selected row
1493
- * -> the wheel is repositioned -> that scroll reads as another commit.
1494
- *
1495
- * Whether it converges comes down to how precisely a browser says
1496
- * "scrolling stopped". Chrome has `scrollend` and settles at once; iOS
1497
- * below Safari 26 has none, and its momentum runs on after the finger
1498
- * lifts, so each lap committed the next month along and the month climbed
1499
- * on its own — reported from a device, invisible in Chrome.
1500
- *
1501
- * Driven here through the calendar's real scroll listener, which needs a
1502
- * measured scrollport (`withLayout`) and a `scrollLeft` far enough to land
1503
- * on another pane, then a frame for the rAF throttle. No timing assumptions:
1504
- * the echo either reaches the month or it does not.
1505
- */
1506
- it('ignores the calendar echo while the wheels are steering it', async () => {
1507
- await withLayout(async () => {
1508
- render(<Controlled initial="2026-03-21" {...FIVE_YEARS} />);
1509
- fireEvent.click(field());
1510
- openWheels();
1511
- fireEvent.click(
1512
- within(screen.getByRole('listbox', {name: 'Month'})).getByText(
1513
- 'January',
1514
- ),
1515
- );
1516
- expect(title()).toHaveTextContent('January 2026');
1517
-
1518
- // The calendar, scrolling to January behind the wheels, reports each
1519
- // month it passes. None of it may move the month the wheels just set.
1520
- const scroller = document.querySelector<HTMLElement>(
1521
- '[data-scroller="months"]',
1522
- )!;
1523
- for (const row of [5, 6, 7, 8]) {
1524
- scroller.scrollLeft = row * SCROLLPORT_WIDTH;
1525
- fireEvent.scroll(scroller);
1526
- await frame();
1527
- }
1528
- expect(title()).toHaveTextContent('January 2026');
1529
- });
1530
- // The other direction — the calendar reporting its month when it IS the
1531
- // surface — is what every test in the calendar-surface block above
1532
- // depends on, so it is covered rather than restated here.
1533
- });
1534
-
1535
- /**
1536
- * The reveal case, which is the one that was reported from a device.
1537
- *
1538
- * A wheel commit steers the calendar while it is hidden behind the wheels,
1539
- * and `visibility: hidden` keeps the layout box but does not guarantee the
1540
- * scroll position survives: iOS re-snaps the scroller when it becomes
1541
- * visible again, and not necessarily onto the pane it was put on. That
1542
- * fires a scroll exactly as the wheels close and reports start being
1543
- * trusted again — so the month drifted on the way back to the dates.
1544
- *
1545
- * Simulated here by moving the hidden scroller somewhere it was never sent,
1546
- * which is what the re-snap amounts to.
1547
- */
1548
- it('holds the month when the hidden calendar is re-snapped on reveal', async () => {
1549
- await withLayout(async () => {
1550
- render(<Controlled initial="2026-03-21" {...FIVE_YEARS} />);
1551
- fireEvent.click(field());
1552
- openWheels();
1553
- fireEvent.click(
1554
- within(screen.getByRole('listbox', {name: 'Month'})).getByText(
1555
- 'January',
1556
- ),
1557
- );
1558
- expect(title()).toHaveTextContent('January 2026');
1559
-
1560
- // iOS moves the hidden scroller off the pane it was steered to.
1561
- const scroller = document.querySelector<HTMLElement>(
1562
- '[data-scroller="months"]',
1563
- )!;
1564
- scroller.scrollLeft += 4 * SCROLLPORT_WIDTH;
1565
-
1566
- // Back to the dates. Two things have to hold: the stray position must
1567
- // not become the month, and the calendar must be put back on the pane
1568
- // the month names — or the header would say January over a different
1569
- // month's grid.
1570
- const scrollTo = vi.mocked(Element.prototype.scrollTo);
1571
- scrollTo.mockClear();
1572
- fireEvent.click(title());
1573
- fireEvent.scroll(scroller);
1574
- await frame();
1575
- await frame();
1576
- expect(title()).toHaveTextContent('January 2026');
1577
-
1578
- // January 2026 is row 24 of a range that starts in January 2024.
1579
- expect(scrollTo).toHaveBeenCalledWith(
1580
- expect.objectContaining({left: 24 * SCROLLPORT_WIDTH}),
1581
- );
1582
- });
1583
- });
1584
-
1585
- /**
1586
- * The wheels are a detour to reach a far month, not a mode. Reopening into
1587
- * them would answer a question the user has not asked yet, and hide the
1588
- * dates they came back for behind another tap.
1589
- */
1590
- it('always reopens on the calendar, whatever was showing last time', () => {
1591
- renderAndOpen();
1592
- openWheels();
1593
- expect(title()).toHaveAttribute('aria-expanded', 'true');
1594
-
1595
- // Dismissed from the wheels, where Done is deliberately not offered —
1596
- // the handle, the scrim and Escape are the ways out.
1597
- fireEvent.keyDown(document.querySelector('dialog[open]')!, {key: 'Escape'});
1598
- expect(field()).toHaveAttribute('aria-expanded', 'false');
1599
-
1600
- fireEvent.click(field());
1601
- expect(title()).toHaveAttribute('aria-expanded', 'false');
1602
- expect(panel('calendar')).not.toHaveAttribute('inert');
1603
- expect(panel('wheels')).toHaveAttribute('inert');
1604
- });
1605
-
1606
- it('the year wheel keeps the month', () => {
1607
- renderAndOpen(<Controlled initial="2026-03-21" {...FIVE_YEARS} />);
1608
- openWheels();
1609
- fireEvent.click(
1610
- within(screen.getByRole('listbox', {name: 'Year'})).getByText('2025'),
1611
- );
1612
- expect(title()).toHaveTextContent('March 2025');
1613
- });
1614
-
1615
- it('is a single tab stop driven by the arrow keys', () => {
1616
- renderAndOpen();
1617
- openWheels();
1618
- const months = screen.getByRole('listbox', {name: 'Month'});
1619
- expect(months).toHaveAttribute('tabindex', '0');
1620
- fireEvent.keyDown(months, {key: 'ArrowDown'});
1621
- expect(title()).toHaveTextContent('April 2026');
1622
- fireEvent.keyDown(months, {key: 'ArrowUp'});
1623
- expect(title()).toHaveTextContent('March 2026');
1624
- });
1625
-
1626
- it('will not commit a row outside min/max', () => {
1627
- renderAndOpen(<Controlled initial="2026-03-10" />);
1628
- openWheels();
1629
- const december = within(screen.getByRole('listbox', {name: 'Month'}))
1630
- .getByText('December')
1631
- .closest('[role="option"]')!;
1632
- expect(december).toHaveAttribute('aria-disabled', 'true');
1633
- fireEvent.click(december);
1634
- expect(title()).toHaveTextContent('March 2026');
1635
- });
1636
-
1637
- it('bounds the year wheel to the reachable range', () => {
1638
- renderAndOpen(
1639
- <Controlled initial="2026-03-10" min="2025-01-01" max="2027-12-31" />,
1640
- );
1641
- openWheels();
1642
- expect(
1643
- within(screen.getByRole('listbox', {name: 'Year'}))
1644
- .getAllByRole('option')
1645
- .map(o => o.textContent),
1646
- ).toEqual(['2025', '2026', '2027']);
1647
- });
1648
-
1649
- it('the title is what closes them again', () => {
1650
- renderAndOpen();
1651
- openWheels();
1652
- expect(title()).toHaveAttribute('aria-expanded', 'true');
1653
- fireEvent.click(title());
1654
- expect(title()).toHaveAttribute('aria-expanded', 'false');
1655
- expect(panel('wheels')).toHaveAttribute('inert');
1656
- });
1657
-
1658
- it('Reset empties the field and brings the calendar home', () => {
1659
- const onChange = vi.fn();
1660
- // Today is 15 March 2026 in these tests; open on a month away from it.
1661
- renderAndOpen(
1662
- <Controlled
1663
- initial="2026-08-21"
1664
- onChange={onChange}
1665
- min="2026-01-01"
1666
- max="2026-12-31"
1667
- />,
1668
- );
1669
- expect(title()).toHaveTextContent('August 2026');
1670
-
1671
- fireEvent.click(screen.getByRole('button', {name: 'Reset'}));
1672
- expect(onChange).toHaveBeenCalledWith(undefined);
1673
- expect(field()).toHaveValue('');
1674
- // Clearing the date and leaving the calendar on the month of the date you
1675
- // just cleared is a half-finished action.
1676
- expect(title()).toHaveTextContent('March 2026');
1677
- // And it does not dismiss — the sheet is still there to pick again.
1678
- expect(field()).toHaveAttribute('aria-expanded', 'true');
1679
- });
1680
-
1681
- /**
1682
- * "If possible" is the whole subtlety. A range can exclude the current
1683
- * month entirely — a booking window that opens next quarter — and there is
1684
- * then no honest month to go to. Clamping would land on the nearest edge
1685
- * and present a different month as though it were today's, so the move is
1686
- * skipped and the calendar stays put. The value clears either way.
1687
- */
1688
- it('clears without moving when the current month is out of range', () => {
1689
- const onChange = vi.fn();
1690
- renderAndOpen(
1691
- <Controlled
1692
- initial="2027-05-10"
1693
- onChange={onChange}
1694
- min="2027-01-01"
1695
- max="2027-12-31"
1696
- />,
1697
- );
1698
- expect(title()).toHaveTextContent('May 2027');
1699
-
1700
- fireEvent.click(screen.getByRole('button', {name: 'Reset'}));
1701
- expect(onChange).toHaveBeenCalledWith(undefined);
1702
- expect(field()).toHaveValue('');
1703
- expect(title()).toHaveTextContent('May 2027');
1704
- });
1705
-
1706
- it('offers Reset only on the calendar, in the header corner', () => {
1707
- renderAndOpen();
1708
- const reset = screen.getByRole('button', {name: 'Reset'});
1709
- // The trailing-most thing in the header, past the arrows — not the
1710
- // footer, which is Save's alone.
1711
- const header = reset.closest('[data-action="reset"]')!.parentElement!;
1712
- expect(header.querySelector('[data-title="month-year"]')).not.toBeNull();
1713
- expect(header.lastElementChild).toHaveAttribute('data-action', 'reset');
1714
-
1715
- openWheels();
1716
- // The wheels choose a month; there is no date there to clear.
1717
- expect(screen.queryByRole('button', {name: 'Reset'})).toBeNull();
1718
- // Hidden, not unmounted, so the header cannot change height mid-swap.
1719
- expect(
1720
- document.querySelector('dialog[open] [data-action="reset"]'),
1721
- ).toHaveAttribute('inert');
1722
- });
1723
-
1724
- it('Save closes the whole picker; Done only leaves the wheels', () => {
1725
- // Two finishes, deliberately different: Save ends the task, Done ends a
1726
- // step. They never appear together — each belongs to the surface it is
1727
- // shown on — so neither has to carry two meanings by position.
1728
- renderAndOpen();
1729
- openWheels();
1730
- fireEvent.click(screen.getByRole('button', {name: 'Done'}));
1731
- // Back on the calendar, still open.
1732
- expect(field()).toHaveAttribute('aria-expanded', 'true');
1733
- expect(title()).toHaveAttribute('aria-expanded', 'false');
1734
-
1735
- fireEvent.click(screen.getByRole('button', {name: 'Save'}));
1736
- expect(field()).toHaveAttribute('aria-expanded', 'false');
1737
- });
1738
-
1739
- /**
1740
- * The two actions share one grid cell and take turns, so the footer is one
1741
- * button tall whichever is showing and the sheet never changes height
1742
- * mid-swap. `inert` is what keeps the hidden one out of the accessibility
1743
- * tree, rather than merely out of sight.
1744
- */
1745
- /**
1746
- * `inert` disables everything INSIDE it, so an inert ancestor is enough to
1747
- * kill a button that looks perfectly fine on its own.
1748
- *
1749
- * This is not hypothetical. The footer kept an `inert` from an earlier
1750
- * version where it was hidden wholesale on the wheels; once the wheels grew
1751
- * their own Done button inside that same footer, the button rendered,
1752
- * looked right, passed every attribute assertion — and did nothing when
1753
- * tapped.
1754
- *
1755
- * Nothing above caught it: `inert` has no behavioural effect in jsdom, so
1756
- * role queries still found the button, and the cell's own attribute was
1757
- * correct. The only honest check is to walk the ancestors, which is what
1758
- * this does.
1759
- */
1760
- it('leaves no inert ancestor over whichever action is showing', () => {
1761
- const inertAncestorsOf = (label: string) => {
1762
- const el = [...document.querySelectorAll('dialog[open] button')].find(
1763
- b => b.textContent?.trim() === label,
1764
- )!;
1765
- const blocking: string[] = [];
1766
- // Start above the button's own cell, which is legitimately inert for
1767
- // the action that is currently hidden.
1768
- let node = el.parentElement?.parentElement ?? null;
1769
- while (node != null && node.tagName !== 'BODY') {
1770
- if (node.hasAttribute('inert')) {
1771
- blocking.push(node.tagName.toLowerCase());
1772
- }
1773
- node = node.parentElement;
1774
- }
1775
- return blocking;
1776
- };
1777
-
1778
- renderAndOpen();
1779
- expect(inertAncestorsOf('Save')).toEqual([]);
1780
- expect(inertAncestorsOf('Reset')).toEqual([]);
1781
-
1782
- openWheels();
1783
- expect(inertAncestorsOf('Done')).toEqual([]);
1784
- });
1785
-
1786
- it('shows exactly one footer action, and only the visible one is reachable', () => {
1787
- renderAndOpen();
1788
- // Queried off the DOM rather than by role: every role-with-name query
1789
- // walks this tree computing accessible names, and there are ~150
1790
- // elements in it. Same reason the title helper above does it this way.
1791
- const button = (label: string) =>
1792
- [...document.querySelectorAll('dialog[open] button')].find(
1793
- el => el.textContent?.trim() === label,
1794
- );
1795
- // Which ANCESTOR carries `inert`, not which parent — the wheels' action
1796
- // sits inside a fading wrapper, and asserting on `parentElement` would
1797
- // pass or fail on that nesting rather than on reachability.
1798
- const isBlocked = (label: string) =>
1799
- button(label)?.closest('[inert]') != null;
1800
-
1801
- expect(isBlocked('Save')).toBe(false);
1802
- expect(isBlocked('Done')).toBe(true);
1803
- expect(screen.queryByRole('button', {name: 'Done'})).toBeNull();
1804
-
1805
- openWheels();
1806
- expect(isBlocked('Save')).toBe(true);
1807
- expect(isBlocked('Done')).toBe(false);
1808
- expect(screen.queryByRole('button', {name: 'Save'})).toBeNull();
1809
-
1810
- // Both stay mounted throughout, which is what keeps the row's height
1811
- // fixed across the swap.
1812
- expect(button('Save')).toBeInTheDocument();
1813
- expect(button('Done')).toBeInTheDocument();
1814
- });
1815
-
1816
- it('the year wheel keeps the month', () => {
1817
- renderAndOpen(<Controlled initial="2026-03-21" {...FIVE_YEARS} />);
1818
- openWheels();
1819
- fireEvent.click(
1820
- within(screen.getByRole('listbox', {name: 'Year'})).getByText('2025'),
1821
- );
1822
- expect(title()).toHaveTextContent('March 2025');
1823
- });
1824
-
1825
- it('is a single tab stop driven by the arrow keys', () => {
1826
- renderAndOpen();
1827
- openWheels();
1828
- const months = screen.getByRole('listbox', {name: 'Month'});
1829
- expect(months).toHaveAttribute('tabindex', '0');
1830
- fireEvent.keyDown(months, {key: 'ArrowDown'});
1831
- expect(title()).toHaveTextContent('April 2026');
1832
- fireEvent.keyDown(months, {key: 'ArrowUp'});
1833
- expect(title()).toHaveTextContent('March 2026');
1834
- });
1835
-
1836
- it('will not commit a row outside min/max', () => {
1837
- renderAndOpen(<Controlled initial="2026-03-10" />);
1838
- openWheels();
1839
- const december = within(screen.getByRole('listbox', {name: 'Month'}))
1840
- .getByText('December')
1841
- .closest('[role="option"]')!;
1842
- expect(december).toHaveAttribute('aria-disabled', 'true');
1843
- fireEvent.click(december);
1844
- expect(title()).toHaveTextContent('March 2026');
1845
- });
1846
-
1847
- it('bounds the year wheel to the reachable range', () => {
1848
- renderAndOpen(
1849
- <Controlled initial="2026-03-10" min="2025-01-01" max="2027-12-31" />,
1850
- );
1851
- openWheels();
1852
- expect(
1853
- within(screen.getByRole('listbox', {name: 'Year'}))
1854
- .getAllByRole('option')
1855
- .map(o => o.textContent),
1856
- ).toEqual(['2025', '2026', '2027']);
1857
- });
1858
-
1859
- it('the title is what closes them again', () => {
1860
- renderAndOpen();
1861
- openWheels();
1862
- expect(title()).toHaveAttribute('aria-expanded', 'true');
1863
- fireEvent.click(title());
1864
- expect(title()).toHaveAttribute('aria-expanded', 'false');
1865
- expect(panel('wheels')).toHaveAttribute('inert');
1866
- });
1867
- });
1868
-
1869
- // ---------------------------------------------------------------------------
1870
- // Gesture ownership — the nested scrollers vs. the sheet's swipe-to-dismiss
1871
- // ---------------------------------------------------------------------------
1872
-
1873
- describe('DateInput — nested scrollers keep their own touch gesture', () => {
1874
- /**
1875
- * Stand-in for `BottomSheet`'s swipe-to-dismiss listener: a NATIVE listener
1876
- * on an ancestor, in the bubble phase, which is exactly how the sheet
1877
- * attaches its own (`addEventListener('touchstart', …, {passive: true})` on
1878
- * its scrolling body). If an event reaches this, the sheet would have read
1879
- * it as a drag.
1880
- */
1881
- function watchAncestor(): {seen: string[]; stop: () => void} {
1882
- const seen: string[] = [];
1883
- const listener = (event: Event) => seen.push(event.type);
1884
- for (const type of ['touchstart', 'touchmove', 'touchend']) {
1885
- document.body.addEventListener(type, listener);
1886
- }
1887
- return {
1888
- seen,
1889
- stop: () => {
1890
- for (const type of ['touchstart', 'touchmove', 'touchend']) {
1891
- document.body.removeEventListener(type, listener);
1892
- }
1893
- },
1894
- };
1895
- }
1896
-
1897
- /**
1898
- * A touch event realistic enough for a real listener to read.
1899
- *
1900
- * jsdom has no constructible `TouchEvent`, and a bare `Event` carries no
1901
- * `changedTouches` — which crashes any handler that reads one, including
1902
- * BottomSheet's (`event.changedTouches[0]`). That crash is an artifact of
1903
- * the fake event, not a bug: a browser's touchstart always has the list.
1904
- * The stand-in below carries it, so an event that DOES reach the sheet
1905
- * exercises the sheet rather than blowing up inside it.
1906
- */
1907
- const touch = (
1908
- el: Element,
1909
- type: string,
1910
- at: {x: number; y: number} = {x: 100, y: 200},
1911
- ) => {
1912
- const event = new Event(type, {
1913
- bubbles: true,
1914
- cancelable: type !== 'touchend',
1915
- });
1916
- const point = {identifier: 1, clientX: at.x, clientY: at.y, target: el};
1917
- Object.defineProperties(event, {
1918
- changedTouches: {value: [point]},
1919
- touches: {value: type === 'touchend' ? [] : [point]},
1920
- targetTouches: {value: type === 'touchend' ? [] : [point]},
1921
- });
1922
- return el.dispatchEvent(event);
1923
- };
1924
-
1925
- /**
1926
- * A whole gesture: down at the origin, drag by (dx, dy), lift. Returns the
1927
- * scroller's stubbed `scrollBy`, which is how the paging fallback shows up
1928
- * (jsdom implements neither scrolling nor `scrollBy`).
1929
- */
1930
- const swipe = (
1931
- el: Element,
1932
- dx: number,
1933
- dy: number,
1934
- {scrollsBy = 0}: {scrollsBy?: number} = {},
1935
- ) => {
1936
- // jsdom has no layout, so `scrollLeft` never moves on its own. Shadow it
1937
- // on this instance for the gesture: a native pan is the browser moving
1938
- // the scroller mid-drag, and watching for exactly that is how the hook
1939
- // knows whether its claim was honoured. Instance-only and deleted after,
1940
- // per the prototype-getter cost noted at the top of this file.
1941
- let offset = 0;
1942
- const scrollBy = vi.fn();
1943
- Object.defineProperties(el, {
1944
- scrollLeft: {
1945
- configurable: true,
1946
- get: () => offset,
1947
- set: (value: number) => {
1948
- offset = value;
1949
- },
1950
- },
1951
- scrollBy: {configurable: true, value: scrollBy},
1952
- });
1953
- const origin = {x: 150, y: 200};
1954
- touch(el, 'touchstart', origin);
1955
- for (const step of [0.5, 1]) {
1956
- if (step === 0.5) {
1957
- offset += scrollsBy;
1958
- }
1959
- touch(el, 'touchmove', {
1960
- x: origin.x + dx * step,
1961
- y: origin.y + dy * step,
1962
- });
1963
- }
1964
- touch(el, 'touchend');
1965
- // @ts-expect-error - removing the shadows restores the prototype's
1966
- delete el.scrollLeft;
1967
- // @ts-expect-error - same
1968
- delete el.scrollBy;
1969
- return scrollBy;
1970
- };
1971
-
1972
- it('lets a touch on the calendar reach the sheet, now that it pages sideways', () => {
1973
- renderAndOpen();
1974
- const scroller = document.querySelector('[data-scroller="months"]')!;
1975
- const ancestor = watchAncestor();
1976
- touch(scroller, 'touchstart');
1977
- touch(scroller, 'touchmove');
1978
- // The calendar used to claim the gesture, because it scrolled vertically
1979
- // and the sheet read every downward drag as a dismiss. Paging sideways
1980
- // removes the conflict: horizontal pans stay here and vertical ones go to
1981
- // the sheet, so a downward drag can go back to meaning swipe-to-dismiss.
1982
- // A move with no direction yet (the same point twice) is nobody's.
1983
- expect(ancestor.seen).toEqual(['touchstart', 'touchmove']);
1984
- ancestor.stop();
1985
- });
1986
-
1987
- it('claims a horizontal drag on the calendar', () => {
1988
- renderAndOpen();
1989
- const scroller = document.querySelector('[data-scroller="months"]')!;
1990
- const ancestor = watchAncestor();
1991
- swipe(scroller, -80, 0);
1992
- // touchstart still propagates — 'inline' cannot know the direction yet —
1993
- // but every move after the axis locks is ours.
1994
- expect(ancestor.seen).not.toContain('touchmove');
1995
- ancestor.stop();
1996
- });
1997
-
1998
- it('leaves a downward drag on the calendar to the sheet', () => {
1999
- renderAndOpen();
2000
- const scroller = document.querySelector('[data-scroller="months"]')!;
2001
- const ancestor = watchAncestor();
2002
- swipe(scroller, 0, 80);
2003
- expect(ancestor.seen).toContain('touchmove');
2004
- ancestor.stop();
2005
- });
2006
-
2007
- it('keeps a diagonal drag, because a thumb arcs as it swipes', () => {
2008
- renderAndOpen();
2009
- const scroller = document.querySelector('[data-scroller="months"]')!;
2010
- const ancestor = watchAncestor();
2011
- // ~50° off horizontal: past the browser's own pan-x cone, still ours.
2012
- swipe(scroller, -60, 72);
2013
- expect(ancestor.seen).not.toContain('touchmove');
2014
- ancestor.stop();
2015
- });
2016
-
2017
- /**
2018
- * The band between our claim and the browser's `pan-x` cone. The sheet has
2019
- * been told to keep off, and the compositor refuses to pan, so without the
2020
- * fallback these gestures would do nothing at all — measured as a dead zone
2021
- * from 45° to 60° on an iPhone 15 profile.
2022
- */
2023
- it('pages a month itself when the browser refuses to pan a claimed swipe', () => {
2024
- renderAndOpen();
2025
- const scroller = document.querySelector('[data-scroller="months"]')!;
2026
-
2027
- const forward = swipe(scroller, -60, 72);
2028
- expect(forward).toHaveBeenCalledTimes(1);
2029
- expect(forward.mock.calls[0][0]).toMatchObject({behavior: 'smooth'});
2030
- // Swiping left advances: the offset moves towards the end of the line.
2031
- expect(forward.mock.calls[0][0].left).toBeGreaterThan(0);
2032
-
2033
- const back = swipe(scroller, 60, 72);
2034
- expect(back.mock.calls[0][0].left).toBeLessThan(0);
2035
- });
2036
-
2037
- it('stays out of the way when the browser did pan', () => {
2038
- renderAndOpen();
2039
- const scroller = document.querySelector('[data-scroller="months"]')!;
2040
- // Native momentum and snapping own this one; a second nudge would fight
2041
- // them. `scrollsBy` stands in for the compositor moving the scroller.
2042
- expect(swipe(scroller, -120, 0, {scrollsBy: 40})).not.toHaveBeenCalled();
2043
- });
2044
-
2045
- it('ignores a claimed gesture too short to be a swipe', () => {
2046
- renderAndOpen();
2047
- const scroller = document.querySelector('[data-scroller="months"]')!;
2048
- expect(swipe(scroller, -SWIPE_DISTANCE + 4, 0)).not.toHaveBeenCalled();
2049
- });
2050
-
2051
- it('never pages from a drag it gave to the sheet', () => {
2052
- renderAndOpen();
2053
- const scroller = document.querySelector('[data-scroller="months"]')!;
2054
- expect(swipe(scroller, -40, 200)).not.toHaveBeenCalled();
2055
- });
2056
-
2057
- it('stops a touch on a wheel from reaching the sheet', () => {
2058
- renderAndOpen();
2059
- fireEvent.click(
2060
- document.querySelector<HTMLElement>('[data-title="month-year"]')!,
2061
- );
2062
- const wheel = screen.getByRole('listbox', {name: 'Month'});
2063
- const ancestor = watchAncestor();
2064
- touch(wheel, 'touchstart');
2065
- touch(wheel, 'touchmove');
2066
- expect(ancestor.seen).not.toContain('touchstart');
2067
- expect(ancestor.seen).not.toContain('touchmove');
2068
- ancestor.stop();
2069
- });
2070
-
2071
- it('lets touchend through, so the sheet can reset its own bookkeeping', () => {
2072
- renderAndOpen();
2073
- const scroller = document.querySelector('[data-scroller="months"]')!;
2074
- const ancestor = watchAncestor();
2075
- touch(scroller, 'touchend');
2076
- expect(ancestor.seen).toContain('touchend');
2077
- ancestor.stop();
2078
- });
2079
-
2080
- it('leaves the rest of the picker to the sheet', () => {
2081
- renderAndOpen();
2082
- // The header is not a scroller: a drag there is the sheet's to interpret,
2083
- // and it is one of the two places a dismiss can still start from.
2084
- const title = document.querySelector<HTMLElement>(
2085
- '[data-title="month-year"]',
2086
- )!;
2087
- const ancestor = watchAncestor();
2088
- touch(title, 'touchstart');
2089
- touch(title, 'touchmove');
2090
- expect(ancestor.seen).toEqual(['touchstart', 'touchmove']);
2091
- ancestor.stop();
2092
- });
2093
-
2094
- it('does not swallow taps — stopPropagation must not reach click', () => {
2095
- const onChange = vi.fn();
2096
- renderAndOpen(<Controlled initial="2026-03-21" onChange={onChange} />);
2097
- fireEvent.click(
2098
- within(pane('March 2026')).getByRole('button', {name: /March 25, 2026/}),
2099
- );
2100
- expect(onChange).toHaveBeenCalledWith('2026-03-25');
2101
- });
2102
- });
2103
-
2104
- // ---------------------------------------------------------------------------
2105
- // Dragging a wheel with a mouse
2106
- // ---------------------------------------------------------------------------
2107
-
2108
- /**
2109
- * A wheel is a scroll container, so a finger pans it for free. A mouse gets
2110
- * nothing: browsers do not drag-scroll an overflow container, so pressing and
2111
- * pulling on the one control shaped like a thing you spin did nothing at all.
2112
- *
2113
- * It matters on desktop specifically because that is where this surface is
2114
- * reviewed, themed and screenshotted.
2115
- */
2116
- describe('DateInput — a mouse can drag a wheel', () => {
2117
- const title = () =>
2118
- document.querySelector<HTMLElement>('[data-title="month-year"]')!;
2119
-
2120
- /** jsdom has no layout: give the rows a height and the wheel a scrollTop. */
2121
- function withWheelLayout<T>(fn: () => T): T {
2122
- Object.defineProperty(HTMLElement.prototype, 'offsetHeight', {
2123
- configurable: true,
2124
- get(this: HTMLElement) {
2125
- return this.getAttribute('role') === 'option' ? 28 : 0;
2126
- },
2127
- });
2128
- try {
2129
- return fn();
2130
- } finally {
2131
- // @ts-expect-error - deleting the shadow restores Element's own getter
2132
- delete HTMLElement.prototype.offsetHeight;
2133
- }
2134
- }
2135
-
2136
- const wheel = () => screen.getByRole('listbox', {name: 'Month'});
2137
-
2138
- const pointer = (
2139
- type: string,
2140
- {y = 0, pointerType = 'mouse', button = 0, id = 1} = {},
2141
- ) => {
2142
- const event = new Event(type, {bubbles: true, cancelable: true});
2143
- Object.defineProperties(event, {
2144
- clientY: {value: y},
2145
- pointerId: {value: id},
2146
- pointerType: {value: pointerType},
2147
- button: {value: button},
2148
- });
2149
- return event;
2150
- };
2151
-
2152
- /** Stubs jsdom's missing capture API and records scrollTop as it moves. */
2153
- function trackable(el: HTMLElement) {
2154
- let top = 0;
2155
- Object.defineProperty(el, 'scrollTop', {
2156
- configurable: true,
2157
- get: () => top,
2158
- set: (v: number) => {
2159
- top = v;
2160
- },
2161
- });
2162
- el.setPointerCapture = () => {};
2163
- el.releasePointerCapture = () => {};
2164
- el.hasPointerCapture = () => true;
2165
- el.scrollTo = ((opts: ScrollToOptions) => {
2166
- top = opts.top ?? top;
2167
- }) as HTMLElement['scrollTo'];
2168
- return {
2169
- get scrollTop() {
2170
- return top;
2171
- },
2172
- };
2173
- }
2174
-
2175
- it('scrolls the wheel when a mouse drags it', () => {
2176
- renderAndOpen();
2177
- fireEvent.click(title());
2178
- withWheelLayout(() => {
2179
- const el = wheel();
2180
- const track = trackable(el);
2181
- el.dispatchEvent(pointer('pointerdown', {y: 200}));
2182
- el.dispatchEvent(pointer('pointermove', {y: 160}));
2183
- // Content follows the hand: pulling up scrolls further down the list.
2184
- expect(track.scrollTop).toBe(40);
2185
- el.dispatchEvent(pointer('pointerup', {y: 160}));
2186
- // And the release lands on a row boundary rather than between two.
2187
- expect(track.scrollTop % 28).toBe(0);
2188
- });
2189
- });
2190
-
2191
- it('ignores movement too small to be a drag, so a click is still a click', () => {
2192
- renderAndOpen();
2193
- fireEvent.click(title());
2194
- withWheelLayout(() => {
2195
- const el = wheel();
2196
- const track = trackable(el);
2197
- el.dispatchEvent(pointer('pointerdown', {y: 200}));
2198
- el.dispatchEvent(pointer('pointermove', {y: 200 - (DRAG_SLOP - 1)}));
2199
- expect(track.scrollTop).toBe(0);
2200
- });
2201
- });
2202
-
2203
- it('leaves touch and pen alone — they pan natively, and better', () => {
2204
- renderAndOpen();
2205
- fireEvent.click(title());
2206
- withWheelLayout(() => {
2207
- for (const pointerType of ['touch', 'pen']) {
2208
- const el = wheel();
2209
- const track = trackable(el);
2210
- el.dispatchEvent(pointer('pointerdown', {y: 200, pointerType}));
2211
- el.dispatchEvent(pointer('pointermove', {y: 120, pointerType}));
2212
- expect(track.scrollTop).toBe(0);
2213
- el.dispatchEvent(pointer('pointerup', {y: 120, pointerType}));
2214
- }
2215
- });
2216
- });
2217
-
2218
- it('ignores a secondary button, which belongs to the context menu', () => {
2219
- renderAndOpen();
2220
- fireEvent.click(title());
2221
- withWheelLayout(() => {
2222
- const el = wheel();
2223
- const track = trackable(el);
2224
- el.dispatchEvent(pointer('pointerdown', {y: 200, button: 2}));
2225
- el.dispatchEvent(pointer('pointermove', {y: 120}));
2226
- expect(track.scrollTop).toBe(0);
2227
- });
2228
- });
2229
-
2230
- /**
2231
- * `scroll-snap-type: y mandatory` re-snaps after every scroll, programmatic
2232
- * ones included. Measured with it left on: 7 of 8 five-pixel drag steps were
2233
- * yanked back to a snap position, so the wheel stuck to a row and then
2234
- * jumped a whole one.
2235
- */
2236
- it('suspends snapping for the drag, and restores it after', () => {
2237
- renderAndOpen();
2238
- fireEvent.click(title());
2239
- withWheelLayout(() => {
2240
- const el = wheel();
2241
- trackable(el);
2242
- expect(el.style.scrollSnapType).toBe('');
2243
- el.dispatchEvent(pointer('pointerdown', {y: 200}));
2244
- el.dispatchEvent(pointer('pointermove', {y: 160}));
2245
- expect(el.style.scrollSnapType).toBe('none');
2246
- el.dispatchEvent(pointer('pointerup', {y: 160}));
2247
- el.dispatchEvent(new Event('scrollend'));
2248
- expect(el.style.scrollSnapType).toBe('');
2249
- });
2250
- });
2251
-
2252
- /**
2253
- * BottomSheet starts its own drag-to-dismiss from a `pointerdown` on its
2254
- * body and CAPTURES the pointer for it, which retargets every later pointer
2255
- * event — including the click. Measured before this: a click on a wheel row
2256
- * that wobbled more than a pixel selected nothing at all.
2257
- */
2258
- it('keeps the press away from the sheet, which would capture the pointer', () => {
2259
- renderAndOpen();
2260
- fireEvent.click(title());
2261
- withWheelLayout(() => {
2262
- const el = wheel();
2263
- trackable(el);
2264
- const seen: string[] = [];
2265
- const listener = (event: Event) => seen.push(event.type);
2266
- document.body.addEventListener('pointerdown', listener);
2267
- el.dispatchEvent(pointer('pointerdown', {y: 200}));
2268
- expect(seen).not.toContain('pointerdown');
2269
- document.body.removeEventListener('pointerdown', listener);
2270
- });
2271
- });
2272
- });
2273
-
2274
- // ---------------------------------------------------------------------------
2275
- // Pure month arithmetic
2276
- // ---------------------------------------------------------------------------
2277
-
2278
- describe('monthGeometry', () => {
2279
- it('round-trips a month through its index', () => {
2280
- for (const [year, month] of [
2281
- [2026, 1],
2282
- [2026, 12],
2283
- [1976, 7],
2284
- [2100, 2],
2285
- ] as const) {
2286
- expect(fromMonthIndex(toMonthIndex(year, month))).toEqual({year, month});
2287
- }
2288
- });
2289
-
2290
- it('orders months across a year boundary', () => {
2291
- expect(toMonthIndex(2027, 1) - toMonthIndex(2026, 12)).toBe(1);
2292
- });
2293
-
2294
- it('reads a month index off a PlainDate, ignoring the day', () => {
2295
- expect(monthIndexOf({year: 2026, month: 3, day: 1})).toBe(
2296
- monthIndexOf({year: 2026, month: 3, day: 31}),
2297
- );
2298
- });
2299
-
2300
- it('clamps to the reachable range', () => {
2301
- expect(clampIndex(5, 10, 20)).toBe(10);
2302
- expect(clampIndex(25, 10, 20)).toBe(20);
2303
- expect(clampIndex(15, 10, 20)).toBe(15);
2304
- });
2305
-
2306
- describe('rowAtScrollOffset', () => {
2307
- it('maps an exact offset to its row', () => {
2308
- expect(rowAtScrollOffset(0, PANE, 100)).toBe(0);
2309
- expect(rowAtScrollOffset(PANE * 7, PANE, 100)).toBe(7);
2310
- });
2311
-
2312
- it('rounds to the nearest row mid-scroll', () => {
2313
- expect(rowAtScrollOffset(PANE * 7 + 10, PANE, 100)).toBe(7);
2314
- expect(rowAtScrollOffset(PANE * 7 - 10, PANE, 100)).toBe(7);
2315
- expect(rowAtScrollOffset(PANE * 6.6, PANE, 100)).toBe(7);
2316
- });
2317
-
2318
- it('never leaves the list', () => {
2319
- expect(rowAtScrollOffset(-500, PANE, 100)).toBe(0);
2320
- expect(rowAtScrollOffset(PANE * 1000, PANE, 100)).toBe(99);
2321
- });
2322
-
2323
- it('is 0 before the pane size is known, rather than dividing by zero', () => {
2324
- expect(rowAtScrollOffset(1234, 0, 100)).toBe(0);
2325
- });
2326
-
2327
- it('reads RTL scrollLeft, which counts down from zero', () => {
2328
- // The spec puts the inline start at 0 and runs negative from there, so
2329
- // an unsigned read would pin an RTL calendar to month zero forever.
2330
- expect(rowAtScrollOffset(-PANE * 7, PANE, 100, true)).toBe(7);
2331
- expect(rowAtScrollOffset(-PANE * 7 - 10, PANE, 100, true)).toBe(7);
2332
- expect(rowAtScrollOffset(0, PANE, 100, true)).toBe(0);
2333
- });
2334
- });
2335
-
2336
- describe('scrollOffsetForRow', () => {
2337
- it('is the inverse of rowAtScrollOffset, in both directions', () => {
2338
- for (const isRTL of [false, true]) {
2339
- for (const row of [0, 1, 7, 99]) {
2340
- const offset = scrollOffsetForRow(row, PANE, isRTL);
2341
- expect(rowAtScrollOffset(offset, PANE, 100, isRTL)).toBe(row);
2342
- }
2343
- }
2344
- });
2345
-
2346
- it('runs negative under RTL', () => {
2347
- expect(scrollOffsetForRow(3, PANE, false)).toBe(PANE * 3);
2348
- expect(scrollOffsetForRow(3, PANE, true)).toBe(-PANE * 3);
2349
- });
2350
- });
2351
-
2352
- describe('paneWindow', () => {
2353
- it('mounts the overscan on both sides', () => {
2354
- expect(paneWindow(50, 100, 3)).toEqual({start: 47, end: 53});
2355
- expect(rowsIn(paneWindow(50, 100, 1))).toEqual([49, 50, 51]);
2356
- });
2357
-
2358
- it('truncates at the ends of the list instead of going out of bounds', () => {
2359
- expect(paneWindow(0, 100, 3)).toEqual({start: 0, end: 3});
2360
- expect(paneWindow(99, 100, 3)).toEqual({start: 96, end: 99});
2361
- });
2362
- });
2363
-
2364
- it('reaches a century in each direction by default', () => {
2365
- expect(DEFAULT_MONTH_REACH).toBe(600);
2366
- });
2367
- });
2368
-
2369
- // ---------------------------------------------------------------------------
2370
- // Styles jsdom cannot resolve — assert the definition, not the effect
2371
- // ---------------------------------------------------------------------------
2372
-
2373
- describe('DateInput — scroll CSS (definition-level)', () => {
2374
- const dir = path.dirname(fileURLToPath(import.meta.url));
2375
- const read = (file: string) => readFileSync(path.join(dir, file), 'utf8');
2376
-
2377
- /**
2378
- * The declarations inside one named style object, comments stripped and
2379
- * trailing commas removed.
2380
- *
2381
- * Crude on purpose — a nested value object contributes its own inner lines
2382
- * too. Every caller looks for a specific property prefix, so the noise is
2383
- * harmless, and a real parser here would be more machinery than the
2384
- * question deserves.
2385
- */
2386
- const declarations = (source: string, object: string) => {
2387
- const open = source.indexOf(` ${object}: {`);
2388
- expect(open).toBeGreaterThan(-1);
2389
- return source
2390
- .slice(open, source.indexOf('\n },', open))
2391
- .replace(/\/\/.*$/gm, '')
2392
- .split('\n')
2393
- .map(line => line.trim())
2394
- .filter(line => line.endsWith(','))
2395
- .map(line => line.slice(0, -1));
2396
- };
2397
-
2398
- /** The same, scoped to one `export const <group> = stylex.create({...})`. */
2399
- const declarationsIn = (source: string, group: string, object: string) => {
2400
- const at = source.indexOf(`export const ${group}`);
2401
- expect(at).toBeGreaterThan(-1);
2402
- return declarations(source.slice(at), object);
2403
- };
2404
-
2405
- it('pages the month scroller one whole pane at a time, horizontally', () => {
2406
- const source = read('MonthScroller.tsx');
2407
- expect(source).toContain("scrollSnapType: 'x mandatory'");
2408
- expect(source).toContain("scrollSnapAlign: 'start'");
2409
- // pan-x is what splits the gesture by axis: horizontal pans stay with the
2410
- // calendar, vertical ones reach the sheet as swipe-to-dismiss. Without it
2411
- // the two would fight again, the way they did when this scrolled down.
2412
- expect(source).toContain("touchAction: 'pan-x'");
2413
- // The pane and the scrollport must come from the same expression, or a
2414
- // pane stops being exactly one screen and every snap offset drifts.
2415
- expect(
2416
- source.match(/blockSize: dateInputTouchGeometry\.paneBlockSize/g),
2417
- ).toHaveLength(2);
2418
- });
2419
-
2420
- it('positions panes with logical properties, so RTL mirrors', () => {
2421
- const source = read('MonthScroller.tsx');
2422
- // Scoped to the style objects: `scrollTo({left})` is the DOM API and is
2423
- // supposed to say left — it is the CSS that must stay logical, because
2424
- // physical `left` would lay the months out identically in both directions
2425
- // while the scroll math mirrored, and the two would disagree under RTL.
2426
- const styles = source
2427
- .slice(
2428
- source.indexOf('const styles = stylex.create('),
2429
- source.indexOf('export interface MonthScrollerHandle'),
2430
- )
2431
- // Comments explain the rule ("insetInlineStart, not left") and would
2432
- // otherwise trip it.
2433
- .replace(/\/\/.*$/gm, '');
2434
- expect(styles).toContain('insetInlineStart');
2435
- expect(styles).not.toMatch(/\bleft:/);
2436
- expect(styles).not.toMatch(/\bright:/);
2437
- });
2438
-
2439
- /**
2440
- * Adjacent days take the desktop calendar's exact treatment, and the point
2441
- * of reading BOTH files is that "exact" stays true if the desktop's changes.
2442
- *
2443
- * Calendar splits the treatment across two style objects — `dayCellTheme`
2444
- * carries the colour, `dayCellStyles` the opacity — so copying it by eye
2445
- * gets you one half and not the other. This pane took only the colour at
2446
- * first, and the spill days came out visibly heavier than the desktop's.
2447
- *
2448
- * Both surfaces now render the same three tiers, measured in a browser on
2449
- * the same story: 23 for a day you can pick, 185 for one the range rules
2450
- * out, 203 for a spilled day (which is outside AND therefore disabled, so
2451
- * it takes both). The enabled-adjacent tier that used to sit at 169 is gone
2452
- * with the tap that produced it.
2453
- */
2454
- it('mutes adjacent days exactly as the desktop calendar does', () => {
2455
- // The desktop's two halves, read out of its own source rather than
2456
- // restated here — so the check follows the desktop if its treatment
2457
- // moves, instead of freezing today's values into this file.
2458
- const desktop = read('../Calendar/styles.ts');
2459
- const structural = declarationsIn(desktop, 'dayCellStyles', 'dayOutside');
2460
- const theme = declarationsIn(desktop, 'dayCellTheme', 'dayOutside');
2461
- // Both halves must have found something, or the parity check below is
2462
- // `arrayContaining([])` and passes on anything at all.
2463
- expect(structural.length).toBeGreaterThan(0);
2464
- expect(theme.length).toBeGreaterThan(0);
2465
-
2466
- // And the touch pane carries all of it, in its one object.
2467
- const touch = declarations(read('MonthScroller.tsx'), 'dayOutside');
2468
- expect(touch).toEqual(expect.arrayContaining([...structural, ...theme]));
2469
- });
2470
-
2471
- /**
2472
- * Disabled days follow the desktop too, and this is the half that actually
2473
- * answered "the disabled dates and the adjacent ones look the same".
2474
- *
2475
- * The desktop FADES a disabled day rather than recolouring it: `opacity:
2476
- * 0.3` over whatever colour the day already had. This pane used to paint a
2477
- * flat `--color-text-disabled` instead, which on white put a disabled
2478
- * in-month day at ~163 and an ENABLED adjacent day at ~168 — five levels
2479
- * apart, indistinguishable, and with the disabled one the darker of the
2480
- * two, so the unpickable date read as the more solid one. Fading instead
2481
- * puts every disabled day lighter than every enabled one, which is the
2482
- * ordering a calendar needs.
2483
- */
2484
- it('fades disabled days as the desktop does, rather than recolouring them', () => {
2485
- const desktop = read('../Calendar/styles.ts');
2486
- const theme = declarationsIn(desktop, 'dayCellTheme', 'dayDisabled');
2487
- const touch = declarations(read('MonthScroller.tsx'), 'dayDisabled');
2488
-
2489
- // Whatever opacity the desktop fades to, this pane fades to the same one.
2490
- const fade = theme.find(d => d.startsWith('opacity:'));
2491
- expect(fade).toBeDefined();
2492
- expect(touch).toContain(fade);
2493
-
2494
- // And no colour of its own: a colour would override the secondary one a
2495
- // spilled day carries, collapsing "disabled" and "disabled and adjacent"
2496
- // into a single shade.
2497
- expect(touch.some(d => d.startsWith('color:'))).toBe(false);
2498
- // Parity, not a rule of this pane's own — if the desktop ever starts
2499
- // recolouring a disabled day, this fires and says to follow it.
2500
- expect(theme.some(d => d.startsWith('color:'))).toBe(false);
2501
- });
2502
-
2503
- /**
2504
- * Order matters as much as the values: `dayDisabled` is applied AFTER
2505
- * `dayOutside`, so a spilled day beyond min/max paints disabled rather than
2506
- * merely outside. Reversed, an unselectable date would look more available
2507
- * than the selectable ones beside it.
2508
- */
2509
- it('lets disabled win over outside on a spilled day past min/max', () => {
2510
- const applied = read('MonthScroller.tsx');
2511
- const outside = applied.indexOf('day.isOutside && styles.dayOutside');
2512
- const disabled = applied.indexOf('isDisabled && styles.dayDisabled');
2513
- expect(outside).toBeGreaterThan(-1);
2514
- expect(outside).toBeLessThan(disabled);
2515
- });
2516
-
2517
- it('keeps the month scroller and the wheels on border-box', () => {
2518
- // Load-bearing: clientHeight is the pane height, the snap offsets and the
2519
- // virtualization all at once.
2520
- expect(read('MonthScroller.tsx')).toContain("boxSizing: 'border-box'");
2521
- expect(read('Wheel.tsx')).toContain("boxSizing: 'border-box'");
2522
- });
2523
-
2524
- it('sizes the wheel row tighter than a day cell, with larger text', () => {
2525
- const tokens = read('tokens.stylex.ts');
2526
- // Scroll-first rows: closer together than day cells and closer to the
2527
- // text they hold, the way a platform picker packs them.
2528
- expect(tokens).toContain("wheelItemSize: '28px'");
2529
- expect(read('Wheel.tsx')).toContain(
2530
- "fontSize: typeScaleVars['--text-large-size']",
2531
- );
2532
- });
2533
-
2534
- it('centers wheel rows and pads both ends so either extreme can reach the band', () => {
2535
- const source = read('Wheel.tsx');
2536
- expect(source).toContain("scrollSnapType: 'y mandatory'");
2537
- expect(source).toContain("scrollSnapAlign: 'center'");
2538
- expect(source).toContain(
2539
- 'paddingBlock: dateInputTouchGeometry.wheelEdgePadding',
2540
- );
2541
- });
2542
-
2543
- it('leaves a two-finger pinch to the page over the wheels', () => {
2544
- // `pan-y` alone also refuses the browser's pinch-zoom over the wheel, so
2545
- // the page could not be zoomed over an open picker. The real-engine proof
2546
- // is WheelPinchZoom.a11y.chromium.spec.ts; jsdom computes no touch-action.
2547
- expect(declarations(read('Wheel.tsx'), 'scroller')).toContain(
2548
- "touchAction: 'pan-y pinch-zoom'",
2549
- );
2550
- });
2551
-
2552
- it('guards the scroll-driven falloff behind @supports', () => {
2553
- const source = read('Wheel.tsx');
2554
- // Without the guard, a browser that does not understand animation-timeline
2555
- // runs these keyframes once on the document timeline instead.
2556
- expect(source).toContain("'@supports (animation-timeline: view())'");
2557
- expect(source).toContain("animationTimeline: 'view(y)'");
2558
- expect(source).toContain("'@media (prefers-reduced-motion: reduce)'");
2559
- });
2560
-
2561
- it('keeps the falloff off the snap area itself', () => {
2562
- // A transform moves the snap area, and the wheel then settles a few
2563
- // pixels off the row it is showing.
2564
- const source = read('Wheel.tsx');
2565
- const itemInner = source.slice(source.indexOf('itemInner: {'));
2566
- expect(itemInner).toContain("animationTimeline: 'view(y)'");
2567
- const item = source.slice(
2568
- source.indexOf(' item: {'),
2569
- source.indexOf('itemInner: {'),
2570
- );
2571
- expect(item).not.toContain('animationTimeline');
2572
- expect(item).not.toContain("overflow: 'hidden'");
2573
- });
2574
-
2575
- it('insets the sheet content equally on every edge', () => {
2576
- const source = read('TouchDateField.tsx');
2577
- // One inset, and the header/footer must not add their own on top of it —
2578
- // that is what put the title and Done 4px off the day grid's line.
2579
- expect(source).toContain("paddingInline: spacingVars['--spacing-4']");
2580
- expect(source).toContain("paddingBlockEnd: spacingVars['--spacing-4']");
2581
- // The block-start is the documented exception: the grab handle floats out
2582
- // of flow, so the content wrapper owes it the height it occupies.
2583
- expect(source).toContain("paddingBlockStart: spacingVars['--spacing-6']");
2584
- const header = source.slice(
2585
- source.indexOf(' header: {'),
2586
- source.indexOf(' title: {'),
2587
- );
2588
- expect(header).not.toContain('paddingInline');
2589
- const footer = source.slice(
2590
- source.indexOf(' footer: {'),
2591
- source.indexOf(' sheetBody: {'),
2592
- );
2593
- expect(footer).not.toContain('paddingInline');
2594
- });
2595
-
2596
- it('sizes the closed field the same on both surfaces', () => {
2597
- // `DateInput` picks a surface from the pointer and `nativePicker`, so a
2598
- // field that sizes itself differently on one of them changes height for
2599
- // a reason the call site never asked about.
2600
- //
2601
- // Compared with formatting normalized away: the two files write the same
2602
- // declarations differently, one entry per line against one per size.
2603
- const sizeMap = (file: string) => {
2604
- const source = read(file);
2605
- const start = source.indexOf('const sizeStyles = stylex.create(');
2606
- expect(start).toBeGreaterThan(-1);
2607
- return source
2608
- .slice(start, source.indexOf('});', start))
2609
- .replace(/\/\/.*$/gm, '')
2610
- .replace(/\/\*[\s\S]*?\*\//g, '')
2611
- .replace(/\s+/g, '')
2612
- .replace(/,(?=[}\]])/g, '');
2613
- };
2614
- expect(sizeMap('TouchDateField.tsx')).toEqual(
2615
- sizeMap('NativeDateField.tsx'),
2616
- );
2617
- });
2618
-
2619
- it('floors the month arrows too — Button tops out at 36px', () => {
2620
- const source = read('TouchDateField.tsx');
2621
- const arrow = source.slice(
2622
- source.indexOf(' monthArrow: {'),
2623
- source.indexOf(' monthArrowIcon: {'),
2624
- );
2625
- expect(arrow).toContain(
2626
- "minBlockSize: {default: null, '@media (pointer: coarse)': TOUCH_TARGET}",
2627
- );
2628
- expect(arrow).toContain(
2629
- "minInlineSize: {default: null, '@media (pointer: coarse)': TOUCH_TARGET}",
2630
- );
2631
- });
2632
-
2633
- /**
2634
- * A bare inline wrapper puts the glyph on the text baseline, a few px above
2635
- * the button's optical centre. Core's Calendar carries the same rule on its
2636
- * own nav icons.
2637
- */
2638
- it('keeps the mirrored arrow glyph centred', () => {
2639
- const source = read('TouchDateField.tsx');
2640
- const icon = source.slice(source.indexOf(' monthArrowIcon: {'));
2641
- expect(icon.slice(0, icon.indexOf('}'))).toContain(
2642
- "display: 'inline-flex'",
2643
- );
2644
- });
2645
-
2646
- /**
2647
- * The wheels are a layer that fades in and out on top; the calendar under
2648
- * them is covered and uncovered, and never seen to move.
2649
- *
2650
- * The swap used to take turns — the outgoing surface faded out over a first
2651
- * leg, the incoming one waited and faded in over a second — because the
2652
- * wheels' panel was transparent. Overlapping them put the wheels'
2653
- * translucent selection band over the live calendar grid and tinted one
2654
- * band-shaped strip of it: "the grey area animates differently from the
2655
- * content".
2656
- *
2657
- * An opaque plate INSIDE the fading layer fixes that at the root. The layer
2658
- * renders as one finished opaque image and the fade applies to the image,
2659
- * so the band crosses at the same rate as everything beside it. And once it
2660
- * is opaque, the calendar needs no fade of its own — animating it too would
2661
- * be animating the date picker rather than the thing arriving over it.
2662
- *
2663
- * What this pins is that split: the layer above gets opacity and a
2664
- * background, the layer beneath gets visibility and nothing else.
2665
- */
2666
- it('fades the wheels in and out over a calendar that does not animate', () => {
2667
- const source = read('TouchDateField.tsx');
2668
- const overlay = declarations(source, 'panelOverlay');
2669
- const beneath = declarations(source, 'panelBeneath');
2670
-
2671
- // The layer fades, both directions — the transition is on the shown
2672
- // state, so entering and leaving it both animate.
2673
- expect(overlay).toContain("transitionProperty: 'opacity, visibility'");
2674
- expect(overlay).toContain('transitionDuration: SWAP_DURATION');
2675
- expect(declarations(source, 'panelOverlayHidden')).toContain('opacity: 0');
2676
-
2677
- // And it is opaque while it does, in the token the sheet paints itself
2678
- // with, so the fade is uniform across the band and the text alike.
2679
- expect(overlay).toContain(
2680
- "backgroundColor: colorVars['--color-background-surface']",
2681
- );
2682
-
2683
- // The layer beneath moves nothing that can be SEEN moving: visibility
2684
- // only, no opacity, so it is covered and uncovered rather than faded.
2685
- expect(beneath).toContain("transitionProperty: 'visibility'");
2686
- expect(beneath.some(d => d.startsWith('opacity'))).toBe(false);
2687
- expect(
2688
- declarations(source, 'panelBeneathHidden').some(d =>
2689
- d.startsWith('opacity'),
2690
- ),
2691
- ).toBe(false);
2692
-
2693
- // Two of each, and never the same one twice: the calendar panel and the
2694
- // calendar's footer actions are beneath, the wheels and their Done above.
2695
- const count = (name: string) =>
2696
- source.match(new RegExp(`styles\\.${name},`, 'g'))?.length ?? 0;
2697
- expect(count('panelBeneath')).toBe(2);
2698
- expect(count('panelOverlay')).toBe(2);
2699
- });
2700
-
2701
- /**
2702
- * The layer paints as a unit, which is what makes "opaque" mean "covers".
2703
- *
2704
- * Backgrounds and text paint in separate phases, so without a stacking
2705
- * context a later sibling's background lands UNDER an earlier sibling's
2706
- * text — the plate went in opaque and the calendar's day numbers showed
2707
- * straight through it. Measured before and after: ink inside the grid's box
2708
- * at full cover went from the calendar's 2.5% of pixels to the wheels' own.
2709
- *
2710
- * Easy to lose, because any opacity below 1 makes a stacking context by
2711
- * accident. It only breaks at the two ends of the fade, where opacity is
2712
- * exactly 1 — which is to say, whenever anyone is actually looking.
2713
- */
2714
- it('paints the layer as a unit, so the plate really covers', () => {
2715
- expect(declarations(read('TouchDateField.tsx'), 'panelOverlay')).toContain(
2716
- "isolation: 'isolate'",
2717
- );
2718
- });
2719
-
2720
- /**
2721
- * The weekday row and the header arrows are the one part of the calendar
2722
- * the layer cannot cover — the plate starts below the header. They fade on
2723
- * the layer's own timing rather than clearing instantly, so the change
2724
- * reads as one motion instead of chrome blinking out a beat ahead of the
2725
- * grid being covered.
2726
- */
2727
- it('fades the uncovered chrome on the same timing as the layer', () => {
2728
- const source = read('TouchDateField.tsx');
2729
- for (const name of ['weekdays', 'monthArrows']) {
2730
- expect(declarations(source, name)).toContain(
2731
- 'transitionDuration: SWAP_DURATION',
2732
- );
2733
- expect(declarations(source, `${name}Hidden`)).toContain('opacity: 0');
2734
- }
2735
- });
2736
-
2737
- /**
2738
- * The footer action spans the sheet. A full-width primary is the shape a
2739
- * phone form ends with, and it puts the target under the thumb wherever
2740
- * the hand is.
2741
- */
2742
- it('spans the footer with its action', () => {
2743
- const source = read('TouchDateField.tsx');
2744
- // One per surface: Save on the calendar, Done on the wheels.
2745
- expect(source.match(/width="100%"/g)).toHaveLength(2);
2746
- });
2747
-
2748
- /**
2749
- * The selection band has to be visible enough that fading it reads as a
2750
- * fade. At `--color-background-muted` (4.7% alpha) the whole plate sat 17
2751
- * units of colour from the sheet behind it, so its animation had 17 units
2752
- * to happen in while the text beside it travelled 412 — it did not look
2753
- * like it was fading, it looked like it appeared at the end.
2754
- * `--color-neutral` (10%) doubles that to 36 and is still quiet enough to
2755
- * sit under text.
2756
- */
2757
- it('gives the wheel band enough contrast for its fade to read', () => {
2758
- const source = read('Wheel.tsx');
2759
- const band = source.slice(
2760
- source.indexOf(' band: {'),
2761
- source.indexOf('});', source.indexOf(' band: {')),
2762
- );
2763
- expect(band).toContain("backgroundColor: colorVars['--color-neutral']");
2764
- });
2765
-
2766
- /**
2767
- * `--ease-standard` is `cubic-bezier(0.24, 1, 0.4, 1)`: right for something
2768
- * travelling a distance, wrong for a fade. Measured with it, opacity hit
2769
- * 50% in 91ms and 95% in 241ms of a 410ms transition — the fade was over
2770
- * long before the duration was, so lengthening the duration bought an
2771
- * imperceptible tail rather than a slower fade. A fade covers no distance,
2772
- * so its progress should simply be its progress.
2773
- *
2774
- * The title chevron is the exception and keeps the token: it rotates, and
2775
- * rotation is travel.
2776
- */
2777
- it('fades linearly, and eases only the thing that travels', () => {
2778
- const source = read('TouchDateField.tsx');
2779
- const styles = source.slice(
2780
- source.indexOf('const styles = stylex.create('),
2781
- );
2782
- const chevron = styles.slice(
2783
- styles.indexOf(' titleChevron: {'),
2784
- styles.indexOf(' titleChevronOpen: {'),
2785
- );
2786
- expect(chevron).toContain("transitionProperty: 'transform'");
2787
- expect(chevron).toContain(
2788
- "transitionTimingFunction: easeVars['--ease-standard']",
2789
- );
2790
- // The chevron is the only eased transition; every fade is linear.
2791
- expect(
2792
- styles.match(/transitionTimingFunction: easeVars\['--ease-standard'\]/g),
2793
- ).toHaveLength(1);
2794
- expect(styles.match(/transitionTimingFunction: 'linear'/g)).toHaveLength(4);
2795
- });
2796
-
2797
- /**
2798
- * Everything in the swap runs for the same time, so it reads as one change
2799
- * rather than several. The chevron included — it used to run
2800
- * `--duration-medium` against a 220ms swap and was still turning well after
2801
- * the wheels had settled.
2802
- *
2803
- * A token rather than a literal, so a consumer's motion scale carries: the
2804
- * Storybook theme resolves `--duration-fast` to 125ms, not the default
2805
- * 175ms, and the swap follows it without knowing.
2806
- */
2807
- it('runs the whole swap on one duration', () => {
2808
- const source = read('TouchDateField.tsx');
2809
- const styles = source.slice(
2810
- source.indexOf('const styles = stylex.create('),
2811
- );
2812
- // The arrows, Reset, the weekday row, the layer beneath, the layer
2813
- // above, and the chevron.
2814
- expect(styles.match(/transitionDuration: SWAP_DURATION/g)).toHaveLength(6);
2815
- // And no leftover hand-rolled timing beside them.
2816
- expect(styles).not.toContain('PANEL_FADE_MS');
2817
- expect(source).toContain(
2818
- "const SWAP_DURATION = durationVars['--duration-fast']",
2819
- );
2820
- });
2821
-
2822
- it('keeps the virtual keyboard down on the touch field', () => {
2823
- const source = read('TouchDateField.tsx');
2824
- // readOnly alone still opens the keyboard on some Android browsers.
2825
- expect(source).toContain('readOnly');
2826
- expect(source).toContain('inputMode="none"');
2827
- });
2828
- });