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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (559) hide show
  1. package/dist/AlertDialog/AlertDialog.d.ts +1 -1
  2. package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
  3. package/dist/AlertDialog/AlertDialog.js +5 -5
  4. package/dist/Avatar/Avatar.d.ts.map +1 -1
  5. package/dist/Avatar/Avatar.js +12 -3
  6. package/dist/Badge/Badge.d.ts.map +1 -1
  7. package/dist/Badge/Badge.js +7 -1
  8. package/dist/BottomSheet/BottomSheet.js +1 -1
  9. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
  10. package/dist/BottomSheet/BottomSheetPanel.js +2 -1
  11. package/dist/BottomSheet/useSheetGestures.d.ts +12 -0
  12. package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
  13. package/dist/BottomSheet/useSheetGestures.js +30 -3
  14. package/dist/Button/Button.js +4 -4
  15. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  16. package/dist/CheckboxInput/CheckboxInput.js +6 -5
  17. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  18. package/dist/ClickableCard/ClickableCard.js +37 -4
  19. package/dist/DateInput/DateInput.d.ts.map +1 -1
  20. package/dist/DateInput/DateInput.js +12 -4
  21. package/dist/DateInput/MonthScroller.d.ts.map +1 -1
  22. package/dist/DateInput/MonthScroller.js +101 -15
  23. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  24. package/dist/DateInput/TouchDateField.js +8 -3
  25. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  26. package/dist/DateRangeInput/DateRangeInput.js +1 -1
  27. package/dist/DateTimeInput/DateTimeInput.d.ts +5 -2
  28. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  29. package/dist/DateTimeInput/DateTimeInput.js +23 -12
  30. package/dist/DateTimeInput/NativeTimeSegment.d.ts.map +1 -1
  31. package/dist/DateTimeInput/NativeTimeSegment.js +5 -4
  32. package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
  33. package/dist/DateTimeInput/TouchDateTimeField.js +4 -3
  34. package/dist/Dialog/Dialog.d.ts.map +1 -1
  35. package/dist/Dialog/Dialog.js +34 -9
  36. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  37. package/dist/Dialog/DialogHeader.js +5 -4
  38. package/dist/Divider/Divider.d.ts.map +1 -1
  39. package/dist/Divider/Divider.js +2 -1
  40. package/dist/Drawer/Drawer.d.ts +1 -0
  41. package/dist/Drawer/Drawer.d.ts.map +1 -1
  42. package/dist/Drawer/Drawer.js +7 -2
  43. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  44. package/dist/DropdownMenu/DropdownMenu.js +7 -3
  45. package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts.map +1 -1
  46. package/dist/DropdownMenu/MenuBottomSheetActionList.js +6 -5
  47. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts +20 -2
  48. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts.map +1 -1
  49. package/dist/DropdownMenu/lazyMenuBottomSheet.js +31 -3
  50. package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
  51. package/dist/DropdownMenu/renderDropdownItems.js +21 -16
  52. package/dist/EmptyState/EmptyState.d.ts.map +1 -1
  53. package/dist/EmptyState/EmptyState.js +2 -1
  54. package/dist/Field/FieldLabel.d.ts +1 -1
  55. package/dist/Field/FieldLabel.d.ts.map +1 -1
  56. package/dist/Field/FieldLabel.js +4 -4
  57. package/dist/Field/InputClearButton.js +3 -3
  58. package/dist/Field/PanelSearchInput.js +2 -2
  59. package/dist/FieldStatus/FieldStatus.js +2 -2
  60. package/dist/FileInput/FileInput.d.ts.map +1 -1
  61. package/dist/FileInput/FileInput.js +7 -1
  62. package/dist/Heading/Heading.js +1 -1
  63. package/dist/Icon/Icon.js +1 -1
  64. package/dist/Indicator/CheckIndicator.d.ts.map +1 -1
  65. package/dist/Indicator/CheckIndicator.js +2 -1
  66. package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -1
  67. package/dist/Indicator/CheckboxIndicator.js +3 -1
  68. package/dist/Indicator/RadioIndicator.d.ts.map +1 -1
  69. package/dist/Indicator/RadioIndicator.js +3 -1
  70. package/dist/Item/Item.d.ts.map +1 -1
  71. package/dist/Item/Item.js +2 -1
  72. package/dist/Item/ItemSwipeLayer.js +1 -1
  73. package/dist/Layer/popoverOperations.d.ts +27 -0
  74. package/dist/Layer/popoverOperations.d.ts.map +1 -0
  75. package/dist/Layer/popoverOperations.js +159 -0
  76. package/dist/Layer/useLayer.d.ts +1 -1
  77. package/dist/Layer/useLayer.d.ts.map +1 -1
  78. package/dist/Layer/useLayer.js +93 -59
  79. package/dist/Layout/Layout.js +1 -1
  80. package/dist/Layout/LayoutContent.js +1 -1
  81. package/dist/Layout/LayoutFooter.js +1 -1
  82. package/dist/Layout/LayoutHeader.js +1 -1
  83. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  84. package/dist/Lightbox/Lightbox.js +5 -0
  85. package/dist/Lightbox/LightboxViewport.a11y.browser.spec.js +5 -4
  86. package/dist/List/List.js +1 -1
  87. package/dist/List/ListItem.js +3 -3
  88. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  89. package/dist/MobileNav/MobileNav.js +7 -2
  90. package/dist/MultiSelector/CreateRow.a11y.chromium.spec.js +7 -6
  91. package/dist/MultiSelector/MultiSelector.d.ts +1 -1
  92. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  93. package/dist/MultiSelector/MultiSelector.js +26 -10
  94. package/dist/NumberInput/NumberInput.d.ts +3 -1
  95. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  96. package/dist/NumberInput/NumberInput.js +3 -3
  97. package/dist/NumberInput/numberParser.d.ts +3 -0
  98. package/dist/NumberInput/numberParser.d.ts.map +1 -1
  99. package/dist/NumberInput/numberParser.js +7 -44
  100. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  101. package/dist/ProgressBar/ProgressBar.js +16 -12
  102. package/dist/Resizable/useResizable.d.ts.map +1 -1
  103. package/dist/Resizable/useResizable.js +28 -2
  104. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  105. package/dist/SegmentedControl/SegmentedControlItem.js +4 -1
  106. package/dist/Selector/useSelectorPresentation.d.ts +8 -1
  107. package/dist/Selector/useSelectorPresentation.d.ts.map +1 -1
  108. package/dist/Selector/useSelectorPresentation.js +20 -4
  109. package/dist/Skeleton/Skeleton.d.ts.map +1 -1
  110. package/dist/Skeleton/Skeleton.js +1 -1
  111. package/dist/Slider/Slider.d.ts.map +1 -1
  112. package/dist/Slider/Slider.js +10 -2
  113. package/dist/Spinner/Spinner.d.ts.map +1 -1
  114. package/dist/Spinner/Spinner.js +3 -3
  115. package/dist/Stack/Stack.js +1 -1
  116. package/dist/Stack/StackItem.js +1 -1
  117. package/dist/TabList/TabList.d.ts.map +1 -1
  118. package/dist/TabList/TabList.js +16 -1
  119. package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
  120. package/dist/Table/plugins/columnResize/useTableColumnResize.js +9 -1
  121. package/dist/Text/Text.js +1 -1
  122. package/dist/Text/useTruncation.d.ts.map +1 -1
  123. package/dist/Text/useTruncation.js +23 -5
  124. package/dist/TextArea/TextArea.d.ts +1 -1
  125. package/dist/TextArea/TextArea.d.ts.map +1 -1
  126. package/dist/TextArea/TextArea.js +13 -2
  127. package/dist/TextInput/TextInput.d.ts.map +1 -1
  128. package/dist/TextInput/TextInput.js +3 -3
  129. package/dist/TimeInput/TimeInput.d.ts +6 -2
  130. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  131. package/dist/TimeInput/TimeInput.js +21 -14
  132. package/dist/TimeInput/TouchTimeField.d.ts.map +1 -1
  133. package/dist/TimeInput/TouchTimeField.js +5 -4
  134. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  135. package/dist/Timestamp/Timestamp.js +2 -2
  136. package/dist/Timestamp/TimestampHoverCard.js +4 -4
  137. package/dist/Toast/Toast.d.ts.map +1 -1
  138. package/dist/Toast/Toast.js +60 -20
  139. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  140. package/dist/Toast/ToastViewport.js +82 -51
  141. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  142. package/dist/Tokenizer/Tokenizer.js +13 -2
  143. package/dist/Tokenizer/TokenizerBottomSheet.js +3 -3
  144. package/dist/Toolbar/Toolbar.d.ts.map +1 -1
  145. package/dist/Toolbar/Toolbar.js +2 -1
  146. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  147. package/dist/TopNav/TopNavMegaMenu.js +3 -0
  148. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  149. package/dist/TopNav/TopNavMenu.js +1 -0
  150. package/dist/Typeahead/Typeahead.d.ts +1 -1
  151. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  152. package/dist/Typeahead/Typeahead.js +9 -1
  153. package/dist/astryx.css +20 -4
  154. package/dist/gestures/GestureArena.d.ts +6 -0
  155. package/dist/gestures/GestureArena.d.ts.map +1 -1
  156. package/dist/gestures/GestureArena.js +39 -0
  157. package/dist/gestures/GestureHost.d.ts +352 -0
  158. package/dist/gestures/GestureHost.d.ts.map +1 -0
  159. package/dist/gestures/GestureHost.js +1773 -0
  160. package/dist/gestures/GestureRecognizer.d.ts +10 -0
  161. package/dist/gestures/GestureRecognizer.d.ts.map +1 -1
  162. package/dist/gestures/GestureRecognizer.js +16 -0
  163. package/dist/gestures/LongPressGestureRecognizer.d.ts +1 -0
  164. package/dist/gestures/LongPressGestureRecognizer.d.ts.map +1 -1
  165. package/dist/gestures/LongPressGestureRecognizer.js +3 -0
  166. package/dist/gestures/PanGestureRecognizer.d.ts +1 -0
  167. package/dist/gestures/PanGestureRecognizer.d.ts.map +1 -1
  168. package/dist/gestures/PanGestureRecognizer.js +3 -0
  169. package/dist/gestures/PinchGestureRecognizer.d.ts +31 -0
  170. package/dist/gestures/PinchGestureRecognizer.d.ts.map +1 -0
  171. package/dist/gestures/PinchGestureRecognizer.js +128 -0
  172. package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts +71 -0
  173. package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts.map +1 -0
  174. package/dist/gestures/ScreenEdgePanGestureRecognizer.js +223 -0
  175. package/dist/gestures/SwipeGestureRecognizer.d.ts +37 -0
  176. package/dist/gestures/SwipeGestureRecognizer.d.ts.map +1 -0
  177. package/dist/gestures/SwipeGestureRecognizer.js +148 -0
  178. package/dist/gestures/TapGestureRecognizer.d.ts +1 -0
  179. package/dist/gestures/TapGestureRecognizer.d.ts.map +1 -1
  180. package/dist/gestures/TapGestureRecognizer.js +3 -0
  181. package/dist/gestures/VelocityTracker.d.ts +6 -2
  182. package/dist/gestures/VelocityTracker.d.ts.map +1 -1
  183. package/dist/gestures/VelocityTracker.js +7 -3
  184. package/dist/gestures/haptics.d.ts +65 -0
  185. package/dist/gestures/haptics.d.ts.map +1 -0
  186. package/dist/gestures/haptics.js +182 -0
  187. package/dist/gestures/nativeScroll.d.ts +42 -0
  188. package/dist/gestures/nativeScroll.d.ts.map +1 -0
  189. package/dist/gestures/nativeScroll.js +228 -0
  190. package/dist/gestures/touchAction.d.ts +60 -0
  191. package/dist/gestures/touchAction.d.ts.map +1 -0
  192. package/dist/gestures/touchAction.js +157 -0
  193. package/dist/gestures/touchActionRule.d.ts +34 -0
  194. package/dist/gestures/touchActionRule.d.ts.map +1 -0
  195. package/dist/gestures/touchActionRule.js +140 -0
  196. package/dist/gestures/types.d.ts +18 -7
  197. package/dist/gestures/types.d.ts.map +1 -1
  198. package/dist/gestures/types.js +22 -2
  199. package/dist/hooks/index.d.ts +1 -1
  200. package/dist/hooks/index.d.ts.map +1 -1
  201. package/dist/hooks/modalAnnounce.d.ts.map +1 -1
  202. package/dist/hooks/modalAnnounce.js +107 -61
  203. package/dist/hooks/useAdaptivePresentation.d.ts.map +1 -1
  204. package/dist/hooks/useAdaptivePresentation.js +4 -1
  205. package/dist/hooks/useAnnounce.d.ts +101 -42
  206. package/dist/hooks/useAnnounce.d.ts.map +1 -1
  207. package/dist/hooks/useAnnounce.js +161 -75
  208. package/dist/hooks/useAnnounceRenderedText.d.ts +11 -3
  209. package/dist/hooks/useAnnounceRenderedText.d.ts.map +1 -1
  210. package/dist/hooks/useAnnounceRenderedText.js +5 -3
  211. package/dist/hooks/useBusyAnnouncement.d.ts.map +1 -1
  212. package/dist/hooks/useBusyAnnouncement.js +6 -12
  213. package/dist/hooks/useMenuHover.d.ts.map +1 -1
  214. package/dist/hooks/useMenuHover.js +12 -1
  215. package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
  216. package/dist/i18n/generated-locales/en.generated.js +5 -0
  217. package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
  218. package/dist/i18n/generated-locales/pseudo.generated.js +5 -0
  219. package/dist/motion/animator.d.ts +7 -1
  220. package/dist/motion/animator.d.ts.map +1 -1
  221. package/dist/motion/animator.js +119 -27
  222. package/dist/theme/defineTheme.d.ts +19 -5
  223. package/dist/theme/defineTheme.d.ts.map +1 -1
  224. package/dist/theme/defineTheme.js +64 -4
  225. package/dist/theme/domainTokens/domainTokenDefaults.d.ts +3 -0
  226. package/dist/theme/domainTokens/domainTokenDefaults.d.ts.map +1 -0
  227. package/dist/theme/domainTokens/domainTokenDefaults.js +19 -0
  228. package/dist/theme/domainTokens/index.d.ts +5 -4
  229. package/dist/theme/domainTokens/index.d.ts.map +1 -1
  230. package/dist/theme/domainTokens/index.js +5 -9
  231. package/dist/theme/index.d.ts +1 -0
  232. package/dist/theme/index.d.ts.map +1 -1
  233. package/dist/theme/motionKnobs.d.ts +56 -0
  234. package/dist/theme/motionKnobs.d.ts.map +1 -0
  235. package/dist/theme/motionKnobs.js +48 -0
  236. package/dist/theme/resolveThemeValues.d.ts +11 -4
  237. package/dist/theme/resolveThemeValues.d.ts.map +1 -1
  238. package/dist/theme/resolveThemeValues.js +40 -4
  239. package/dist/theme/themeAdaptations.d.ts +7 -3
  240. package/dist/theme/themeAdaptations.d.ts.map +1 -1
  241. package/dist/theme/themeAdaptations.js +36 -7
  242. package/dist/theme/themeMotion.d.ts +96 -0
  243. package/dist/theme/themeMotion.d.ts.map +1 -0
  244. package/dist/theme/themeMotion.js +177 -0
  245. package/dist/theme/tokenReferences.d.ts +31 -0
  246. package/dist/theme/tokenReferences.d.ts.map +1 -0
  247. package/dist/theme/tokenReferences.js +132 -0
  248. package/dist/theme/tokens.d.ts +1 -0
  249. package/dist/theme/tokens.d.ts.map +1 -1
  250. package/dist/theme/tokens.js +9 -129
  251. package/dist/theme/tokens.stylex.d.ts +12 -0
  252. package/dist/theme/tokens.stylex.d.ts.map +1 -1
  253. package/dist/theme/tokens.stylex.js +12 -0
  254. package/dist/utils/focusReturn.d.ts +17 -1
  255. package/dist/utils/focusReturn.d.ts.map +1 -1
  256. package/dist/utils/focusReturn.js +11 -4
  257. package/dist/utils/getNodeText.d.ts +8 -0
  258. package/dist/utils/getNodeText.d.ts.map +1 -0
  259. package/dist/utils/getNodeText.js +37 -0
  260. package/dist/utils/interactionModality.d.ts +11 -2
  261. package/dist/utils/interactionModality.d.ts.map +1 -1
  262. package/dist/utils/interactionModality.js +58 -5
  263. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
  264. package/dist/utils/interactionOverlay.stylex.js +17 -8
  265. package/dist/utils/plainDate.d.ts +2 -0
  266. package/dist/utils/plainDate.d.ts.map +1 -1
  267. package/dist/utils/plainDate.js +46 -3
  268. package/dist/utils/presentation.d.ts +50 -0
  269. package/dist/utils/presentation.d.ts.map +1 -0
  270. package/dist/utils/presentation.js +125 -0
  271. package/dist/utils/pressFeedback.d.ts.map +1 -1
  272. package/dist/utils/pressFeedback.js +20 -1
  273. package/dist/utils/primaryClick.d.ts +11 -0
  274. package/dist/utils/primaryClick.d.ts.map +1 -0
  275. package/dist/utils/primaryClick.js +25 -0
  276. package/dist/utils/timeFormat.d.ts +47 -0
  277. package/dist/utils/timeFormat.d.ts.map +1 -0
  278. package/dist/utils/timeFormat.js +240 -0
  279. package/dist/utils/touchPresentation.d.ts.map +1 -1
  280. package/dist/utils/touchPresentation.js +5 -3
  281. package/dist/utils/touchPresentation.stylex.d.ts +15 -0
  282. package/dist/utils/touchPresentation.stylex.d.ts.map +1 -0
  283. package/dist/utils/touchPresentation.stylex.js +33 -0
  284. package/dist/utils/unicodeDigits.d.ts +20 -0
  285. package/dist/utils/unicodeDigits.d.ts.map +1 -0
  286. package/dist/utils/unicodeDigits.js +70 -0
  287. package/locales/en.json +23 -3
  288. package/locales/pseudo.json +15 -0
  289. package/package.json +5 -4
  290. package/src/AlertDialog/AlertDialog.tsx +6 -5
  291. package/src/AlertDialog/__tests__/AlertDialog.a11y.chromium.spec.ts +18 -6
  292. package/src/Avatar/Avatar.spec.md +22 -22
  293. package/src/Avatar/Avatar.tsx +18 -1
  294. package/src/Avatar/__tests__/AvatarForcedColors.a11y.chromium.spec.ts +126 -0
  295. package/src/Badge/Badge.doc.mjs +1 -1
  296. package/src/Badge/Badge.tsx +19 -2
  297. package/src/Badge/__tests__/BadgeLargerText.a11y.chromium.spec.ts +260 -0
  298. package/src/BottomSheet/BottomSheet.test.tsx +46 -0
  299. package/src/BottomSheet/BottomSheet.tsx +1 -1
  300. package/src/BottomSheet/BottomSheetPanel.tsx +2 -1
  301. package/src/BottomSheet/useSheetGestures.test.ts +52 -0
  302. package/src/BottomSheet/useSheetGestures.ts +37 -6
  303. package/src/Breadcrumbs/__tests__/Breadcrumbs.a11y.chromium.spec.ts +18 -6
  304. package/src/Button/Button.tsx +4 -4
  305. package/src/Calendar/Calendar.spec.md +87 -48
  306. package/src/Calendar/__tests__/Calendar.a11y.chromium.spec.ts +21 -7
  307. package/src/Carousel/__tests__/Carousel.a11y.chromium.spec.ts +21 -7
  308. package/src/CheckboxInput/CheckboxInput.tsx +6 -5
  309. package/src/ClickableCard/ClickableCard.test.tsx +96 -0
  310. package/src/ClickableCard/ClickableCard.tsx +48 -4
  311. package/src/Collapsible/Collapsible.spec.md +2 -0
  312. package/src/Collapsible/CollapsibleGroup.spec.md +57 -29
  313. package/src/Collapsible/__tests__/Collapsible.a11y.chromium.spec.ts +18 -7
  314. package/src/Collapsible/__tests__/CollapsibleGroupAccordion.a11y.chromium.spec.ts +18 -6
  315. package/src/ComplexSelector/ComplexSelector.test.tsx +37 -0
  316. package/src/ContextMenu/ContextMenu.test.tsx +35 -0
  317. package/src/DateInput/DateInput.test.tsx +115 -3
  318. package/src/DateInput/DateInput.tsx +29 -14
  319. package/src/DateInput/DateInputTouch.test.tsx +76 -0
  320. package/src/DateInput/MonthScroller.tsx +106 -20
  321. package/src/DateInput/MonthScrollerSettle.test.tsx +165 -0
  322. package/src/DateInput/TouchDateField.tsx +14 -3
  323. package/src/DateInput/__tests__/MonthScrollerSteps.interaction.browser.spec.ts +312 -0
  324. package/src/DateRangeInput/DateRangeInput.test.tsx +46 -3
  325. package/src/DateRangeInput/DateRangeInput.tsx +16 -12
  326. package/src/DateTimeInput/DateTimeInput.doc.mjs +10 -8
  327. package/src/DateTimeInput/DateTimeInput.spec.md +75 -51
  328. package/src/DateTimeInput/DateTimeInput.test.tsx +81 -0
  329. package/src/DateTimeInput/DateTimeInput.tsx +46 -24
  330. package/src/DateTimeInput/NativeTimeSegment.tsx +4 -6
  331. package/src/DateTimeInput/TouchDateTimeField.tsx +3 -7
  332. package/src/Dialog/Dialog.test.tsx +216 -2
  333. package/src/Dialog/Dialog.tsx +42 -9
  334. package/src/Dialog/DialogHeader.tsx +5 -4
  335. package/src/Dialog/__tests__/DialogSecondDocument.a11y.browser.spec.ts +202 -0
  336. package/src/Divider/Divider.tsx +2 -1
  337. package/src/Drawer/Drawer.spec.md +111 -80
  338. package/src/Drawer/Drawer.test.tsx +35 -0
  339. package/src/Drawer/Drawer.tsx +13 -2
  340. package/src/Drawer/DrawerHeader.spec.md +181 -0
  341. package/src/Drawer/__tests__/DrawerNonModalPageScroll.a11y.chromium.spec.ts +267 -0
  342. package/src/DropdownMenu/DropdownMenu.test.tsx +41 -0
  343. package/src/DropdownMenu/DropdownMenu.tsx +10 -3
  344. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +34 -0
  345. package/src/DropdownMenu/MenuBottomSheetActionList.tsx +6 -5
  346. package/src/DropdownMenu/__tests__/Menu.a11y.chromium.spec.ts +19 -7
  347. package/src/DropdownMenu/__tests__/MenuButton.a11y.chromium.spec.ts +21 -9
  348. package/src/DropdownMenu/lazyMenuBottomSheet.test.ts +60 -0
  349. package/src/DropdownMenu/lazyMenuBottomSheet.ts +36 -7
  350. package/src/DropdownMenu/renderDropdownItems.tsx +24 -19
  351. package/src/EmptyState/EmptyState.tsx +2 -1
  352. package/src/Field/FieldLabel.tsx +5 -4
  353. package/src/Field/InputClearButton.tsx +3 -3
  354. package/src/Field/PanelSearchInput.tsx +2 -2
  355. package/src/FieldStatus/FieldStatus.tsx +2 -2
  356. package/src/FileInput/FileInput.test.tsx +21 -0
  357. package/src/FileInput/FileInput.tsx +4 -1
  358. package/src/FormLayout/FormLayout.spec.md +7 -8
  359. package/src/Heading/Heading.tsx +1 -1
  360. package/src/Icon/Icon.tsx +1 -1
  361. package/src/Indicator/CheckIndicator.spec.md +47 -42
  362. package/src/Indicator/CheckIndicator.tsx +2 -1
  363. package/src/Indicator/CheckboxIndicator.spec.md +40 -37
  364. package/src/Indicator/CheckboxIndicator.tsx +3 -1
  365. package/src/Indicator/Indicator.spec.md +188 -0
  366. package/src/Indicator/RadioIndicator.tsx +3 -1
  367. package/src/Item/Item.tsx +2 -1
  368. package/src/Item/ItemSwipeLayer.tsx +1 -1
  369. package/src/Kbd/Kbd.spec.md +81 -38
  370. package/src/Layer/__tests__/LayerBrowserHide.a11y.chromium.spec.ts +126 -0
  371. package/src/Layer/popoverOperations.test.ts +205 -0
  372. package/src/Layer/popoverOperations.ts +172 -0
  373. package/src/Layer/useLayer.test.tsx +348 -1
  374. package/src/Layer/useLayer.tsx +118 -71
  375. package/src/Layout/Layout.spec.md +127 -131
  376. package/src/Layout/Layout.tsx +1 -1
  377. package/src/Layout/LayoutContent.spec.md +205 -0
  378. package/src/Layout/LayoutContent.tsx +1 -1
  379. package/src/Layout/LayoutFooter.spec.md +190 -0
  380. package/src/Layout/LayoutFooter.tsx +1 -1
  381. package/src/Layout/LayoutHeader.spec.md +193 -0
  382. package/src/Layout/LayoutHeader.tsx +1 -1
  383. package/src/Layout/LayoutPanel.spec.md +194 -0
  384. package/src/Layout/__tests__/Layout.a11y.chromium.spec.ts +18 -6
  385. package/src/Lightbox/Lightbox.test.tsx +18 -0
  386. package/src/Lightbox/Lightbox.tsx +5 -0
  387. package/src/Lightbox/LightboxViewport.a11y.browser.spec.ts +8 -4
  388. package/src/Link/__tests__/Link.a11y.chromium.spec.ts +18 -8
  389. package/src/List/List.tsx +1 -1
  390. package/src/List/ListItem.spec.md +205 -0
  391. package/src/List/ListItem.tsx +3 -3
  392. package/src/MetadataList/MetadataList.spec.md +187 -0
  393. package/src/MetadataList/MetadataListItem.spec.md +165 -0
  394. package/src/MobileNav/MobileNav.test.tsx +15 -0
  395. package/src/MobileNav/MobileNav.tsx +9 -1
  396. package/src/MobileNav/__tests__/MobileNavHeader.a11y.chromium.spec.ts +89 -0
  397. package/src/MoreMenu/MoreMenu.test.tsx +11 -0
  398. package/src/MultiSelector/CreateRow.a11y.chromium.spec.ts +7 -8
  399. package/src/MultiSelector/MultiSelector.spec.md +7 -4
  400. package/src/MultiSelector/MultiSelector.test.tsx +270 -1
  401. package/src/MultiSelector/MultiSelector.tsx +25 -10
  402. package/src/MultiSelector/__tests__/MultiSelector.listbox.a11y.test.tsx +8 -1
  403. package/src/NavMenu/NavHeadingMenu.spec.md +1 -5
  404. package/src/NumberInput/NumberInput.doc.mjs +13 -7
  405. package/src/NumberInput/NumberInput.spec.md +59 -37
  406. package/src/NumberInput/NumberInput.tsx +13 -3
  407. package/src/NumberInput/__tests__/NumberInput.coarse-pointer.a11y.chromium.spec.ts +102 -0
  408. package/src/NumberInput/numberParser.ts +7 -45
  409. package/src/ProgressBar/ProgressBar.test.tsx +108 -32
  410. package/src/ProgressBar/ProgressBar.tsx +58 -10
  411. package/src/ProgressBar/__tests__/ProgressBar.a11y.chromium.spec.ts +21 -9
  412. package/src/ProgressBar/__tests__/ProgressBarMotion.a11y.chromium.spec.ts +831 -0
  413. package/src/Resizable/__tests__/ResizeHandle.a11y.chromium.spec.ts +21 -14
  414. package/src/Resizable/useResizable.test.ts +43 -0
  415. package/src/Resizable/useResizable.ts +32 -9
  416. package/src/SegmentedControl/SegmentedControl.test.tsx +84 -0
  417. package/src/SegmentedControl/SegmentedControlItem.tsx +11 -5
  418. package/src/Selector/Selector.test.tsx +90 -1
  419. package/src/Selector/__tests__/Selector.combobox.a11y.test.tsx +8 -1
  420. package/src/Selector/__tests__/Selector.listbox.a11y.test.tsx +8 -1
  421. package/src/Selector/useSelectorPresentation.ts +31 -3
  422. package/src/SideNav/SideNav.test.tsx +27 -0
  423. package/src/SideNav/__tests__/SideNavRailMotion.interaction.browser.spec.ts +176 -51
  424. package/src/Skeleton/Skeleton.tsx +3 -1
  425. package/src/Slider/Slider.test.tsx +31 -0
  426. package/src/Slider/Slider.tsx +8 -3
  427. package/src/Slider/__tests__/Slider.a11y.chromium.spec.ts +19 -7
  428. package/src/Spinner/Spinner.tsx +5 -3
  429. package/src/Stack/Stack.tsx +1 -1
  430. package/src/Stack/StackItem.tsx +1 -1
  431. package/src/TabList/TabList.test.tsx +58 -4
  432. package/src/TabList/TabList.tsx +16 -1
  433. package/src/TabList/__tests__/TabPressPointer.interaction.browser.spec.ts +163 -0
  434. package/src/Table/__tests__/Table.a11y.chromium.spec.ts +18 -6
  435. package/src/Table/plugins/columnResize/useTableColumnResize.test.tsx +22 -0
  436. package/src/Table/plugins/columnResize/useTableColumnResize.tsx +8 -4
  437. package/src/Text/Text.tsx +1 -1
  438. package/src/Text/useTruncation.test.tsx +128 -1
  439. package/src/Text/useTruncation.ts +23 -5
  440. package/src/TextArea/TextArea.spec.md +10 -13
  441. package/src/TextArea/TextArea.test.tsx +60 -0
  442. package/src/TextArea/TextArea.tsx +15 -1
  443. package/src/TextInput/TextInput.test.tsx +21 -0
  444. package/src/TextInput/TextInput.tsx +3 -1
  445. package/src/TimeInput/NativeTimeInput.test.tsx +17 -0
  446. package/src/TimeInput/Presentation.test.tsx +21 -0
  447. package/src/TimeInput/TimeInput.doc.mjs +8 -8
  448. package/src/TimeInput/TimeInput.spec.md +45 -48
  449. package/src/TimeInput/TimeInput.test.tsx +76 -0
  450. package/src/TimeInput/TimeInput.tsx +36 -18
  451. package/src/TimeInput/TouchTimeField.tsx +4 -6
  452. package/src/Timestamp/Timestamp.spec.md +6 -12
  453. package/src/Timestamp/Timestamp.test.tsx +30 -5
  454. package/src/Timestamp/Timestamp.tsx +6 -2
  455. package/src/Timestamp/TimestampHoverCard.tsx +4 -4
  456. package/src/Toast/Toast.spec.md +14 -20
  457. package/src/Toast/Toast.tsx +104 -36
  458. package/src/Toast/ToastViewport.test.tsx +719 -1
  459. package/src/Toast/ToastViewport.tsx +100 -50
  460. package/src/Tokenizer/Tokenizer.spec.md +5 -3
  461. package/src/Tokenizer/Tokenizer.test.tsx +68 -0
  462. package/src/Tokenizer/Tokenizer.tsx +14 -2
  463. package/src/Tokenizer/TokenizerBottomSheet.test.tsx +15 -4
  464. package/src/Tokenizer/TokenizerBottomSheet.tsx +3 -3
  465. package/src/Toolbar/Toolbar.spec.md +5 -6
  466. package/src/Toolbar/Toolbar.test.tsx +30 -0
  467. package/src/Toolbar/Toolbar.tsx +2 -1
  468. package/src/Toolbar/__tests__/Toolbar.a11y.chromium.spec.ts +18 -6
  469. package/src/Tooltip/__tests__/Tooltip.a11y.chromium.spec.ts +18 -7
  470. package/src/TopNav/TopNav.test.tsx +27 -0
  471. package/src/TopNav/TopNavMegaMenu.test.tsx +21 -0
  472. package/src/TopNav/TopNavMegaMenu.tsx +4 -1
  473. package/src/TopNav/TopNavMenu.test.tsx +17 -0
  474. package/src/TopNav/TopNavMenu.tsx +1 -0
  475. package/src/Typeahead/Typeahead.test.tsx +40 -0
  476. package/src/Typeahead/Typeahead.tsx +12 -1
  477. package/src/__tests__/pressState.ts +8 -4
  478. package/src/gestures/GestureArena.ts +35 -0
  479. package/src/gestures/GestureHost.ts +2065 -0
  480. package/src/gestures/GestureRecognizer.ts +18 -0
  481. package/src/gestures/LongPressGestureRecognizer.ts +4 -0
  482. package/src/gestures/PanGestureRecognizer.ts +4 -0
  483. package/src/gestures/PinchGestureRecognizer.ts +148 -0
  484. package/src/gestures/ScreenEdgePanGestureRecognizer.ts +256 -0
  485. package/src/gestures/SwipeGestureRecognizer.ts +197 -0
  486. package/src/gestures/TapGestureRecognizer.ts +4 -0
  487. package/src/gestures/VelocityTracker.ts +10 -3
  488. package/src/gestures/__tests__/GestureHost.test.ts +2087 -0
  489. package/src/gestures/__tests__/PanGestureRecognizer.test.ts +4 -4
  490. package/src/gestures/__tests__/PinchGestureRecognizer.test.ts +74 -0
  491. package/src/gestures/__tests__/ScreenEdgePanGestureRecognizer.test.ts +498 -0
  492. package/src/gestures/__tests__/SwipeGestureRecognizer.test.ts +108 -0
  493. package/src/gestures/__tests__/arena.test.ts +5 -0
  494. package/src/gestures/__tests__/arenaPinchSwipeEdge.test.ts +193 -0
  495. package/src/gestures/__tests__/browser/build-fixture.mjs +46 -0
  496. package/src/gestures/__tests__/browser/fixture.ts +307 -0
  497. package/src/gestures/__tests__/browser/gestures.interaction.browser.spec.ts +1137 -0
  498. package/src/gestures/__tests__/browserNegotiation.test.ts +293 -0
  499. package/src/gestures/__tests__/haptics.test.ts +187 -0
  500. package/src/gestures/__tests__/harness.ts +21 -2
  501. package/src/gestures/__tests__/recognizerKind.test.ts +78 -0
  502. package/src/gestures/__tests__/touchActionRule.test.ts +54 -0
  503. package/src/gestures/haptics.ts +203 -0
  504. package/src/gestures/nativeScroll.ts +277 -0
  505. package/src/gestures/touchAction.ts +191 -0
  506. package/src/gestures/touchActionRule.ts +157 -0
  507. package/src/gestures/types.ts +30 -9
  508. package/src/hooks/index.ts +5 -1
  509. package/src/hooks/modalAnnounce.ts +129 -72
  510. package/src/hooks/useAdaptivePresentation.ts +4 -1
  511. package/src/hooks/useAnnounce.doc.mjs +35 -3
  512. package/src/hooks/useAnnounce.replace.test.tsx +516 -0
  513. package/src/hooks/useAnnounce.ts +209 -102
  514. package/src/hooks/useAnnounceRenderedText.adopters.test.tsx +10 -1
  515. package/src/hooks/useAnnounceRenderedText.ts +17 -3
  516. package/src/hooks/useBusyAnnouncement.ts +7 -10
  517. package/src/hooks/useMenuHover.ts +15 -1
  518. package/src/i18n/generated-locales/en.generated.ts +6 -0
  519. package/src/i18n/generated-locales/pseudo.generated.ts +6 -0
  520. package/src/motion/README.md +11 -1
  521. package/src/motion/animator.test.ts +151 -3
  522. package/src/motion/animator.ts +149 -33
  523. package/src/theme/Theme.doc.mjs +1 -1
  524. package/src/theme/defineTheme.ts +117 -8
  525. package/src/theme/derivedVarRegistry.test.ts +4 -0
  526. package/src/theme/domainTokens/domainTokenDefaults.ts +19 -0
  527. package/src/theme/domainTokens/index.ts +6 -10
  528. package/src/theme/expandMotionScale.test.ts +1 -1
  529. package/src/theme/index.ts +5 -0
  530. package/src/theme/motionKnobs.ts +82 -0
  531. package/src/theme/resolveThemeValues.ts +68 -6
  532. package/src/theme/themeAdaptations.ts +52 -12
  533. package/src/theme/themeMotion.test.ts +620 -0
  534. package/src/theme/themeMotion.ts +221 -0
  535. package/src/theme/tokenReferences.ts +149 -0
  536. package/src/theme/tokens.stylex.ts +10 -0
  537. package/src/theme/tokens.ts +15 -158
  538. package/src/utils/focusReturn.ts +17 -6
  539. package/src/utils/getNodeText.test.ts +24 -0
  540. package/src/utils/getNodeText.ts +37 -0
  541. package/src/utils/interactionModality.test.ts +45 -1
  542. package/src/utils/interactionModality.ts +64 -5
  543. package/src/utils/interactionOverlay.stylex.ts +12 -3
  544. package/src/utils/plainDate.test.ts +90 -0
  545. package/src/utils/plainDate.ts +58 -3
  546. package/src/utils/presentation.test.ts +380 -0
  547. package/src/utils/presentation.ts +180 -0
  548. package/src/utils/pressFeedback.test.ts +138 -0
  549. package/src/utils/pressFeedback.ts +34 -11
  550. package/src/utils/pressPaintPriority.test.ts +80 -0
  551. package/src/utils/primaryClick.test.ts +38 -0
  552. package/src/utils/primaryClick.ts +28 -0
  553. package/src/utils/timeFormat.test.ts +204 -0
  554. package/src/utils/timeFormat.ts +314 -0
  555. package/src/utils/touchPresentation.stylex.ts +43 -0
  556. package/src/utils/touchPresentation.test.ts +140 -1
  557. package/src/utils/touchPresentation.ts +5 -3
  558. package/src/utils/unicodeDigits.test.ts +44 -0
  559. package/src/utils/unicodeDigits.ts +71 -0
@@ -30,7 +30,7 @@ import {
30
30
  waitFor,
31
31
  within,
32
32
  } from '@testing-library/react';
33
- import React from 'react';
33
+ import React, {useRef} from 'react';
34
34
  import {readFileSync} from 'node:fs';
35
35
  import {type AnnounceFn, __resetLiveRegionsForTest} from '../hooks/useAnnounce';
36
36
  import {Button} from '../Button';
@@ -602,6 +602,173 @@ describe('ToastViewport keyboard reach + focus', () => {
602
602
  expect(document.activeElement).toBe(dismiss);
603
603
  });
604
604
 
605
+ it('moves focus to the neighbour when a control inside a toast raises its repeat and dismisses it', () => {
606
+ function OfflineFlow() {
607
+ const toast = useToast();
608
+ const dismissOfflineRef = useRef<(() => void) | null>(null);
609
+ const showOffline = (body: string) => {
610
+ dismissOfflineRef.current = toast({
611
+ uniqueID: 'offline',
612
+ isAutoHide: false,
613
+ body,
614
+ endContent: (
615
+ <button
616
+ type="button"
617
+ onClick={() => {
618
+ // A retry reports the state again, then closes the toast it
619
+ // was pressed in.
620
+ const dismissPressed = dismissOfflineRef.current;
621
+ showOffline('Still offline');
622
+ dismissPressed?.();
623
+ }}>
624
+ Retry
625
+ </button>
626
+ ),
627
+ });
628
+ };
629
+ return (
630
+ <>
631
+ <button
632
+ type="button"
633
+ onClick={() => {
634
+ toast({isAutoHide: false, body: 'Alpha'});
635
+ toast({isAutoHide: false, body: 'Bravo'});
636
+ }}>
637
+ Show two
638
+ </button>
639
+ <button type="button" onClick={() => showOffline('Offline')}>
640
+ Show offline
641
+ </button>
642
+ </>
643
+ );
644
+ }
645
+ render(
646
+ <ToastViewport isTopLayer={false} maxVisible={2}>
647
+ <OfflineFlow />
648
+ </ToastViewport>,
649
+ );
650
+ act(() => {
651
+ fireEvent.click(screen.getByText('Show two'));
652
+ });
653
+ act(() => {
654
+ fireEvent.click(screen.getByText('Show offline'));
655
+ });
656
+ // Alpha waits hidden; Bravo and Offline show.
657
+ const retry = within(getToastWrapperByText('Offline')).getByRole('button', {
658
+ name: 'Retry',
659
+ });
660
+ retry.focus();
661
+ act(() => {
662
+ fireEvent.click(retry);
663
+ });
664
+ // Toast.spec.md FR10: focus moves to a control in a remaining toast, the
665
+ // neighbour of the dismissed one, not to the hidden oldest toast or the
666
+ // region.
667
+ expect(
668
+ getToastWrapperByText('Bravo').contains(document.activeElement),
669
+ ).toBe(true);
670
+ });
671
+
672
+ it('moves focus into the replacement when a control inside the only toast raises its repeat and dismisses it', () => {
673
+ function OfflineFlow() {
674
+ const toast = useToast();
675
+ const dismissOfflineRef = useRef<(() => void) | null>(null);
676
+ const showOffline = (body: string) => {
677
+ dismissOfflineRef.current = toast({
678
+ uniqueID: 'offline',
679
+ isAutoHide: false,
680
+ body,
681
+ endContent: (
682
+ <button
683
+ type="button"
684
+ onClick={() => {
685
+ const dismissPressed = dismissOfflineRef.current;
686
+ showOffline('Still offline');
687
+ dismissPressed?.();
688
+ }}>
689
+ Retry
690
+ </button>
691
+ ),
692
+ });
693
+ };
694
+ return (
695
+ <button type="button" onClick={() => showOffline('Offline')}>
696
+ Show offline
697
+ </button>
698
+ );
699
+ }
700
+ render(
701
+ <ToastViewport isTopLayer={false}>
702
+ <OfflineFlow />
703
+ </ToastViewport>,
704
+ );
705
+ act(() => {
706
+ fireEvent.click(screen.getByText('Show offline'));
707
+ });
708
+ const retry = within(getToastWrapperByText('Offline')).getByRole('button', {
709
+ name: 'Retry',
710
+ });
711
+ retry.focus();
712
+ act(() => {
713
+ fireEvent.click(retry);
714
+ });
715
+ // FR10: the replacement is the remaining toast, so focus goes into it.
716
+ expect(
717
+ getToastWrapperByText('Still offline').contains(document.activeElement),
718
+ ).toBe(true);
719
+ });
720
+
721
+ it('moves focus to a toast that shows when a control inside a toast raises two toasts at the cap and dismisses its own', () => {
722
+ function UploadFlow() {
723
+ const toast = useToast();
724
+ const dismissSavedRef = useRef<(() => void) | null>(null);
725
+ return (
726
+ <button
727
+ type="button"
728
+ onClick={() => {
729
+ dismissSavedRef.current = toast({
730
+ isAutoHide: false,
731
+ body: 'Saved',
732
+ endContent: (
733
+ <button
734
+ type="button"
735
+ onClick={() => {
736
+ toast({isAutoHide: false, body: 'Uploading'});
737
+ toast({isAutoHide: false, body: 'Uploaded'});
738
+ dismissSavedRef.current?.();
739
+ }}>
740
+ Upload
741
+ </button>
742
+ ),
743
+ });
744
+ }}>
745
+ Save
746
+ </button>
747
+ );
748
+ }
749
+ render(
750
+ <ToastViewport isTopLayer={false} maxVisible={1}>
751
+ <UploadFlow />
752
+ </ToastViewport>,
753
+ );
754
+ act(() => {
755
+ fireEvent.click(screen.getByText('Save'));
756
+ });
757
+ const upload = within(getToastWrapperByText('Saved')).getByRole('button', {
758
+ name: 'Upload',
759
+ });
760
+ upload.focus();
761
+ act(() => {
762
+ fireEvent.click(upload);
763
+ });
764
+ // FR10: with one visible place, "Uploaded" shows and "Uploading" waits
765
+ // hidden, so focus goes to "Uploaded", not to the hidden toast or the
766
+ // region.
767
+ expect(
768
+ getToastWrapperByText('Uploaded').contains(document.activeElement),
769
+ ).toBe(true);
770
+ });
771
+
605
772
  it('dismissing a focused toast moves focus to a remaining toast, not body', () => {
606
773
  renderViewport(
607
774
  <>
@@ -2061,6 +2228,413 @@ describe('toast announcements via singleton live regions', () => {
2061
2228
  expect(within(viewport).getByText('Kept')).toBeInTheDocument();
2062
2229
  expect(within(viewport).queryByText('Dropped')).not.toBeInTheDocument();
2063
2230
  });
2231
+
2232
+ it('drops an ignored-collision toast while its namesake is still leaving', () => {
2233
+ renderViewport(
2234
+ <>
2235
+ <ShowToastButton
2236
+ options={{
2237
+ uniqueID: 'offline',
2238
+ collisionBehavior: 'ignore',
2239
+ isAutoHide: false,
2240
+ body: 'You are offline',
2241
+ }}
2242
+ triggerLabel="Show 1"
2243
+ />
2244
+ <ShowToastButton
2245
+ options={{
2246
+ uniqueID: 'offline',
2247
+ collisionBehavior: 'ignore',
2248
+ isAutoHide: false,
2249
+ body: 'Still offline',
2250
+ }}
2251
+ triggerLabel="Show 2"
2252
+ />
2253
+ </>,
2254
+ );
2255
+ act(() => {
2256
+ fireEvent.click(screen.getByText('Show 1'));
2257
+ });
2258
+ const first = getToastWrapperByText('You are offline');
2259
+ act(() => {
2260
+ fireEvent.click(
2261
+ within(first).getByRole('button', {name: 'Dismiss notification'}),
2262
+ );
2263
+ });
2264
+ // Toast.spec.md FR8: a leaving toast still holds its uniqueID, so the
2265
+ // ignored namesake is neither shown nor announced.
2266
+ act(() => {
2267
+ fireEvent.click(screen.getByText('Show 2'));
2268
+ });
2269
+ expect(announceSpy).toHaveBeenCalledTimes(1);
2270
+ expect(screen.queryByText('Still offline')).toBeNull();
2271
+ act(() => {
2272
+ completeExit(first.dataset.toastId ?? '');
2273
+ });
2274
+ expect(document.querySelectorAll('[data-toast-id]')).toHaveLength(0);
2275
+ });
2276
+
2277
+ it('lets a leaving toast finish its exit when a new toast arrives with no cap', () => {
2278
+ render(
2279
+ <ToastViewport isTopLayer={false} maxVisible={0}>
2280
+ <ShowToastButton
2281
+ options={{isAutoHide: false, body: 'Saved'}}
2282
+ triggerLabel="Show 1"
2283
+ />
2284
+ <ShowToastButton
2285
+ options={{isAutoHide: false, body: 'Uploaded'}}
2286
+ triggerLabel="Show 2"
2287
+ />
2288
+ </ToastViewport>,
2289
+ );
2290
+ act(() => {
2291
+ fireEvent.click(screen.getByText('Show 1'));
2292
+ });
2293
+ const first = getToastWrapperByText('Saved');
2294
+ const firstId = first.dataset.toastId ?? '';
2295
+ act(() => {
2296
+ fireEvent.click(
2297
+ within(first).getByRole('button', {name: 'Dismiss notification'}),
2298
+ );
2299
+ });
2300
+ // maxVisible={0} shows every toast (Toast.spec.md FR7), so the closing
2301
+ // toast keeps its row and collapses (FR5) while the new one arrives.
2302
+ act(() => {
2303
+ fireEvent.click(screen.getByText('Show 2'));
2304
+ });
2305
+ expect(getToastWrapperByText('Saved').dataset.toastId).toBe(firstId);
2306
+ expect(screen.getByText('Uploaded')).toBeInTheDocument();
2307
+ act(() => {
2308
+ completeExit(firstId);
2309
+ });
2310
+ expect(screen.queryByText('Saved')).toBeNull();
2311
+ expect(screen.getByText('Uploaded')).toBeInTheDocument();
2312
+ });
2313
+
2314
+ it('drops a second ignore toast with the same uniqueID raised in the same handler', () => {
2315
+ function ShowTwoIgnored() {
2316
+ const toast = useToast();
2317
+ return (
2318
+ <button
2319
+ type="button"
2320
+ onClick={() => {
2321
+ toast({
2322
+ uniqueID: 'offline',
2323
+ collisionBehavior: 'ignore',
2324
+ isAutoHide: false,
2325
+ body: 'You are offline',
2326
+ });
2327
+ toast({
2328
+ uniqueID: 'offline',
2329
+ collisionBehavior: 'ignore',
2330
+ isAutoHide: false,
2331
+ body: 'Still offline',
2332
+ });
2333
+ }}>
2334
+ Show twice
2335
+ </button>
2336
+ );
2337
+ }
2338
+ render(
2339
+ <ToastViewport isTopLayer={false}>
2340
+ <ShowTwoIgnored />
2341
+ </ToastViewport>,
2342
+ );
2343
+ act(() => {
2344
+ fireEvent.click(screen.getByText('Show twice'));
2345
+ });
2346
+ // Toast.spec.md FR8 and ORD1: the ignored namesake is neither shown nor
2347
+ // announced, even before the first toast renders.
2348
+ expect(announceSpy).toHaveBeenCalledTimes(1);
2349
+ expect(announceSpy).toHaveBeenLastCalledWith('You are offline', 'polite');
2350
+ const rows = [...document.querySelectorAll('[data-toast-id]')];
2351
+ expect(rows).toHaveLength(1);
2352
+ expect(rows[0].textContent).toContain('You are offline');
2353
+ });
2354
+
2355
+ it('leaves no row behind when a new toast takes the last visible slot from a leaving one', () => {
2356
+ render(
2357
+ <ToastViewport isTopLayer={false} maxVisible={1}>
2358
+ <ShowToastButton
2359
+ options={{isAutoHide: false, body: 'Saved'}}
2360
+ triggerLabel="Show 1"
2361
+ />
2362
+ <ShowToastButton
2363
+ options={{isAutoHide: false, body: 'Uploaded'}}
2364
+ triggerLabel="Show 2"
2365
+ />
2366
+ </ToastViewport>,
2367
+ );
2368
+ act(() => {
2369
+ fireEvent.click(screen.getByText('Show 1'));
2370
+ });
2371
+ const first = getToastWrapperByText('Saved');
2372
+ act(() => {
2373
+ fireEvent.click(
2374
+ within(first).getByRole('button', {name: 'Dismiss notification'}),
2375
+ );
2376
+ });
2377
+ // A new toast arrives at once; with one visible slot it takes the place of
2378
+ // the leaving toast, which can no longer finish its exit on screen.
2379
+ act(() => {
2380
+ fireEvent.click(screen.getByText('Show 2'));
2381
+ });
2382
+ const second = getToastWrapperByText('Uploaded');
2383
+ act(() => {
2384
+ fireEvent.click(
2385
+ within(second).getByRole('button', {name: 'Dismiss notification'}),
2386
+ );
2387
+ });
2388
+ act(() => {
2389
+ completeExit(second.dataset.toastId ?? '');
2390
+ });
2391
+ // Nothing is left: no row comes back, and the landmark is gone.
2392
+ expect(document.querySelectorAll('[data-toast-id]')).toHaveLength(0);
2393
+ expect(screen.queryByRole('region', {name: 'Notifications'})).toBeNull();
2394
+ });
2395
+
2396
+ it('reports the namesake once when one handler shows a repeat and dismisses the namesake', () => {
2397
+ const onHide = vi.fn();
2398
+ function RepeatAndDismiss() {
2399
+ const toast = useToast();
2400
+ const dismissFirstRef = useRef<(() => void) | null>(null);
2401
+ return (
2402
+ <>
2403
+ <button
2404
+ type="button"
2405
+ onClick={() => {
2406
+ dismissFirstRef.current = toast({
2407
+ uniqueID: 'offline',
2408
+ isAutoHide: false,
2409
+ body: 'Offline',
2410
+ onHide,
2411
+ });
2412
+ }}>
2413
+ Show first
2414
+ </button>
2415
+ <button
2416
+ type="button"
2417
+ onClick={() => {
2418
+ toast({
2419
+ uniqueID: 'offline',
2420
+ isAutoHide: false,
2421
+ body: 'Still offline',
2422
+ });
2423
+ dismissFirstRef.current?.();
2424
+ }}>
2425
+ Repeat and dismiss
2426
+ </button>
2427
+ </>
2428
+ );
2429
+ }
2430
+ render(
2431
+ <ToastViewport isTopLayer={false}>
2432
+ <RepeatAndDismiss />
2433
+ </ToastViewport>,
2434
+ );
2435
+ act(() => {
2436
+ fireEvent.click(screen.getByText('Show first'));
2437
+ });
2438
+ act(() => {
2439
+ fireEvent.click(screen.getByText('Repeat and dismiss'));
2440
+ });
2441
+ // As on `main`: the repeat replaces its namesake in place, and the
2442
+ // namesake's dismissal reports it once.
2443
+ expect(onHide).toHaveBeenCalledTimes(1);
2444
+ const rows = [...document.querySelectorAll('[data-toast-id]')];
2445
+ expect(rows).toHaveLength(1);
2446
+ expect(rows[0].textContent).toContain('Still offline');
2447
+ });
2448
+
2449
+ it('leaves no row behind when one handler raises a toast at the cap and dismisses the one it pushed out', () => {
2450
+ const onHide = vi.fn();
2451
+ function UndoFlow() {
2452
+ const toast = useToast();
2453
+ const dismissDeletedRef = useRef<(() => void) | null>(null);
2454
+ return (
2455
+ <>
2456
+ <button
2457
+ type="button"
2458
+ onClick={() => {
2459
+ dismissDeletedRef.current = toast({
2460
+ isAutoHide: false,
2461
+ body: 'Deleted',
2462
+ onHide,
2463
+ });
2464
+ }}>
2465
+ Delete
2466
+ </button>
2467
+ <button
2468
+ type="button"
2469
+ onClick={() => {
2470
+ // An undo shows its confirmation, then dismisses its own toast.
2471
+ toast({isAutoHide: false, body: 'Restored'});
2472
+ dismissDeletedRef.current?.();
2473
+ }}>
2474
+ Undo
2475
+ </button>
2476
+ </>
2477
+ );
2478
+ }
2479
+ render(
2480
+ <ToastViewport isTopLayer={false} maxVisible={1}>
2481
+ <UndoFlow />
2482
+ </ToastViewport>,
2483
+ );
2484
+ act(() => {
2485
+ fireEvent.click(screen.getByText('Delete'));
2486
+ });
2487
+ act(() => {
2488
+ fireEvent.click(screen.getByText('Undo'));
2489
+ });
2490
+ expect(onHide).toHaveBeenCalledTimes(1);
2491
+ const restored = getToastWrapperByText('Restored');
2492
+ act(() => {
2493
+ fireEvent.click(
2494
+ within(restored).getByRole('button', {name: 'Dismiss notification'}),
2495
+ );
2496
+ });
2497
+ act(() => {
2498
+ completeExit(restored.dataset.toastId ?? '');
2499
+ });
2500
+ // Nothing is left: no row comes back, and the landmark is gone.
2501
+ expect(document.querySelectorAll('[data-toast-id]')).toHaveLength(0);
2502
+ expect(screen.queryByRole('region', {name: 'Notifications'})).toBeNull();
2503
+ });
2504
+
2505
+ it('reports a leaving toast once when it is dismissed again after a new toast pushed it out of view', () => {
2506
+ const onHide = vi.fn();
2507
+ function ShowPushDismiss() {
2508
+ const toast = useToast();
2509
+ const dismissFirstRef = useRef<(() => void) | null>(null);
2510
+ return (
2511
+ <>
2512
+ <button
2513
+ type="button"
2514
+ onClick={() => {
2515
+ dismissFirstRef.current = toast({
2516
+ isAutoHide: false,
2517
+ body: 'Saved',
2518
+ onHide,
2519
+ });
2520
+ }}>
2521
+ Show first
2522
+ </button>
2523
+ <button
2524
+ type="button"
2525
+ onClick={() => {
2526
+ toast({isAutoHide: false, body: 'Uploaded'});
2527
+ }}>
2528
+ Show second
2529
+ </button>
2530
+ <button type="button" onClick={() => dismissFirstRef.current?.()}>
2531
+ Dismiss first
2532
+ </button>
2533
+ </>
2534
+ );
2535
+ }
2536
+ render(
2537
+ <ToastViewport isTopLayer={false} maxVisible={1}>
2538
+ <ShowPushDismiss />
2539
+ </ToastViewport>,
2540
+ );
2541
+ act(() => {
2542
+ fireEvent.click(screen.getByText('Show first'));
2543
+ });
2544
+ // It starts leaving, and reports it.
2545
+ act(() => {
2546
+ fireEvent.click(screen.getByText('Dismiss first'));
2547
+ });
2548
+ expect(onHide).toHaveBeenCalledTimes(1);
2549
+ // A new toast takes the only visible slot: the leaving one leaves the list.
2550
+ act(() => {
2551
+ fireEvent.click(screen.getByText('Show second'));
2552
+ });
2553
+ // Its dismissal again reports nothing more.
2554
+ act(() => {
2555
+ fireEvent.click(screen.getByText('Dismiss first'));
2556
+ });
2557
+ expect(onHide).toHaveBeenCalledTimes(1);
2558
+ const rows = [...document.querySelectorAll('[data-toast-id]')];
2559
+ expect(rows).toHaveLength(1);
2560
+ expect(rows[0].textContent).toContain('Uploaded');
2561
+ });
2562
+
2563
+ it('reports nothing for a toast replaced before it rendered, however often one handler dismisses it', () => {
2564
+ const onHide = vi.fn();
2565
+ function ShowReplaceDismiss() {
2566
+ const toast = useToast();
2567
+ return (
2568
+ <button
2569
+ type="button"
2570
+ onClick={() => {
2571
+ const dismissFirst = toast({
2572
+ uniqueID: 'offline',
2573
+ isAutoHide: false,
2574
+ body: 'Offline',
2575
+ onHide,
2576
+ });
2577
+ toast({
2578
+ uniqueID: 'offline',
2579
+ isAutoHide: false,
2580
+ body: 'Still offline',
2581
+ });
2582
+ dismissFirst();
2583
+ dismissFirst();
2584
+ }}>
2585
+ Show, replace and dismiss
2586
+ </button>
2587
+ );
2588
+ }
2589
+ render(
2590
+ <ToastViewport isTopLayer={false}>
2591
+ <ShowReplaceDismiss />
2592
+ </ToastViewport>,
2593
+ );
2594
+ act(() => {
2595
+ fireEvent.click(screen.getByText('Show, replace and dismiss'));
2596
+ });
2597
+ // Toast.spec.md FR3: a toast replaced through uniqueID is not dismissed
2598
+ // and reports no onHide.
2599
+ expect(onHide).not.toHaveBeenCalled();
2600
+ const rows = [...document.querySelectorAll('[data-toast-id]')];
2601
+ expect(rows).toHaveLength(1);
2602
+ expect(rows[0].textContent).toContain('Still offline');
2603
+ });
2604
+
2605
+ it('replaces a leaving namesake in place under overwrite and announces it again', () => {
2606
+ renderViewport(
2607
+ <>
2608
+ <ShowToastButton
2609
+ options={{uniqueID: 'upload', isAutoHide: false, body: 'Upload 30%'}}
2610
+ triggerLabel="Show 1"
2611
+ />
2612
+ <ShowToastButton
2613
+ options={{uniqueID: 'upload', isAutoHide: false, body: 'Upload 31%'}}
2614
+ triggerLabel="Show 2"
2615
+ />
2616
+ </>,
2617
+ );
2618
+ act(() => {
2619
+ fireEvent.click(screen.getByText('Show 1'));
2620
+ });
2621
+ const first = getToastWrapperByText('Upload 30%');
2622
+ act(() => {
2623
+ fireEvent.click(
2624
+ within(first).getByRole('button', {name: 'Dismiss notification'}),
2625
+ );
2626
+ });
2627
+ // Toast.spec.md FR8: an overwrite replaces its namesake in place even
2628
+ // while it is leaving, and is announced again.
2629
+ act(() => {
2630
+ fireEvent.click(screen.getByText('Show 2'));
2631
+ });
2632
+ expect(announceSpy).toHaveBeenLastCalledWith('Upload 31%', 'polite');
2633
+ expect(screen.queryByText('Upload 30%')).toBeNull();
2634
+ const rows = [...document.querySelectorAll('[data-toast-id]')];
2635
+ expect(rows).toHaveLength(1);
2636
+ expect(rows[0].textContent).toContain('Upload 31%');
2637
+ });
2064
2638
  });
2065
2639
 
2066
2640
  describe('toast timer lifecycle (#3589)', () => {
@@ -2084,6 +2658,150 @@ describe('toast timer lifecycle (#3589)', () => {
2084
2658
  expect(onHide).toHaveBeenCalledTimes(1);
2085
2659
  });
2086
2660
 
2661
+ // spec:Toast FR2/AR3: each pause condition is held on its own, so one
2662
+ // ending never resumes the timer while another still holds.
2663
+ function showPausableToast(onHide: () => void) {
2664
+ renderViewport(
2665
+ <ShowToastButton
2666
+ options={{
2667
+ body: 'Held',
2668
+ autoHideDuration: 3000,
2669
+ endContent: <Button label="Undo" />,
2670
+ onHide,
2671
+ }}
2672
+ triggerLabel="Show held"
2673
+ />,
2674
+ );
2675
+ act(() => {
2676
+ fireEvent.click(screen.getByText('Show held'));
2677
+ });
2678
+ const viewport = screen.getByRole('region', {name: 'Notifications'});
2679
+ const card = within(viewport).getByText('Held').closest('[role="status"]');
2680
+ if (!(card instanceof HTMLElement)) {
2681
+ throw new Error('toast card not found');
2682
+ }
2683
+ return {card, action: within(card).getByRole('button', {name: 'Undo'})};
2684
+ }
2685
+
2686
+ it('keeps the timer paused while focus is inside after the pointer leaves', () => {
2687
+ vi.useFakeTimers();
2688
+ try {
2689
+ const onHide = vi.fn();
2690
+ const {card, action} = showPausableToast(onHide);
2691
+ act(() => {
2692
+ fireEvent.mouseEnter(card);
2693
+ });
2694
+ act(() => {
2695
+ action.focus();
2696
+ });
2697
+ act(() => {
2698
+ fireEvent.mouseLeave(card);
2699
+ });
2700
+ act(() => {
2701
+ vi.advanceTimersByTime(60_000);
2702
+ });
2703
+ expect(onHide).not.toHaveBeenCalled();
2704
+ // Focus leaving the card releases the last hold.
2705
+ act(() => {
2706
+ action.blur();
2707
+ });
2708
+ act(() => {
2709
+ vi.advanceTimersByTime(60_000);
2710
+ });
2711
+ expect(onHide).toHaveBeenCalledWith('auto');
2712
+ } finally {
2713
+ vi.useRealTimers();
2714
+ }
2715
+ });
2716
+
2717
+ it('keeps the timer paused while the pointer is over it after the window regains focus', () => {
2718
+ vi.useFakeTimers();
2719
+ try {
2720
+ const onHide = vi.fn();
2721
+ const {card} = showPausableToast(onHide);
2722
+ act(() => {
2723
+ fireEvent.blur(window);
2724
+ });
2725
+ act(() => {
2726
+ fireEvent.mouseEnter(card);
2727
+ });
2728
+ act(() => {
2729
+ fireEvent.focus(window);
2730
+ });
2731
+ act(() => {
2732
+ vi.advanceTimersByTime(60_000);
2733
+ });
2734
+ expect(onHide).not.toHaveBeenCalled();
2735
+ act(() => {
2736
+ fireEvent.mouseLeave(card);
2737
+ });
2738
+ act(() => {
2739
+ vi.advanceTimersByTime(60_000);
2740
+ });
2741
+ expect(onHide).toHaveBeenCalledWith('auto');
2742
+ } finally {
2743
+ vi.useRealTimers();
2744
+ }
2745
+ });
2746
+
2747
+ it('releases the focus hold when the focused control is removed', () => {
2748
+ vi.useFakeTimers();
2749
+ try {
2750
+ const onHide = vi.fn();
2751
+ const {card, action} = showPausableToast(onHide);
2752
+ act(() => {
2753
+ fireEvent.mouseEnter(card);
2754
+ });
2755
+ act(() => {
2756
+ action.focus();
2757
+ });
2758
+ // A control that unmounts while focused fires no blur.
2759
+ act(() => {
2760
+ action.remove();
2761
+ });
2762
+ act(() => {
2763
+ fireEvent.mouseLeave(card);
2764
+ });
2765
+ act(() => {
2766
+ vi.advanceTimersByTime(60_000);
2767
+ });
2768
+ expect(onHide).toHaveBeenCalledWith('auto');
2769
+ } finally {
2770
+ vi.useRealTimers();
2771
+ }
2772
+ });
2773
+
2774
+ it('keeps the timer paused while focus moves between controls inside the card', () => {
2775
+ vi.useFakeTimers();
2776
+ try {
2777
+ const onHide = vi.fn();
2778
+ const {card, action} = showPausableToast(onHide);
2779
+ const dismiss = within(card)
2780
+ .getAllByRole('button')
2781
+ .find(button => button !== action);
2782
+ if (!dismiss) {
2783
+ throw new Error('dismiss button not found');
2784
+ }
2785
+ act(() => {
2786
+ action.focus();
2787
+ });
2788
+ act(() => {
2789
+ vi.advanceTimersByTime(2_000);
2790
+ });
2791
+ act(() => {
2792
+ dismiss.focus();
2793
+ });
2794
+ // Moving between the card's own controls neither restarts nor resumes
2795
+ // the timer.
2796
+ act(() => {
2797
+ vi.advanceTimersByTime(60_000);
2798
+ });
2799
+ expect(onHide).not.toHaveBeenCalled();
2800
+ } finally {
2801
+ vi.useRealTimers();
2802
+ }
2803
+ });
2804
+
2087
2805
  it('keeps a window-blur pause alive when another toast arrives', () => {
2088
2806
  vi.useFakeTimers();
2089
2807
  try {