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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (559) hide show
  1. package/dist/AlertDialog/AlertDialog.d.ts +1 -1
  2. package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
  3. package/dist/AlertDialog/AlertDialog.js +5 -5
  4. package/dist/Avatar/Avatar.d.ts.map +1 -1
  5. package/dist/Avatar/Avatar.js +12 -3
  6. package/dist/Badge/Badge.d.ts.map +1 -1
  7. package/dist/Badge/Badge.js +7 -1
  8. package/dist/BottomSheet/BottomSheet.js +1 -1
  9. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
  10. package/dist/BottomSheet/BottomSheetPanel.js +2 -1
  11. package/dist/BottomSheet/useSheetGestures.d.ts +12 -0
  12. package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
  13. package/dist/BottomSheet/useSheetGestures.js +30 -3
  14. package/dist/Button/Button.js +4 -4
  15. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  16. package/dist/CheckboxInput/CheckboxInput.js +6 -5
  17. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  18. package/dist/ClickableCard/ClickableCard.js +37 -4
  19. package/dist/DateInput/DateInput.d.ts.map +1 -1
  20. package/dist/DateInput/DateInput.js +12 -4
  21. package/dist/DateInput/MonthScroller.d.ts.map +1 -1
  22. package/dist/DateInput/MonthScroller.js +101 -15
  23. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  24. package/dist/DateInput/TouchDateField.js +8 -3
  25. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  26. package/dist/DateRangeInput/DateRangeInput.js +1 -1
  27. package/dist/DateTimeInput/DateTimeInput.d.ts +5 -2
  28. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  29. package/dist/DateTimeInput/DateTimeInput.js +23 -12
  30. package/dist/DateTimeInput/NativeTimeSegment.d.ts.map +1 -1
  31. package/dist/DateTimeInput/NativeTimeSegment.js +5 -4
  32. package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
  33. package/dist/DateTimeInput/TouchDateTimeField.js +4 -3
  34. package/dist/Dialog/Dialog.d.ts.map +1 -1
  35. package/dist/Dialog/Dialog.js +34 -9
  36. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  37. package/dist/Dialog/DialogHeader.js +5 -4
  38. package/dist/Divider/Divider.d.ts.map +1 -1
  39. package/dist/Divider/Divider.js +2 -1
  40. package/dist/Drawer/Drawer.d.ts +1 -0
  41. package/dist/Drawer/Drawer.d.ts.map +1 -1
  42. package/dist/Drawer/Drawer.js +7 -2
  43. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  44. package/dist/DropdownMenu/DropdownMenu.js +7 -3
  45. package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts.map +1 -1
  46. package/dist/DropdownMenu/MenuBottomSheetActionList.js +6 -5
  47. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts +20 -2
  48. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts.map +1 -1
  49. package/dist/DropdownMenu/lazyMenuBottomSheet.js +31 -3
  50. package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
  51. package/dist/DropdownMenu/renderDropdownItems.js +21 -16
  52. package/dist/EmptyState/EmptyState.d.ts.map +1 -1
  53. package/dist/EmptyState/EmptyState.js +2 -1
  54. package/dist/Field/FieldLabel.d.ts +1 -1
  55. package/dist/Field/FieldLabel.d.ts.map +1 -1
  56. package/dist/Field/FieldLabel.js +4 -4
  57. package/dist/Field/InputClearButton.js +3 -3
  58. package/dist/Field/PanelSearchInput.js +2 -2
  59. package/dist/FieldStatus/FieldStatus.js +2 -2
  60. package/dist/FileInput/FileInput.d.ts.map +1 -1
  61. package/dist/FileInput/FileInput.js +7 -1
  62. package/dist/Heading/Heading.js +1 -1
  63. package/dist/Icon/Icon.js +1 -1
  64. package/dist/Indicator/CheckIndicator.d.ts.map +1 -1
  65. package/dist/Indicator/CheckIndicator.js +2 -1
  66. package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -1
  67. package/dist/Indicator/CheckboxIndicator.js +3 -1
  68. package/dist/Indicator/RadioIndicator.d.ts.map +1 -1
  69. package/dist/Indicator/RadioIndicator.js +3 -1
  70. package/dist/Item/Item.d.ts.map +1 -1
  71. package/dist/Item/Item.js +2 -1
  72. package/dist/Item/ItemSwipeLayer.js +1 -1
  73. package/dist/Layer/popoverOperations.d.ts +27 -0
  74. package/dist/Layer/popoverOperations.d.ts.map +1 -0
  75. package/dist/Layer/popoverOperations.js +159 -0
  76. package/dist/Layer/useLayer.d.ts +1 -1
  77. package/dist/Layer/useLayer.d.ts.map +1 -1
  78. package/dist/Layer/useLayer.js +93 -59
  79. package/dist/Layout/Layout.js +1 -1
  80. package/dist/Layout/LayoutContent.js +1 -1
  81. package/dist/Layout/LayoutFooter.js +1 -1
  82. package/dist/Layout/LayoutHeader.js +1 -1
  83. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  84. package/dist/Lightbox/Lightbox.js +5 -0
  85. package/dist/Lightbox/LightboxViewport.a11y.browser.spec.js +5 -4
  86. package/dist/List/List.js +1 -1
  87. package/dist/List/ListItem.js +3 -3
  88. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  89. package/dist/MobileNav/MobileNav.js +7 -2
  90. package/dist/MultiSelector/CreateRow.a11y.chromium.spec.js +7 -6
  91. package/dist/MultiSelector/MultiSelector.d.ts +1 -1
  92. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  93. package/dist/MultiSelector/MultiSelector.js +26 -10
  94. package/dist/NumberInput/NumberInput.d.ts +3 -1
  95. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  96. package/dist/NumberInput/NumberInput.js +3 -3
  97. package/dist/NumberInput/numberParser.d.ts +3 -0
  98. package/dist/NumberInput/numberParser.d.ts.map +1 -1
  99. package/dist/NumberInput/numberParser.js +7 -44
  100. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  101. package/dist/ProgressBar/ProgressBar.js +16 -12
  102. package/dist/Resizable/useResizable.d.ts.map +1 -1
  103. package/dist/Resizable/useResizable.js +28 -2
  104. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  105. package/dist/SegmentedControl/SegmentedControlItem.js +4 -1
  106. package/dist/Selector/useSelectorPresentation.d.ts +8 -1
  107. package/dist/Selector/useSelectorPresentation.d.ts.map +1 -1
  108. package/dist/Selector/useSelectorPresentation.js +20 -4
  109. package/dist/Skeleton/Skeleton.d.ts.map +1 -1
  110. package/dist/Skeleton/Skeleton.js +1 -1
  111. package/dist/Slider/Slider.d.ts.map +1 -1
  112. package/dist/Slider/Slider.js +10 -2
  113. package/dist/Spinner/Spinner.d.ts.map +1 -1
  114. package/dist/Spinner/Spinner.js +3 -3
  115. package/dist/Stack/Stack.js +1 -1
  116. package/dist/Stack/StackItem.js +1 -1
  117. package/dist/TabList/TabList.d.ts.map +1 -1
  118. package/dist/TabList/TabList.js +16 -1
  119. package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
  120. package/dist/Table/plugins/columnResize/useTableColumnResize.js +9 -1
  121. package/dist/Text/Text.js +1 -1
  122. package/dist/Text/useTruncation.d.ts.map +1 -1
  123. package/dist/Text/useTruncation.js +23 -5
  124. package/dist/TextArea/TextArea.d.ts +1 -1
  125. package/dist/TextArea/TextArea.d.ts.map +1 -1
  126. package/dist/TextArea/TextArea.js +13 -2
  127. package/dist/TextInput/TextInput.d.ts.map +1 -1
  128. package/dist/TextInput/TextInput.js +3 -3
  129. package/dist/TimeInput/TimeInput.d.ts +6 -2
  130. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  131. package/dist/TimeInput/TimeInput.js +21 -14
  132. package/dist/TimeInput/TouchTimeField.d.ts.map +1 -1
  133. package/dist/TimeInput/TouchTimeField.js +5 -4
  134. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  135. package/dist/Timestamp/Timestamp.js +2 -2
  136. package/dist/Timestamp/TimestampHoverCard.js +4 -4
  137. package/dist/Toast/Toast.d.ts.map +1 -1
  138. package/dist/Toast/Toast.js +60 -20
  139. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  140. package/dist/Toast/ToastViewport.js +82 -51
  141. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  142. package/dist/Tokenizer/Tokenizer.js +13 -2
  143. package/dist/Tokenizer/TokenizerBottomSheet.js +3 -3
  144. package/dist/Toolbar/Toolbar.d.ts.map +1 -1
  145. package/dist/Toolbar/Toolbar.js +2 -1
  146. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  147. package/dist/TopNav/TopNavMegaMenu.js +3 -0
  148. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  149. package/dist/TopNav/TopNavMenu.js +1 -0
  150. package/dist/Typeahead/Typeahead.d.ts +1 -1
  151. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  152. package/dist/Typeahead/Typeahead.js +9 -1
  153. package/dist/astryx.css +20 -4
  154. package/dist/gestures/GestureArena.d.ts +6 -0
  155. package/dist/gestures/GestureArena.d.ts.map +1 -1
  156. package/dist/gestures/GestureArena.js +39 -0
  157. package/dist/gestures/GestureHost.d.ts +352 -0
  158. package/dist/gestures/GestureHost.d.ts.map +1 -0
  159. package/dist/gestures/GestureHost.js +1773 -0
  160. package/dist/gestures/GestureRecognizer.d.ts +10 -0
  161. package/dist/gestures/GestureRecognizer.d.ts.map +1 -1
  162. package/dist/gestures/GestureRecognizer.js +16 -0
  163. package/dist/gestures/LongPressGestureRecognizer.d.ts +1 -0
  164. package/dist/gestures/LongPressGestureRecognizer.d.ts.map +1 -1
  165. package/dist/gestures/LongPressGestureRecognizer.js +3 -0
  166. package/dist/gestures/PanGestureRecognizer.d.ts +1 -0
  167. package/dist/gestures/PanGestureRecognizer.d.ts.map +1 -1
  168. package/dist/gestures/PanGestureRecognizer.js +3 -0
  169. package/dist/gestures/PinchGestureRecognizer.d.ts +31 -0
  170. package/dist/gestures/PinchGestureRecognizer.d.ts.map +1 -0
  171. package/dist/gestures/PinchGestureRecognizer.js +128 -0
  172. package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts +71 -0
  173. package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts.map +1 -0
  174. package/dist/gestures/ScreenEdgePanGestureRecognizer.js +223 -0
  175. package/dist/gestures/SwipeGestureRecognizer.d.ts +37 -0
  176. package/dist/gestures/SwipeGestureRecognizer.d.ts.map +1 -0
  177. package/dist/gestures/SwipeGestureRecognizer.js +148 -0
  178. package/dist/gestures/TapGestureRecognizer.d.ts +1 -0
  179. package/dist/gestures/TapGestureRecognizer.d.ts.map +1 -1
  180. package/dist/gestures/TapGestureRecognizer.js +3 -0
  181. package/dist/gestures/VelocityTracker.d.ts +6 -2
  182. package/dist/gestures/VelocityTracker.d.ts.map +1 -1
  183. package/dist/gestures/VelocityTracker.js +7 -3
  184. package/dist/gestures/haptics.d.ts +65 -0
  185. package/dist/gestures/haptics.d.ts.map +1 -0
  186. package/dist/gestures/haptics.js +182 -0
  187. package/dist/gestures/nativeScroll.d.ts +42 -0
  188. package/dist/gestures/nativeScroll.d.ts.map +1 -0
  189. package/dist/gestures/nativeScroll.js +228 -0
  190. package/dist/gestures/touchAction.d.ts +60 -0
  191. package/dist/gestures/touchAction.d.ts.map +1 -0
  192. package/dist/gestures/touchAction.js +157 -0
  193. package/dist/gestures/touchActionRule.d.ts +34 -0
  194. package/dist/gestures/touchActionRule.d.ts.map +1 -0
  195. package/dist/gestures/touchActionRule.js +140 -0
  196. package/dist/gestures/types.d.ts +18 -7
  197. package/dist/gestures/types.d.ts.map +1 -1
  198. package/dist/gestures/types.js +22 -2
  199. package/dist/hooks/index.d.ts +1 -1
  200. package/dist/hooks/index.d.ts.map +1 -1
  201. package/dist/hooks/modalAnnounce.d.ts.map +1 -1
  202. package/dist/hooks/modalAnnounce.js +107 -61
  203. package/dist/hooks/useAdaptivePresentation.d.ts.map +1 -1
  204. package/dist/hooks/useAdaptivePresentation.js +4 -1
  205. package/dist/hooks/useAnnounce.d.ts +101 -42
  206. package/dist/hooks/useAnnounce.d.ts.map +1 -1
  207. package/dist/hooks/useAnnounce.js +161 -75
  208. package/dist/hooks/useAnnounceRenderedText.d.ts +11 -3
  209. package/dist/hooks/useAnnounceRenderedText.d.ts.map +1 -1
  210. package/dist/hooks/useAnnounceRenderedText.js +5 -3
  211. package/dist/hooks/useBusyAnnouncement.d.ts.map +1 -1
  212. package/dist/hooks/useBusyAnnouncement.js +6 -12
  213. package/dist/hooks/useMenuHover.d.ts.map +1 -1
  214. package/dist/hooks/useMenuHover.js +12 -1
  215. package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
  216. package/dist/i18n/generated-locales/en.generated.js +5 -0
  217. package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
  218. package/dist/i18n/generated-locales/pseudo.generated.js +5 -0
  219. package/dist/motion/animator.d.ts +7 -1
  220. package/dist/motion/animator.d.ts.map +1 -1
  221. package/dist/motion/animator.js +119 -27
  222. package/dist/theme/defineTheme.d.ts +19 -5
  223. package/dist/theme/defineTheme.d.ts.map +1 -1
  224. package/dist/theme/defineTheme.js +64 -4
  225. package/dist/theme/domainTokens/domainTokenDefaults.d.ts +3 -0
  226. package/dist/theme/domainTokens/domainTokenDefaults.d.ts.map +1 -0
  227. package/dist/theme/domainTokens/domainTokenDefaults.js +19 -0
  228. package/dist/theme/domainTokens/index.d.ts +5 -4
  229. package/dist/theme/domainTokens/index.d.ts.map +1 -1
  230. package/dist/theme/domainTokens/index.js +5 -9
  231. package/dist/theme/index.d.ts +1 -0
  232. package/dist/theme/index.d.ts.map +1 -1
  233. package/dist/theme/motionKnobs.d.ts +56 -0
  234. package/dist/theme/motionKnobs.d.ts.map +1 -0
  235. package/dist/theme/motionKnobs.js +48 -0
  236. package/dist/theme/resolveThemeValues.d.ts +11 -4
  237. package/dist/theme/resolveThemeValues.d.ts.map +1 -1
  238. package/dist/theme/resolveThemeValues.js +40 -4
  239. package/dist/theme/themeAdaptations.d.ts +7 -3
  240. package/dist/theme/themeAdaptations.d.ts.map +1 -1
  241. package/dist/theme/themeAdaptations.js +36 -7
  242. package/dist/theme/themeMotion.d.ts +96 -0
  243. package/dist/theme/themeMotion.d.ts.map +1 -0
  244. package/dist/theme/themeMotion.js +177 -0
  245. package/dist/theme/tokenReferences.d.ts +31 -0
  246. package/dist/theme/tokenReferences.d.ts.map +1 -0
  247. package/dist/theme/tokenReferences.js +132 -0
  248. package/dist/theme/tokens.d.ts +1 -0
  249. package/dist/theme/tokens.d.ts.map +1 -1
  250. package/dist/theme/tokens.js +9 -129
  251. package/dist/theme/tokens.stylex.d.ts +12 -0
  252. package/dist/theme/tokens.stylex.d.ts.map +1 -1
  253. package/dist/theme/tokens.stylex.js +12 -0
  254. package/dist/utils/focusReturn.d.ts +17 -1
  255. package/dist/utils/focusReturn.d.ts.map +1 -1
  256. package/dist/utils/focusReturn.js +11 -4
  257. package/dist/utils/getNodeText.d.ts +8 -0
  258. package/dist/utils/getNodeText.d.ts.map +1 -0
  259. package/dist/utils/getNodeText.js +37 -0
  260. package/dist/utils/interactionModality.d.ts +11 -2
  261. package/dist/utils/interactionModality.d.ts.map +1 -1
  262. package/dist/utils/interactionModality.js +58 -5
  263. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
  264. package/dist/utils/interactionOverlay.stylex.js +17 -8
  265. package/dist/utils/plainDate.d.ts +2 -0
  266. package/dist/utils/plainDate.d.ts.map +1 -1
  267. package/dist/utils/plainDate.js +46 -3
  268. package/dist/utils/presentation.d.ts +50 -0
  269. package/dist/utils/presentation.d.ts.map +1 -0
  270. package/dist/utils/presentation.js +125 -0
  271. package/dist/utils/pressFeedback.d.ts.map +1 -1
  272. package/dist/utils/pressFeedback.js +20 -1
  273. package/dist/utils/primaryClick.d.ts +11 -0
  274. package/dist/utils/primaryClick.d.ts.map +1 -0
  275. package/dist/utils/primaryClick.js +25 -0
  276. package/dist/utils/timeFormat.d.ts +47 -0
  277. package/dist/utils/timeFormat.d.ts.map +1 -0
  278. package/dist/utils/timeFormat.js +240 -0
  279. package/dist/utils/touchPresentation.d.ts.map +1 -1
  280. package/dist/utils/touchPresentation.js +5 -3
  281. package/dist/utils/touchPresentation.stylex.d.ts +15 -0
  282. package/dist/utils/touchPresentation.stylex.d.ts.map +1 -0
  283. package/dist/utils/touchPresentation.stylex.js +33 -0
  284. package/dist/utils/unicodeDigits.d.ts +20 -0
  285. package/dist/utils/unicodeDigits.d.ts.map +1 -0
  286. package/dist/utils/unicodeDigits.js +70 -0
  287. package/locales/en.json +23 -3
  288. package/locales/pseudo.json +15 -0
  289. package/package.json +5 -4
  290. package/src/AlertDialog/AlertDialog.tsx +6 -5
  291. package/src/AlertDialog/__tests__/AlertDialog.a11y.chromium.spec.ts +18 -6
  292. package/src/Avatar/Avatar.spec.md +22 -22
  293. package/src/Avatar/Avatar.tsx +18 -1
  294. package/src/Avatar/__tests__/AvatarForcedColors.a11y.chromium.spec.ts +126 -0
  295. package/src/Badge/Badge.doc.mjs +1 -1
  296. package/src/Badge/Badge.tsx +19 -2
  297. package/src/Badge/__tests__/BadgeLargerText.a11y.chromium.spec.ts +260 -0
  298. package/src/BottomSheet/BottomSheet.test.tsx +46 -0
  299. package/src/BottomSheet/BottomSheet.tsx +1 -1
  300. package/src/BottomSheet/BottomSheetPanel.tsx +2 -1
  301. package/src/BottomSheet/useSheetGestures.test.ts +52 -0
  302. package/src/BottomSheet/useSheetGestures.ts +37 -6
  303. package/src/Breadcrumbs/__tests__/Breadcrumbs.a11y.chromium.spec.ts +18 -6
  304. package/src/Button/Button.tsx +4 -4
  305. package/src/Calendar/Calendar.spec.md +87 -48
  306. package/src/Calendar/__tests__/Calendar.a11y.chromium.spec.ts +21 -7
  307. package/src/Carousel/__tests__/Carousel.a11y.chromium.spec.ts +21 -7
  308. package/src/CheckboxInput/CheckboxInput.tsx +6 -5
  309. package/src/ClickableCard/ClickableCard.test.tsx +96 -0
  310. package/src/ClickableCard/ClickableCard.tsx +48 -4
  311. package/src/Collapsible/Collapsible.spec.md +2 -0
  312. package/src/Collapsible/CollapsibleGroup.spec.md +57 -29
  313. package/src/Collapsible/__tests__/Collapsible.a11y.chromium.spec.ts +18 -7
  314. package/src/Collapsible/__tests__/CollapsibleGroupAccordion.a11y.chromium.spec.ts +18 -6
  315. package/src/ComplexSelector/ComplexSelector.test.tsx +37 -0
  316. package/src/ContextMenu/ContextMenu.test.tsx +35 -0
  317. package/src/DateInput/DateInput.test.tsx +115 -3
  318. package/src/DateInput/DateInput.tsx +29 -14
  319. package/src/DateInput/DateInputTouch.test.tsx +76 -0
  320. package/src/DateInput/MonthScroller.tsx +106 -20
  321. package/src/DateInput/MonthScrollerSettle.test.tsx +165 -0
  322. package/src/DateInput/TouchDateField.tsx +14 -3
  323. package/src/DateInput/__tests__/MonthScrollerSteps.interaction.browser.spec.ts +312 -0
  324. package/src/DateRangeInput/DateRangeInput.test.tsx +46 -3
  325. package/src/DateRangeInput/DateRangeInput.tsx +16 -12
  326. package/src/DateTimeInput/DateTimeInput.doc.mjs +10 -8
  327. package/src/DateTimeInput/DateTimeInput.spec.md +75 -51
  328. package/src/DateTimeInput/DateTimeInput.test.tsx +81 -0
  329. package/src/DateTimeInput/DateTimeInput.tsx +46 -24
  330. package/src/DateTimeInput/NativeTimeSegment.tsx +4 -6
  331. package/src/DateTimeInput/TouchDateTimeField.tsx +3 -7
  332. package/src/Dialog/Dialog.test.tsx +216 -2
  333. package/src/Dialog/Dialog.tsx +42 -9
  334. package/src/Dialog/DialogHeader.tsx +5 -4
  335. package/src/Dialog/__tests__/DialogSecondDocument.a11y.browser.spec.ts +202 -0
  336. package/src/Divider/Divider.tsx +2 -1
  337. package/src/Drawer/Drawer.spec.md +111 -80
  338. package/src/Drawer/Drawer.test.tsx +35 -0
  339. package/src/Drawer/Drawer.tsx +13 -2
  340. package/src/Drawer/DrawerHeader.spec.md +181 -0
  341. package/src/Drawer/__tests__/DrawerNonModalPageScroll.a11y.chromium.spec.ts +267 -0
  342. package/src/DropdownMenu/DropdownMenu.test.tsx +41 -0
  343. package/src/DropdownMenu/DropdownMenu.tsx +10 -3
  344. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +34 -0
  345. package/src/DropdownMenu/MenuBottomSheetActionList.tsx +6 -5
  346. package/src/DropdownMenu/__tests__/Menu.a11y.chromium.spec.ts +19 -7
  347. package/src/DropdownMenu/__tests__/MenuButton.a11y.chromium.spec.ts +21 -9
  348. package/src/DropdownMenu/lazyMenuBottomSheet.test.ts +60 -0
  349. package/src/DropdownMenu/lazyMenuBottomSheet.ts +36 -7
  350. package/src/DropdownMenu/renderDropdownItems.tsx +24 -19
  351. package/src/EmptyState/EmptyState.tsx +2 -1
  352. package/src/Field/FieldLabel.tsx +5 -4
  353. package/src/Field/InputClearButton.tsx +3 -3
  354. package/src/Field/PanelSearchInput.tsx +2 -2
  355. package/src/FieldStatus/FieldStatus.tsx +2 -2
  356. package/src/FileInput/FileInput.test.tsx +21 -0
  357. package/src/FileInput/FileInput.tsx +4 -1
  358. package/src/FormLayout/FormLayout.spec.md +7 -8
  359. package/src/Heading/Heading.tsx +1 -1
  360. package/src/Icon/Icon.tsx +1 -1
  361. package/src/Indicator/CheckIndicator.spec.md +47 -42
  362. package/src/Indicator/CheckIndicator.tsx +2 -1
  363. package/src/Indicator/CheckboxIndicator.spec.md +40 -37
  364. package/src/Indicator/CheckboxIndicator.tsx +3 -1
  365. package/src/Indicator/Indicator.spec.md +188 -0
  366. package/src/Indicator/RadioIndicator.tsx +3 -1
  367. package/src/Item/Item.tsx +2 -1
  368. package/src/Item/ItemSwipeLayer.tsx +1 -1
  369. package/src/Kbd/Kbd.spec.md +81 -38
  370. package/src/Layer/__tests__/LayerBrowserHide.a11y.chromium.spec.ts +126 -0
  371. package/src/Layer/popoverOperations.test.ts +205 -0
  372. package/src/Layer/popoverOperations.ts +172 -0
  373. package/src/Layer/useLayer.test.tsx +348 -1
  374. package/src/Layer/useLayer.tsx +118 -71
  375. package/src/Layout/Layout.spec.md +127 -131
  376. package/src/Layout/Layout.tsx +1 -1
  377. package/src/Layout/LayoutContent.spec.md +205 -0
  378. package/src/Layout/LayoutContent.tsx +1 -1
  379. package/src/Layout/LayoutFooter.spec.md +190 -0
  380. package/src/Layout/LayoutFooter.tsx +1 -1
  381. package/src/Layout/LayoutHeader.spec.md +193 -0
  382. package/src/Layout/LayoutHeader.tsx +1 -1
  383. package/src/Layout/LayoutPanel.spec.md +194 -0
  384. package/src/Layout/__tests__/Layout.a11y.chromium.spec.ts +18 -6
  385. package/src/Lightbox/Lightbox.test.tsx +18 -0
  386. package/src/Lightbox/Lightbox.tsx +5 -0
  387. package/src/Lightbox/LightboxViewport.a11y.browser.spec.ts +8 -4
  388. package/src/Link/__tests__/Link.a11y.chromium.spec.ts +18 -8
  389. package/src/List/List.tsx +1 -1
  390. package/src/List/ListItem.spec.md +205 -0
  391. package/src/List/ListItem.tsx +3 -3
  392. package/src/MetadataList/MetadataList.spec.md +187 -0
  393. package/src/MetadataList/MetadataListItem.spec.md +165 -0
  394. package/src/MobileNav/MobileNav.test.tsx +15 -0
  395. package/src/MobileNav/MobileNav.tsx +9 -1
  396. package/src/MobileNav/__tests__/MobileNavHeader.a11y.chromium.spec.ts +89 -0
  397. package/src/MoreMenu/MoreMenu.test.tsx +11 -0
  398. package/src/MultiSelector/CreateRow.a11y.chromium.spec.ts +7 -8
  399. package/src/MultiSelector/MultiSelector.spec.md +7 -4
  400. package/src/MultiSelector/MultiSelector.test.tsx +270 -1
  401. package/src/MultiSelector/MultiSelector.tsx +25 -10
  402. package/src/MultiSelector/__tests__/MultiSelector.listbox.a11y.test.tsx +8 -1
  403. package/src/NavMenu/NavHeadingMenu.spec.md +1 -5
  404. package/src/NumberInput/NumberInput.doc.mjs +13 -7
  405. package/src/NumberInput/NumberInput.spec.md +59 -37
  406. package/src/NumberInput/NumberInput.tsx +13 -3
  407. package/src/NumberInput/__tests__/NumberInput.coarse-pointer.a11y.chromium.spec.ts +102 -0
  408. package/src/NumberInput/numberParser.ts +7 -45
  409. package/src/ProgressBar/ProgressBar.test.tsx +108 -32
  410. package/src/ProgressBar/ProgressBar.tsx +58 -10
  411. package/src/ProgressBar/__tests__/ProgressBar.a11y.chromium.spec.ts +21 -9
  412. package/src/ProgressBar/__tests__/ProgressBarMotion.a11y.chromium.spec.ts +831 -0
  413. package/src/Resizable/__tests__/ResizeHandle.a11y.chromium.spec.ts +21 -14
  414. package/src/Resizable/useResizable.test.ts +43 -0
  415. package/src/Resizable/useResizable.ts +32 -9
  416. package/src/SegmentedControl/SegmentedControl.test.tsx +84 -0
  417. package/src/SegmentedControl/SegmentedControlItem.tsx +11 -5
  418. package/src/Selector/Selector.test.tsx +90 -1
  419. package/src/Selector/__tests__/Selector.combobox.a11y.test.tsx +8 -1
  420. package/src/Selector/__tests__/Selector.listbox.a11y.test.tsx +8 -1
  421. package/src/Selector/useSelectorPresentation.ts +31 -3
  422. package/src/SideNav/SideNav.test.tsx +27 -0
  423. package/src/SideNav/__tests__/SideNavRailMotion.interaction.browser.spec.ts +176 -51
  424. package/src/Skeleton/Skeleton.tsx +3 -1
  425. package/src/Slider/Slider.test.tsx +31 -0
  426. package/src/Slider/Slider.tsx +8 -3
  427. package/src/Slider/__tests__/Slider.a11y.chromium.spec.ts +19 -7
  428. package/src/Spinner/Spinner.tsx +5 -3
  429. package/src/Stack/Stack.tsx +1 -1
  430. package/src/Stack/StackItem.tsx +1 -1
  431. package/src/TabList/TabList.test.tsx +58 -4
  432. package/src/TabList/TabList.tsx +16 -1
  433. package/src/TabList/__tests__/TabPressPointer.interaction.browser.spec.ts +163 -0
  434. package/src/Table/__tests__/Table.a11y.chromium.spec.ts +18 -6
  435. package/src/Table/plugins/columnResize/useTableColumnResize.test.tsx +22 -0
  436. package/src/Table/plugins/columnResize/useTableColumnResize.tsx +8 -4
  437. package/src/Text/Text.tsx +1 -1
  438. package/src/Text/useTruncation.test.tsx +128 -1
  439. package/src/Text/useTruncation.ts +23 -5
  440. package/src/TextArea/TextArea.spec.md +10 -13
  441. package/src/TextArea/TextArea.test.tsx +60 -0
  442. package/src/TextArea/TextArea.tsx +15 -1
  443. package/src/TextInput/TextInput.test.tsx +21 -0
  444. package/src/TextInput/TextInput.tsx +3 -1
  445. package/src/TimeInput/NativeTimeInput.test.tsx +17 -0
  446. package/src/TimeInput/Presentation.test.tsx +21 -0
  447. package/src/TimeInput/TimeInput.doc.mjs +8 -8
  448. package/src/TimeInput/TimeInput.spec.md +45 -48
  449. package/src/TimeInput/TimeInput.test.tsx +76 -0
  450. package/src/TimeInput/TimeInput.tsx +36 -18
  451. package/src/TimeInput/TouchTimeField.tsx +4 -6
  452. package/src/Timestamp/Timestamp.spec.md +6 -12
  453. package/src/Timestamp/Timestamp.test.tsx +30 -5
  454. package/src/Timestamp/Timestamp.tsx +6 -2
  455. package/src/Timestamp/TimestampHoverCard.tsx +4 -4
  456. package/src/Toast/Toast.spec.md +14 -20
  457. package/src/Toast/Toast.tsx +104 -36
  458. package/src/Toast/ToastViewport.test.tsx +719 -1
  459. package/src/Toast/ToastViewport.tsx +100 -50
  460. package/src/Tokenizer/Tokenizer.spec.md +5 -3
  461. package/src/Tokenizer/Tokenizer.test.tsx +68 -0
  462. package/src/Tokenizer/Tokenizer.tsx +14 -2
  463. package/src/Tokenizer/TokenizerBottomSheet.test.tsx +15 -4
  464. package/src/Tokenizer/TokenizerBottomSheet.tsx +3 -3
  465. package/src/Toolbar/Toolbar.spec.md +5 -6
  466. package/src/Toolbar/Toolbar.test.tsx +30 -0
  467. package/src/Toolbar/Toolbar.tsx +2 -1
  468. package/src/Toolbar/__tests__/Toolbar.a11y.chromium.spec.ts +18 -6
  469. package/src/Tooltip/__tests__/Tooltip.a11y.chromium.spec.ts +18 -7
  470. package/src/TopNav/TopNav.test.tsx +27 -0
  471. package/src/TopNav/TopNavMegaMenu.test.tsx +21 -0
  472. package/src/TopNav/TopNavMegaMenu.tsx +4 -1
  473. package/src/TopNav/TopNavMenu.test.tsx +17 -0
  474. package/src/TopNav/TopNavMenu.tsx +1 -0
  475. package/src/Typeahead/Typeahead.test.tsx +40 -0
  476. package/src/Typeahead/Typeahead.tsx +12 -1
  477. package/src/__tests__/pressState.ts +8 -4
  478. package/src/gestures/GestureArena.ts +35 -0
  479. package/src/gestures/GestureHost.ts +2065 -0
  480. package/src/gestures/GestureRecognizer.ts +18 -0
  481. package/src/gestures/LongPressGestureRecognizer.ts +4 -0
  482. package/src/gestures/PanGestureRecognizer.ts +4 -0
  483. package/src/gestures/PinchGestureRecognizer.ts +148 -0
  484. package/src/gestures/ScreenEdgePanGestureRecognizer.ts +256 -0
  485. package/src/gestures/SwipeGestureRecognizer.ts +197 -0
  486. package/src/gestures/TapGestureRecognizer.ts +4 -0
  487. package/src/gestures/VelocityTracker.ts +10 -3
  488. package/src/gestures/__tests__/GestureHost.test.ts +2087 -0
  489. package/src/gestures/__tests__/PanGestureRecognizer.test.ts +4 -4
  490. package/src/gestures/__tests__/PinchGestureRecognizer.test.ts +74 -0
  491. package/src/gestures/__tests__/ScreenEdgePanGestureRecognizer.test.ts +498 -0
  492. package/src/gestures/__tests__/SwipeGestureRecognizer.test.ts +108 -0
  493. package/src/gestures/__tests__/arena.test.ts +5 -0
  494. package/src/gestures/__tests__/arenaPinchSwipeEdge.test.ts +193 -0
  495. package/src/gestures/__tests__/browser/build-fixture.mjs +46 -0
  496. package/src/gestures/__tests__/browser/fixture.ts +307 -0
  497. package/src/gestures/__tests__/browser/gestures.interaction.browser.spec.ts +1137 -0
  498. package/src/gestures/__tests__/browserNegotiation.test.ts +293 -0
  499. package/src/gestures/__tests__/haptics.test.ts +187 -0
  500. package/src/gestures/__tests__/harness.ts +21 -2
  501. package/src/gestures/__tests__/recognizerKind.test.ts +78 -0
  502. package/src/gestures/__tests__/touchActionRule.test.ts +54 -0
  503. package/src/gestures/haptics.ts +203 -0
  504. package/src/gestures/nativeScroll.ts +277 -0
  505. package/src/gestures/touchAction.ts +191 -0
  506. package/src/gestures/touchActionRule.ts +157 -0
  507. package/src/gestures/types.ts +30 -9
  508. package/src/hooks/index.ts +5 -1
  509. package/src/hooks/modalAnnounce.ts +129 -72
  510. package/src/hooks/useAdaptivePresentation.ts +4 -1
  511. package/src/hooks/useAnnounce.doc.mjs +35 -3
  512. package/src/hooks/useAnnounce.replace.test.tsx +516 -0
  513. package/src/hooks/useAnnounce.ts +209 -102
  514. package/src/hooks/useAnnounceRenderedText.adopters.test.tsx +10 -1
  515. package/src/hooks/useAnnounceRenderedText.ts +17 -3
  516. package/src/hooks/useBusyAnnouncement.ts +7 -10
  517. package/src/hooks/useMenuHover.ts +15 -1
  518. package/src/i18n/generated-locales/en.generated.ts +6 -0
  519. package/src/i18n/generated-locales/pseudo.generated.ts +6 -0
  520. package/src/motion/README.md +11 -1
  521. package/src/motion/animator.test.ts +151 -3
  522. package/src/motion/animator.ts +149 -33
  523. package/src/theme/Theme.doc.mjs +1 -1
  524. package/src/theme/defineTheme.ts +117 -8
  525. package/src/theme/derivedVarRegistry.test.ts +4 -0
  526. package/src/theme/domainTokens/domainTokenDefaults.ts +19 -0
  527. package/src/theme/domainTokens/index.ts +6 -10
  528. package/src/theme/expandMotionScale.test.ts +1 -1
  529. package/src/theme/index.ts +5 -0
  530. package/src/theme/motionKnobs.ts +82 -0
  531. package/src/theme/resolveThemeValues.ts +68 -6
  532. package/src/theme/themeAdaptations.ts +52 -12
  533. package/src/theme/themeMotion.test.ts +620 -0
  534. package/src/theme/themeMotion.ts +221 -0
  535. package/src/theme/tokenReferences.ts +149 -0
  536. package/src/theme/tokens.stylex.ts +10 -0
  537. package/src/theme/tokens.ts +15 -158
  538. package/src/utils/focusReturn.ts +17 -6
  539. package/src/utils/getNodeText.test.ts +24 -0
  540. package/src/utils/getNodeText.ts +37 -0
  541. package/src/utils/interactionModality.test.ts +45 -1
  542. package/src/utils/interactionModality.ts +64 -5
  543. package/src/utils/interactionOverlay.stylex.ts +12 -3
  544. package/src/utils/plainDate.test.ts +90 -0
  545. package/src/utils/plainDate.ts +58 -3
  546. package/src/utils/presentation.test.ts +380 -0
  547. package/src/utils/presentation.ts +180 -0
  548. package/src/utils/pressFeedback.test.ts +138 -0
  549. package/src/utils/pressFeedback.ts +34 -11
  550. package/src/utils/pressPaintPriority.test.ts +80 -0
  551. package/src/utils/primaryClick.test.ts +38 -0
  552. package/src/utils/primaryClick.ts +28 -0
  553. package/src/utils/timeFormat.test.ts +204 -0
  554. package/src/utils/timeFormat.ts +314 -0
  555. package/src/utils/touchPresentation.stylex.ts +43 -0
  556. package/src/utils/touchPresentation.test.ts +140 -1
  557. package/src/utils/touchPresentation.ts +5 -3
  558. package/src/utils/unicodeDigits.test.ts +44 -0
  559. package/src/utils/unicodeDigits.ts +71 -0
@@ -0,0 +1,516 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file useAnnounce.replace.test.tsx
5
+ * @input Uses vitest, Testing Library, useAnnounce, and an Astryx Dialog and
6
+ * BottomSheet
7
+ * @output Proof of spec:AST-086 FR9 and FR14 for `useAnnounce({hasReplace})`:
8
+ * each message such an instance writes withdraws its previous one while it
9
+ * is not yet exposed, whatever their urgencies, on the shared channel,
10
+ * inside an open modal and in the commit that presents one; messages from
11
+ * other instances, and from instances without `hasReplace`, still join; a
12
+ * share another instance holds stays; an exposed message is left alone, and
13
+ * taking it back later touches no other announcer's words, in a modal's
14
+ * container or held for its close; the instance's hold on its message
15
+ * follows the words when a modal hands them on (it leaves the
16
+ * accessibility tree, exits, closes, or a step is left) or its write frame
17
+ * finds it unexposed; an empty message clears
18
+ * @position Core a11y tests beside the hook
19
+ */
20
+
21
+ import {
22
+ act,
23
+ fireEvent,
24
+ render,
25
+ renderHook,
26
+ screen,
27
+ } from '@testing-library/react';
28
+ import {useEffect, useState} from 'react';
29
+ import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
30
+ import {BottomSheet} from '../BottomSheet/BottomSheet';
31
+ import {Dialog} from '../Dialog/Dialog';
32
+ import {__resetLiveRegionsForTest, useAnnounce} from './useAnnounce';
33
+
34
+ const shared = (politeness = 'polite') =>
35
+ document.querySelector(`[data-astryx-live-region="${politeness}"]`);
36
+ const regionIn = (dialog: Element, politeness = 'polite') =>
37
+ dialog.querySelector(
38
+ `:scope > [data-astryx-modal-live-region="${politeness}"]`,
39
+ );
40
+
41
+ async function nextFrame() {
42
+ await act(
43
+ async () =>
44
+ new Promise<void>(resolve => requestAnimationFrame(() => resolve())),
45
+ );
46
+ }
47
+
48
+ /** jsdom has no showModal(); stand in for a dialog opened modally. */
49
+ function stubDialogs() {
50
+ HTMLDialogElement.prototype.showModal = vi.fn(function (
51
+ this: HTMLDialogElement,
52
+ ) {
53
+ this.setAttribute('open', '');
54
+ this.dataset.modal = 'true';
55
+ });
56
+ HTMLDialogElement.prototype.close = vi.fn(function (this: HTMLDialogElement) {
57
+ this.removeAttribute('open');
58
+ delete this.dataset.modal;
59
+ this.dispatchEvent(new Event('close'));
60
+ });
61
+ const matches = Element.prototype.matches;
62
+ vi.spyOn(Element.prototype, 'matches').mockImplementation(function (
63
+ this: Element,
64
+ selector: string,
65
+ ) {
66
+ return selector === ':modal'
67
+ ? this instanceof HTMLDialogElement &&
68
+ this.open &&
69
+ this.dataset.modal === 'true'
70
+ : matches.call(this, selector);
71
+ });
72
+ }
73
+
74
+ const REPLACE = {hasReplace: true} as const;
75
+
76
+ beforeEach(() => {
77
+ __resetLiveRegionsForTest();
78
+ });
79
+ afterEach(() => {
80
+ vi.restoreAllMocks();
81
+ __resetLiveRegionsForTest();
82
+ });
83
+
84
+ describe('useAnnounce({hasReplace}) on the shared channel (spec:AST-086 FR9)', () => {
85
+ it('says only the latest of its messages written in one frame', async () => {
86
+ const {result} = renderHook(() => useAnnounce(REPLACE));
87
+ result.current('1 result');
88
+ result.current('Create "Urg"');
89
+ result.current('Create "Urgent"');
90
+ await nextFrame();
91
+ expect(shared()?.textContent).toBe('Create "Urgent"');
92
+ });
93
+
94
+ it('still joins another instance’s message written in the same frame', async () => {
95
+ const {result} = renderHook(() => ({
96
+ count: useAnnounce(REPLACE),
97
+ other: useAnnounce(),
98
+ }));
99
+ result.current.other('Filter applied');
100
+ result.current.count('3 results');
101
+ result.current.count('2 results');
102
+ await nextFrame();
103
+ expect(shared()?.textContent).toBe('Filter applied 2 results');
104
+ });
105
+
106
+ it('keeps joining the messages of an instance without hasReplace', async () => {
107
+ const {result} = renderHook(() => useAnnounce());
108
+ result.current('Added Design');
109
+ result.current('Removed Eng');
110
+ await nextFrame();
111
+ expect(shared()?.textContent).toBe('Added Design Removed Eng');
112
+ });
113
+
114
+ it('withdraws only its own share of words another instance also wrote', async () => {
115
+ const {result} = renderHook(() => ({
116
+ first: useAnnounce(REPLACE),
117
+ second: useAnnounce(REPLACE),
118
+ }));
119
+ result.current.first('1 result');
120
+ result.current.second('1 result');
121
+ result.current.first('2 results');
122
+ await nextFrame();
123
+ // The second instance still holds "1 result".
124
+ expect(shared()?.textContent).toBe('1 result 2 results');
125
+ });
126
+
127
+ it('leaves a message that was already exposed: the next one starts fresh', async () => {
128
+ const {result} = renderHook(() => useAnnounce(REPLACE));
129
+ result.current('1 result');
130
+ await nextFrame();
131
+ expect(shared()?.textContent).toBe('1 result');
132
+ result.current('2 results');
133
+ await nextFrame();
134
+ expect(shared()?.textContent).toBe('2 results');
135
+ });
136
+
137
+ it('leaves another announcer’s equal words written after its own message was exposed', async () => {
138
+ const {result} = renderHook(() => ({
139
+ count: useAnnounce(REPLACE),
140
+ other: useAnnounce(),
141
+ }));
142
+ result.current.count('1 result');
143
+ await nextFrame();
144
+ result.current.other('1 result');
145
+ result.current.count('2 results');
146
+ await nextFrame();
147
+ expect(shared()?.textContent).toBe('1 result 2 results');
148
+ });
149
+
150
+ it('withdraws its polite message for an assertive one, which is spoken in the assertive region', async () => {
151
+ const {result} = renderHook(() => useAnnounce(REPLACE));
152
+ result.current('3 results');
153
+ result.current('Search failed', 'assertive');
154
+ await nextFrame();
155
+ expect(shared('polite')?.textContent ?? '').toBe('');
156
+ expect(shared('assertive')?.textContent).toBe('Search failed');
157
+ });
158
+
159
+ it('clears the region on an empty message', async () => {
160
+ const {result} = renderHook(() => useAnnounce(REPLACE));
161
+ result.current('1 result');
162
+ await nextFrame();
163
+ result.current('');
164
+ await nextFrame();
165
+ expect(shared()?.textContent ?? '').toBe('');
166
+ });
167
+ });
168
+
169
+ describe('useAnnounce({hasReplace}) inside an Astryx modal (spec:AST-086 FR14)', () => {
170
+ beforeEach(() => {
171
+ stubDialogs();
172
+ });
173
+
174
+ function Typist({
175
+ messages,
176
+ }: {
177
+ messages: ReadonlyArray<readonly [string, 'polite' | 'assertive']>;
178
+ }) {
179
+ const announce = useAnnounce(REPLACE);
180
+ return (
181
+ <button
182
+ type="button"
183
+ onClick={() => {
184
+ for (const [message, politeness] of messages) {
185
+ announce(message, politeness);
186
+ }
187
+ }}>
188
+ Type
189
+ </button>
190
+ );
191
+ }
192
+
193
+ it('withdraws its unexposed message in the modal’s container', async () => {
194
+ render(
195
+ <Dialog isOpen onOpenChange={() => {}} aria-label="Modal">
196
+ <Typist
197
+ messages={[
198
+ ['1 result', 'polite'],
199
+ ['Create "Urgent"', 'polite'],
200
+ ]}
201
+ />
202
+ </Dialog>,
203
+ );
204
+ const dialog = screen.getByRole('dialog', {name: 'Modal'});
205
+ await nextFrame();
206
+ fireEvent.click(screen.getByRole('button', {name: 'Type'}));
207
+ await nextFrame();
208
+ expect(regionIn(dialog)?.textContent).toBe('Create "Urgent"');
209
+ expect(shared()?.textContent ?? '').toBe('');
210
+ });
211
+
212
+ it('withdraws across the modal’s two containers', async () => {
213
+ render(
214
+ <Dialog isOpen onOpenChange={() => {}} aria-label="Modal">
215
+ <Typist
216
+ messages={[
217
+ ['3 results', 'polite'],
218
+ ['Search failed', 'assertive'],
219
+ ]}
220
+ />
221
+ </Dialog>,
222
+ );
223
+ const dialog = screen.getByRole('dialog', {name: 'Modal'});
224
+ await nextFrame();
225
+ fireEvent.click(screen.getByRole('button', {name: 'Type'}));
226
+ await nextFrame();
227
+ expect(regionIn(dialog, 'polite')?.textContent ?? '').toBe('');
228
+ expect(regionIn(dialog, 'assertive')?.textContent).toBe('Search failed');
229
+ });
230
+
231
+ // A `hasReplace` count and a plain announcer that may say the same words.
232
+ function CountAndOther() {
233
+ const count = useAnnounce(REPLACE);
234
+ const other = useAnnounce();
235
+ return (
236
+ <>
237
+ <button type="button" onClick={() => count('1 result')}>
238
+ Count
239
+ </button>
240
+ <button type="button" onClick={() => count('2 results')}>
241
+ Recount
242
+ </button>
243
+ <button
244
+ type="button"
245
+ onClick={() => {
246
+ other('1 result');
247
+ count('1 result');
248
+ }}>
249
+ Both
250
+ </button>
251
+ <button
252
+ type="button"
253
+ onClick={() => {
254
+ other('1 result');
255
+ count('2 results');
256
+ }}>
257
+ Next
258
+ </button>
259
+ </>
260
+ );
261
+ }
262
+
263
+ it('leaves another announcer’s equal words in the container after its own message was exposed', async () => {
264
+ render(
265
+ <Dialog isOpen onOpenChange={() => {}} aria-label="Modal">
266
+ <CountAndOther />
267
+ </Dialog>,
268
+ );
269
+ const dialog = screen.getByRole('dialog', {name: 'Modal'});
270
+ await nextFrame();
271
+ fireEvent.click(screen.getByRole('button', {name: 'Count'}));
272
+ // Written, then taken by assistive technology a frame later.
273
+ await nextFrame();
274
+ await nextFrame();
275
+ expect(regionIn(dialog)?.textContent).toBe('1 result');
276
+ // The plain announcer's "1 result" is not the count's spoken one.
277
+ fireEvent.click(screen.getByRole('button', {name: 'Next'}));
278
+ await nextFrame();
279
+ expect(regionIn(dialog)?.textContent).toBe('1 result 2 results');
280
+ });
281
+
282
+ /** A sheet that runs its exit with the announcers inside it. */
283
+ function ExitingSheet() {
284
+ const [isOpen, setIsOpen] = useState(true);
285
+ return (
286
+ <BottomSheet isOpen={isOpen} onOpenChange={setIsOpen} label="Sheet">
287
+ <CountAndOther />
288
+ <button type="button" onClick={() => setIsOpen(false)}>
289
+ Done
290
+ </button>
291
+ </BottomSheet>
292
+ );
293
+ }
294
+
295
+ it('takes back only its own share of words held while its sheet exits', async () => {
296
+ render(<ExitingSheet />);
297
+ const sheet = document.querySelector<HTMLDialogElement>('dialog')!;
298
+ await nextFrame();
299
+ fireEvent.click(screen.getByRole('button', {name: 'Done'}));
300
+ // Open but inert and aria-hidden through its exit: the words are held
301
+ // for the real close (reach the controls by element).
302
+ expect(sheet).toHaveAttribute('inert');
303
+ fireEvent.click(screen.getByText('Both'));
304
+ fireEvent.click(screen.getByText('Next'));
305
+ act(() => {
306
+ sheet.close();
307
+ });
308
+ await nextFrame();
309
+ await nextFrame();
310
+ // The plain announcer still holds "1 result"; the count's was taken back.
311
+ expect(shared()?.textContent).toBe('1 result 2 results');
312
+ });
313
+
314
+ it('leaves words held later when its own held words were already delivered', async () => {
315
+ render(
316
+ <Dialog isOpen onOpenChange={() => {}} aria-label="Modal">
317
+ <CountAndOther />
318
+ </Dialog>,
319
+ );
320
+ const dialog = screen.getByRole('dialog', {name: 'Modal'});
321
+ await nextFrame();
322
+ // Out of the accessibility tree, as through an exit, and back.
323
+ const setHidden = async (hidden: boolean) => {
324
+ await act(async () => {
325
+ if (hidden) {
326
+ dialog.setAttribute('aria-hidden', 'true');
327
+ } else {
328
+ dialog.removeAttribute('aria-hidden');
329
+ }
330
+ });
331
+ };
332
+ await setHidden(true);
333
+ fireEvent.click(screen.getByText('Count'));
334
+ // Exposed again: the held words are delivered and spoken.
335
+ await setHidden(false);
336
+ await nextFrame();
337
+ await nextFrame();
338
+ expect(regionIn(dialog)?.textContent).toBe('1 result');
339
+ // Hidden again: the plain announcer's "1 result" is held now, and the
340
+ // count's delivered one is not among the held words.
341
+ await setHidden(true);
342
+ fireEvent.click(screen.getByText('Next'));
343
+ await setHidden(false);
344
+ await nextFrame();
345
+ expect(regionIn(dialog)?.textContent).toBe('1 result 2 results');
346
+ });
347
+
348
+ it('withdraws its message handed off as its Dialog leaves the accessibility tree, once the Dialog is back', async () => {
349
+ render(
350
+ <Dialog isOpen onOpenChange={() => {}} aria-label="Modal">
351
+ <CountAndOther />
352
+ </Dialog>,
353
+ );
354
+ const dialog = screen.getByRole('dialog', {name: 'Modal'});
355
+ await nextFrame();
356
+ // Written, then the Dialog leaves the tree before the words are exposed:
357
+ // they are handed off, and held while the Dialog still covers the page.
358
+ fireEvent.click(screen.getByRole('button', {name: 'Count'}));
359
+ await act(async () => {
360
+ dialog.setAttribute('aria-hidden', 'true');
361
+ });
362
+ fireEvent.click(screen.getByText('Recount'));
363
+ await act(async () => {
364
+ dialog.removeAttribute('aria-hidden');
365
+ });
366
+ await nextFrame();
367
+ await nextFrame();
368
+ expect(regionIn(dialog)?.textContent).toBe('2 results');
369
+ });
370
+
371
+ it('withdraws its message handed off as its sheet exits, once the sheet has closed', async () => {
372
+ render(<ExitingSheet />);
373
+ const sheet = document.querySelector<HTMLDialogElement>('dialog')!;
374
+ await nextFrame();
375
+ // Written, and the sheet starts its exit before the words are exposed.
376
+ fireEvent.click(screen.getByRole('button', {name: 'Count'}));
377
+ fireEvent.click(screen.getByRole('button', {name: 'Done'}));
378
+ expect(sheet).toHaveAttribute('inert');
379
+ // The sheet's provider sees the exit and hands the words off.
380
+ await act(async () => {});
381
+ fireEvent.click(screen.getByText('Recount'));
382
+ act(() => {
383
+ sheet.close();
384
+ });
385
+ await nextFrame();
386
+ await nextFrame();
387
+ expect(shared()?.textContent).toBe('2 results');
388
+ });
389
+
390
+ it('withdraws its message handed to the entering step when its step is left before the words are exposed', async () => {
391
+ function Flow() {
392
+ const [step, setStep] = useState(1);
393
+ return (
394
+ <>
395
+ <Dialog isOpen={step === 1} onOpenChange={() => {}} aria-label="One">
396
+ <CountAndOther />
397
+ <button type="button" onClick={() => setStep(2)}>
398
+ Continue
399
+ </button>
400
+ </Dialog>
401
+ <Dialog isOpen={step === 2} onOpenChange={() => {}} aria-label="Two">
402
+ <span>Step two</span>
403
+ </Dialog>
404
+ </>
405
+ );
406
+ }
407
+ render(<Flow />);
408
+ await nextFrame();
409
+ // The count is written from step one, which closes in the same update
410
+ // that opens step two, before the words are exposed.
411
+ fireEvent.click(screen.getByRole('button', {name: 'Count'}));
412
+ fireEvent.click(screen.getByRole('button', {name: 'Continue'}));
413
+ // Step one's provider sees the close and hands the words to step two.
414
+ await act(async () => {});
415
+ const two = screen.getByRole('dialog', {name: 'Two'});
416
+ // The count's next message (step one's content stays mounted, closed)
417
+ // takes back its words from step two, and is heard on the page.
418
+ fireEvent.click(screen.getByText('Recount'));
419
+ await nextFrame();
420
+ await nextFrame();
421
+ expect(regionIn(two)?.textContent ?? '').toBe('');
422
+ expect(shared()?.textContent).toBe('2 results');
423
+ });
424
+
425
+ it('withdraws its message handed to the page as its Dialog closes before the words are exposed', async () => {
426
+ function Host() {
427
+ const [isOpen, setIsOpen] = useState(true);
428
+ return (
429
+ <Dialog isOpen={isOpen} onOpenChange={setIsOpen} aria-label="Modal">
430
+ <CountAndOther />
431
+ <button type="button" onClick={() => setIsOpen(false)}>
432
+ Close
433
+ </button>
434
+ </Dialog>
435
+ );
436
+ }
437
+ render(<Host />);
438
+ await nextFrame();
439
+ fireEvent.click(screen.getByRole('button', {name: 'Count'}));
440
+ fireEvent.click(screen.getByRole('button', {name: 'Close'}));
441
+ // The provider sees the close and hands the words to the page.
442
+ await act(async () => {});
443
+ // The count's next message (the closed Dialog's content stays mounted)
444
+ // takes back its words from the page channel.
445
+ fireEvent.click(screen.getByText('Recount'));
446
+ await nextFrame();
447
+ expect(shared()?.textContent).toBe('2 results');
448
+ });
449
+
450
+ it('withdraws its message redirected in the write frame when its Dialog stopped being exposed unseen', async () => {
451
+ render(
452
+ <Dialog isOpen onOpenChange={() => {}} aria-label="Modal">
453
+ <CountAndOther />
454
+ </Dialog>,
455
+ );
456
+ const dialog = screen.getByRole('dialog', {name: 'Modal'});
457
+ await nextFrame();
458
+ const exposed: string[] = [];
459
+ const record = new MutationObserver(() => {
460
+ const text = shared()?.textContent ?? '';
461
+ if (text !== '' && text !== exposed.at(-1)) {
462
+ exposed.push(text);
463
+ }
464
+ });
465
+ record.observe(document.body, {
466
+ subtree: true,
467
+ childList: true,
468
+ characterData: true,
469
+ });
470
+ fireEvent.click(screen.getByRole('button', {name: 'Count'}));
471
+ // No longer a modal, through no attribute its provider watches: the
472
+ // write frame finds it unexposed and sends the words to the page.
473
+ delete dialog.dataset.modal;
474
+ await nextFrame();
475
+ fireEvent.click(screen.getByText('Recount'));
476
+ await nextFrame();
477
+ await nextFrame();
478
+ await nextFrame();
479
+ record.disconnect();
480
+ expect(exposed).toEqual(['2 results']);
481
+ });
482
+
483
+ it('withdraws a message deferred in the commit that presents the Dialog', async () => {
484
+ function OpeningCount() {
485
+ const announce = useAnnounce(REPLACE);
486
+ useEffect(() => {
487
+ // Both before the Dialog's own Effect has presented it.
488
+ announce('1 result');
489
+ announce('2 results');
490
+ }, [announce]);
491
+ return <span>Results</span>;
492
+ }
493
+ function Host() {
494
+ const [isOpen, setIsOpen] = useState(false);
495
+ return (
496
+ <>
497
+ <button type="button" onClick={() => setIsOpen(true)}>
498
+ Open
499
+ </button>
500
+ {isOpen && (
501
+ <Dialog isOpen onOpenChange={setIsOpen} aria-label="Edit">
502
+ <OpeningCount />
503
+ </Dialog>
504
+ )}
505
+ </>
506
+ );
507
+ }
508
+ render(<Host />);
509
+ fireEvent.click(screen.getByRole('button', {name: 'Open'}));
510
+ const dialog = screen.getByRole('dialog', {name: 'Edit'});
511
+ await nextFrame();
512
+ await nextFrame();
513
+ expect(regionIn(dialog)?.textContent).toBe('2 results');
514
+ expect(shared()?.textContent ?? '').toBe('');
515
+ });
516
+ });