@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
@@ -7,10 +7,11 @@
7
7
  * @input Uses React context and useCallback; DOM APIs and cancellable
8
8
  * animation frames for a singleton live-region pair on the page body and
9
9
  * one persistent polite/assertive pair inside each open Astryx modal
10
- * @output Exports useAnnounce hook and AnnouncePoliteness type; the internal
11
- * modal context, the in-dialog region writer the busy-announcement hook
12
- * uses, and the hook the modal route (`modalAnnounce.ts`, loaded only with
13
- * an Astryx modal) installs itself through
10
+ * @output Exports useAnnounce hook (with its `hasReplace` option),
11
+ * AnnouncePoliteness and UseAnnounceOptions types; the internal modal
12
+ * context, the in-dialog region writer the busy-announcement hook uses, and
13
+ * the hook the modal route (`modalAnnounce.ts`, loaded only with an Astryx
14
+ * modal) installs itself through
14
15
  * @position Core a11y hook; provides imperative screen-reader announcements.
15
16
  * A message follows the nearest open native modal enclosing its caller
16
17
  * (`spec:AST-086` FR14): inside an Astryx modal it is written to that
@@ -18,16 +19,20 @@
18
19
  * while a native modal is open; otherwise to the shared page-body pair.
19
20
  * Containers are created empty (FR3), carry the two urgencies (FR5), join
20
21
  * messages written before the previous is exposed and say an identical
21
- * same-frame repeat once (FR9), and clear shortly after each announcement;
22
+ * same-frame repeat once (FR9), except that a `hasReplace` instance's
23
+ * message withdraws that instance's previous one not yet exposed, and clear
24
+ * shortly after each announcement;
22
25
  * the route in `modalAnnounce.ts` hands a message still unexposed when its
23
26
  * modal stops being exposed to the channel exposed after it — the modal
24
- * then on top, or the page body once no modal is open.
27
+ * then on top, or the page body once no modal is open. Each write keeps a
28
+ * receipt per announcer beside the words, which follows them wherever
29
+ * they are moved, so the announcer can take back its own share.
25
30
  *
26
31
  * SYNC: When modified, update:
27
32
  * - /packages/core/src/hooks/index.ts
28
33
  */
29
34
 
30
- import {createContext, use, useCallback, type RefObject} from 'react';
35
+ import {createContext, use, useCallback, useRef, type RefObject} from 'react';
31
36
 
32
37
  /**
33
38
  * Announcement urgency:
@@ -46,6 +51,73 @@ export type AnnounceFn = (
46
51
  politeness?: AnnouncePoliteness,
47
52
  ) => void;
48
53
 
54
+ /** Options for `useAnnounce`. */
55
+ export interface UseAnnounceOptions {
56
+ /**
57
+ * The instance states one current state of its owner, such as a search's
58
+ * result count: each message it writes withdraws the instance's previous
59
+ * message while that one is not yet exposed, whatever their urgencies, and
60
+ * is spoken in the region of its own urgency; a message already exposed has
61
+ * been heard and stays. Messages from other instances, and from instances
62
+ * without `hasReplace`, still join (`spec:AST-086` FR9). Give each state a
63
+ * component reports its own instance.
64
+ * @default false
65
+ */
66
+ hasReplace?: boolean;
67
+ }
68
+
69
+ /**
70
+ * Takes back one announcer's share of a message while it is not yet exposed,
71
+ * wherever the route put it. @internal
72
+ */
73
+ export type WithdrawAnnouncement = () => void;
74
+
75
+ /**
76
+ * One announcer's share of words on their way to being exposed. Whatever
77
+ * holds the words keeps the receipt beside them; when the words move — a
78
+ * modal hands them to the channel exposed after it, or releases words it
79
+ * held through an exit — the mover points the receipt at the new place, so
80
+ * the announcer's handle follows its words. @internal
81
+ */
82
+ export interface AnnounceReceipt {
83
+ withdraw: WithdrawAnnouncement | null;
84
+ }
85
+
86
+ /** Words waiting to be exposed, with their announcers' receipts. @internal */
87
+ export interface WaitingWords {
88
+ readonly text: string;
89
+ readonly receipts: ReadonlyArray<AnnounceReceipt>;
90
+ }
91
+
92
+ /**
93
+ * The announcer's handle to `receipt`: it takes back the words wherever they
94
+ * are now, once. @internal
95
+ */
96
+ export function handleOf(receipt: AnnounceReceipt): WithdrawAnnouncement {
97
+ return () => {
98
+ const withdraw = receipt.withdraw;
99
+ receipt.withdraw = null;
100
+ withdraw?.();
101
+ };
102
+ }
103
+
104
+ /**
105
+ * Move `waiting` words elsewhere, one delivery per announcer and in order,
106
+ * and point each receipt at its delivery, so every announcer can still take
107
+ * back its own share (`spec:AST-086` FR9, FR14). The deliveries join where
108
+ * they land, so the words are spoken once. @internal
109
+ */
110
+ export function forwardWaiting(
111
+ waiting: ReadonlyArray<WaitingWords>,
112
+ deliver: (text: string) => WithdrawAnnouncement | null,
113
+ ): void {
114
+ for (const {text, receipts} of waiting) {
115
+ for (const receipt of receipts) {
116
+ receipt.withdraw = deliver(text);
117
+ }
118
+ }
119
+ }
120
+
49
121
  const CONTAINER_ATTR = 'data-astryx-live-region';
50
122
 
51
123
  // Visually-hidden clip block (matches the VisuallyHidden primitive). Applied
@@ -165,13 +237,17 @@ function getRegions(): LiveRegions | null {
165
237
  return regions;
166
238
  }
167
239
 
240
+ /**
241
+ * Write `message` to the shared region for `politeness`, joining the messages
242
+ * not yet exposed. Returns how to take this write back while it waits.
243
+ */
168
244
  export function announceMessage(
169
245
  message: string,
170
246
  politeness: AnnouncePoliteness,
171
- ): void {
247
+ ): WithdrawAnnouncement | null {
172
248
  const r = getRegions();
173
249
  if (!r) {
174
- return;
250
+ return null;
175
251
  }
176
252
  const target = politeness === 'assertive' ? r.assertive : r.polite;
177
253
  const repeat = pendingMessages[politeness].find(
@@ -180,7 +256,7 @@ export function announceMessage(
180
256
  if (repeat != null) {
181
257
  repeat.holders += 1;
182
258
  lastJoined = repeat;
183
- return;
259
+ return () => withdrawPendingAnnouncement(repeat, politeness);
184
260
  }
185
261
  const pending = {text: message, holders: 1};
186
262
  pendingMessages[politeness].push(pending);
@@ -203,6 +279,7 @@ export function announceMessage(
203
279
  // indefinitely. Scheduled per announce, so a newer announcement always
204
280
  // resets the countdown (the delay comfortably outlasts the rAF re-set).
205
281
  scheduleClear(politeness, target);
282
+ return () => withdrawPendingAnnouncement(pending, politeness);
206
283
  }
207
284
 
208
285
  /**
@@ -233,6 +310,12 @@ export function clearRegion(politeness: AnnouncePoliteness): void {
233
310
  * announced, so users browsing the DOM later do not encounter stale status
234
311
  * text; announcing again before the clear simply resets the countdown.
235
312
  *
313
+ * An instance created with `hasReplace` states one current state, such as a
314
+ * search's result count: each message it writes withdraws its previous one
315
+ * while that one is not yet exposed, so typing faster than a frame says only
316
+ * the latest count (`spec:AST-086` FR9).
317
+ *
318
+ * @param options - `hasReplace` (default false)
236
319
  * @example
237
320
  * ```
238
321
  * function Search() {
@@ -244,27 +327,40 @@ export function clearRegion(politeness: AnnouncePoliteness): void {
244
327
  * }
245
328
  * ```
246
329
  */
247
- export function useAnnounce(): AnnounceFn {
330
+ export function useAnnounce({
331
+ hasReplace = false,
332
+ }: UseAnnounceOptions = {}): AnnounceFn {
248
333
  const modal = use(ModalAnnounceContext);
334
+ // A `hasReplace` instance's latest write, which its next message takes back
335
+ // if assistive technology has not had it yet.
336
+ const withdrawPreviousRef = useRef<WithdrawAnnouncement | null>(null);
249
337
  return useCallback(
250
338
  (message: string, politeness: AnnouncePoliteness = 'polite') => {
339
+ if (hasReplace) {
340
+ const withdrawPrevious = withdrawPreviousRef.current;
341
+ withdrawPreviousRef.current = null;
342
+ withdrawPrevious?.();
343
+ }
344
+ let written: WithdrawAnnouncement | null;
251
345
  // Inside an Astryx modal's provider: the modal route decides, per call,
252
346
  // where the caller is heard — `modal` is non-null only where a provider
253
347
  // rendered, and rendering one loads the route.
254
348
  if (modal != null && modalRoute != null) {
255
- modalRoute.announce(modal, message, politeness);
256
- return;
257
- }
258
- if (!message) {
349
+ written = modalRoute.announce(modal, message, politeness);
350
+ } else if (!message) {
259
351
  // An empty message clears any lingering status from the region,
260
352
  // including messages joined but not yet exposed — useful when the
261
353
  // triggering context ends.
262
354
  clearRegion(politeness);
263
- return;
355
+ written = null;
356
+ } else {
357
+ written = announceMessage(message, politeness);
358
+ }
359
+ if (hasReplace) {
360
+ withdrawPreviousRef.current = written;
264
361
  }
265
- announceMessage(message, politeness);
266
362
  },
267
- [modal],
363
+ [hasReplace, modal],
268
364
  );
269
365
  }
270
366
 
@@ -305,24 +401,25 @@ ModalAnnounceContext.displayName = 'ModalAnnounceContext';
305
401
 
306
402
  /** The modal route `modalAnnounce.ts` installs when a provider loads it. */
307
403
  export interface ModalRoute {
308
- /** `useAnnounce` from inside `scope`: route `message` by where it is. */
404
+ /**
405
+ * `useAnnounce` from inside `scope`: route `message` by where it is, and
406
+ * return how to take this write back while it waits (a `hasReplace`
407
+ * instance's next message does).
408
+ */
309
409
  announce(
310
410
  scope: ModalAnnounceScope,
311
411
  message: string,
312
412
  politeness: AnnouncePoliteness,
313
- ): void;
314
- /** Speak inside `dialog` with the exposure, covered and hold rules. */
413
+ ): WithdrawAnnouncement | null;
414
+ /**
415
+ * Speak inside `dialog` with the exposure, covered and hold rules, and
416
+ * return how to take this write back while it waits.
417
+ */
315
418
  announceInModal(
316
419
  dialog: HTMLDialogElement,
317
420
  message: string,
318
421
  politeness: AnnouncePoliteness,
319
- ): void;
320
- /** Withdraw an announcer's share, written or held. */
321
- withdrawFromModalPending(
322
- dialog: HTMLDialogElement,
323
- message: string,
324
- politeness: AnnouncePoliteness,
325
- ): void;
422
+ ): WithdrawAnnouncement | null;
326
423
  }
327
424
 
328
425
  let modalRoute: ModalRoute | null = null;
@@ -364,47 +461,30 @@ export function enclosingModalDialog(
364
461
  * exposure, covered and hold rules; without it — a native modal an app
365
462
  * renders without Astryx, and no Astryx modal anywhere — the words are
366
463
  * written to the dialog while it is open as a modal, else to the shared
367
- * channel. Internal: used by the busy-announcement hook.
464
+ * channel. Returns how to take the words back while they wait, wherever they
465
+ * move, so a busy start overtaken by its own outcome is never heard ahead of
466
+ * it inside a modal (`spec:AST-086` FR8). Internal: used by the
467
+ * busy-announcement hook.
368
468
  */
369
469
  export function announceInModal(
370
470
  dialog: HTMLDialogElement,
371
471
  message: string,
372
472
  politeness: AnnouncePoliteness = 'polite',
373
- ): void {
473
+ ): WithdrawAnnouncement | null {
374
474
  if (modalRoute != null) {
375
- modalRoute.announceInModal(dialog, message, politeness);
376
- return;
475
+ return modalRoute.announceInModal(dialog, message, politeness);
377
476
  }
378
477
  if (isOpenModal(dialog)) {
379
- writeModalRegion(dialog, message, politeness);
380
- } else {
381
- announceMessage(message, politeness);
382
- }
383
- }
384
-
385
- /**
386
- * Withdraw one announcer's share of `message` from `dialog` before it is
387
- * exposed, written to its region or held by the route for the dialog's
388
- * close, so a busy start overtaken by its own outcome is never heard ahead
389
- * of it inside a modal (`spec:AST-086` FR8). Internal: used by the
390
- * busy-announcement hook's settle function.
391
- */
392
- export function withdrawFromModalPending(
393
- dialog: HTMLDialogElement,
394
- message: string,
395
- politeness: AnnouncePoliteness = 'polite',
396
- ): void {
397
- if (modalRoute != null) {
398
- modalRoute.withdrawFromModalPending(dialog, message, politeness);
399
- return;
478
+ return writeModalRegion(dialog, message, politeness);
400
479
  }
401
- withdrawFromModalRegion(dialog, message, politeness);
480
+ return announceMessage(message, politeness);
402
481
  }
403
482
 
404
483
  /** What the route asks of the writer in the write frame. @internal */
405
484
  export interface ModalWriteGuard {
406
485
  isExposed: () => boolean;
407
- redirect: (joinedMessage: string) => void;
486
+ /** Deliver the waiting words elsewhere, forwarding their receipts. */
487
+ redirect: (waiting: ReadonlyArray<WaitingWords>) => void;
408
488
  }
409
489
 
410
490
  // Each in-dialog region's pending state: the messages written since its text
@@ -414,9 +494,12 @@ export interface ModalWriteGuard {
414
494
  // rather than wiping the words), and the timer that clears them afterwards.
415
495
  interface ModalPending {
416
496
  messages: string[];
417
- // Announcers waiting on each message, by text: one withdrawing a message
418
- // (a busy start overtaken by its outcome) leaves it for the others.
419
- holders: Map<string, number>;
497
+ // The announcers waiting on each message, one receipt each: one taking its
498
+ // share back (a busy start overtaken by its outcome, a `hasReplace`
499
+ // instance's next message) leaves the message for the others. A fresh map
500
+ // once the words are exposed, so a receipt never reaches equal words
501
+ // written after its own were exposed.
502
+ receipts: Map<string, AnnounceReceipt[]>;
420
503
  frame: number | null;
421
504
  settleFrame: number | null;
422
505
  timer: ReturnType<typeof setTimeout> | null;
@@ -438,12 +521,27 @@ function cancelPending(pending: ModalPending): void {
438
521
 
439
522
  /** Words written to `target` that assistive technology has not had yet. */
440
523
  export function unexposedMessages(target: HTMLElement): string[] {
524
+ return unexposedWords(target).map(words => words.text);
525
+ }
526
+
527
+ function waitingIn(pending: ModalPending): WaitingWords[] {
528
+ return pending.messages.map(text => ({
529
+ text,
530
+ receipts: pending.receipts.get(text) ?? [],
531
+ }));
532
+ }
533
+
534
+ /**
535
+ * The words written to `target` that assistive technology has not had yet,
536
+ * with their announcers' receipts, for a hand-off that forwards them.
537
+ */
538
+ export function unexposedWords(target: HTMLElement): WaitingWords[] {
441
539
  const pending = pendingByRegion.get(target);
442
540
  if (pending == null) {
443
541
  return [];
444
542
  }
445
543
  return pending.frame != null || pending.settleFrame != null
446
- ? pending.messages
544
+ ? waitingIn(pending)
447
545
  : [];
448
546
  }
449
547
 
@@ -484,29 +582,32 @@ function ensureModalRegion(
484
582
  /**
485
583
  * Write `message` to the modal `dialog`'s own live region for `politeness`,
486
584
  * joining it to messages written there that are not yet exposed and saying
487
- * an identical repeat once; a holder count per text lets one announcer take
488
- * its share back (`withdrawFromModalPending`). The region-writing core,
489
- * shared by the full modal route and by the busy-announcement hook's fallback
490
- * for a native modal an app renders without Astryx. `guard`, supplied by the
491
- * route, re-checks exposure in the write frame and redirects the joined words
492
- * when the dialog stopped being exposed meanwhile.
585
+ * an identical repeat once. The region-writing core, shared by the full
586
+ * modal route and by the busy-announcement hook's fallback for a native
587
+ * modal an app renders without Astryx. `guard`, supplied by the route,
588
+ * re-checks exposure in the write frame and redirects the waiting words when
589
+ * the dialog stopped being exposed meanwhile. Returns this announcer's
590
+ * handle: it takes back only its own share, only while the words wait, and
591
+ * follows them when the route moves them.
493
592
  */
494
593
  export function writeModalRegion(
495
594
  dialog: HTMLDialogElement,
496
595
  message: string,
497
596
  politeness: AnnouncePoliteness,
498
597
  guard?: ModalWriteGuard,
499
- ): void {
598
+ ): WithdrawAnnouncement {
500
599
  const target = ensureModalRegion(dialog, politeness);
501
600
  const unexposed = unexposedMessages(target);
502
601
  const messages = unexposed.includes(message)
503
602
  ? unexposed
504
603
  : [...unexposed, message];
505
604
  const previous = pendingByRegion.get(target);
506
- const holders = new Map(
507
- unexposed.length > 0 && previous != null ? previous.holders : [],
508
- );
509
- holders.set(message, (holders.get(message) ?? 0) + 1);
605
+ const receipts =
606
+ unexposed.length > 0 && previous != null
607
+ ? previous.receipts
608
+ : new Map<string, AnnounceReceipt[]>();
609
+ const receipt: AnnounceReceipt = {withdraw: null};
610
+ receipts.set(message, [...(receipts.get(message) ?? []), receipt]);
510
611
  if (previous != null) {
511
612
  cancelPending(previous);
512
613
  }
@@ -515,7 +616,7 @@ export function writeModalRegion(
515
616
  target.textContent = '';
516
617
  const pending: ModalPending = {
517
618
  messages,
518
- holders,
619
+ receipts,
519
620
  frame: null,
520
621
  settleFrame: null,
521
622
  timer: null,
@@ -524,9 +625,9 @@ export function writeModalRegion(
524
625
  pending.frame = null;
525
626
  if (guard != null && !guard.isExposed()) {
526
627
  // Stopped being exposed between the call and this frame: the words go
527
- // where they will be heard.
628
+ // where they will be heard, their receipts with them.
528
629
  pendingByRegion.delete(target);
529
- guard.redirect(pending.messages.join(' '));
630
+ guard.redirect(waitingIn(pending));
530
631
  return;
531
632
  }
532
633
  target.textContent = pending.messages.join(' ');
@@ -539,43 +640,49 @@ export function writeModalRegion(
539
640
  }, CLEAR_DELAY_MS);
540
641
  });
541
642
  pendingByRegion.set(target, pending);
643
+ receipt.withdraw = () => withdrawFromRegion(target, message, receipt);
644
+ return handleOf(receipt);
542
645
  }
543
646
 
544
647
  /**
545
- * Withdraw one announcer's share of `message` from `dialog`'s region before
546
- * it is exposed — written but not yet spoken — so a busy start overtaken by
547
- * its own outcome is never heard ahead of it (`spec:AST-086` FR8). The
548
- * message stays while another announcer holds it. The region half of
549
- * `withdrawFromModalPending`; the route also drops words it holds for the
550
- * dialog's close.
648
+ * Withdraw one announcer's share of `message` from `target` while it is not
649
+ * yet exposed — written but not yet spoken — so a busy start overtaken by its
650
+ * own outcome is never heard ahead of it (`spec:AST-086` FR8), and a
651
+ * `hasReplace` instance's next message replaces its previous one (FR9,
652
+ * FR14). The message stays while another announcer holds it; a receipt not
653
+ * among the waiting words (they were exposed, cleared, or moved) takes back
654
+ * nothing.
551
655
  */
552
- export function withdrawFromModalRegion(
553
- dialog: HTMLDialogElement,
656
+ function withdrawFromRegion(
657
+ target: HTMLElement,
554
658
  message: string,
555
- politeness: AnnouncePoliteness = 'polite',
659
+ receipt: AnnounceReceipt,
556
660
  ): void {
557
- const region = modalRegion(dialog, politeness);
558
- const pending = region == null ? undefined : pendingByRegion.get(region);
661
+ const pending = pendingByRegion.get(target);
559
662
  if (
560
- region != null &&
561
- pending != null &&
562
- (pending.frame != null || pending.settleFrame != null)
663
+ pending == null ||
664
+ (pending.frame == null && pending.settleFrame == null)
563
665
  ) {
564
- const count = pending.holders.get(message) ?? 0;
565
- if (count > 1) {
566
- pending.holders.set(message, count - 1);
567
- } else if (count === 1) {
568
- pending.holders.delete(message);
569
- pending.messages = pending.messages.filter(text => text !== message);
570
- if (pending.messages.length === 0) {
571
- cancelPending(pending);
572
- pendingByRegion.delete(region);
573
- region.textContent = '';
574
- } else if (pending.frame == null) {
575
- // Already written this frame, not yet taken: show the rest.
576
- region.textContent = pending.messages.join(' ');
577
- }
578
- }
666
+ return;
667
+ }
668
+ const receipts = pending.receipts.get(message);
669
+ const at = receipts?.indexOf(receipt) ?? -1;
670
+ if (receipts == null || at < 0) {
671
+ return;
672
+ }
673
+ receipts.splice(at, 1);
674
+ if (receipts.length > 0) {
675
+ return;
676
+ }
677
+ pending.receipts.delete(message);
678
+ pending.messages = pending.messages.filter(text => text !== message);
679
+ if (pending.messages.length === 0) {
680
+ cancelPending(pending);
681
+ pendingByRegion.delete(target);
682
+ target.textContent = '';
683
+ } else if (pending.frame == null) {
684
+ // Already written this frame, not yet taken: show the rest.
685
+ target.textContent = pending.messages.join(' ');
579
686
  }
580
687
  }
581
688
 
@@ -13,7 +13,9 @@
13
13
  * still announced its own content would be holding an Effect, observer, timer
14
14
  * or listener of its own for it, which INV10 rules out. The registry check at
15
15
  * the end keeps this list in step with every file that imports the module, so
16
- * a new adopter cannot skip the test.
16
+ * a new adopter cannot skip the test. The sheet case loads Tokenizer's
17
+ * on-demand sheet module before it opens the sheet, so its wait covers the
18
+ * open, not the module's load.
17
19
  */
18
20
 
19
21
  import fs from 'node:fs';
@@ -165,6 +167,13 @@ const ADOPTERS: Record<string, () => Promise<void>> = {
165
167
  'Tokenizer/TokenizerBottomSheet.tsx': async () => {
166
168
  // The sheet's own content is a caller's `emptySearchText` element; the
167
169
  // default EmptyState announces itself.
170
+ //
171
+ // Tokenizer loads the sheet on demand (Tokenizer.tsx's
172
+ // loadTokenizerBottomSheet). Loading the module is not what this case
173
+ // checks, so it waits for it first, and the one-second wait for the
174
+ // sheet's search field below covers only the open: on a busy machine the
175
+ // module's load alone outlasts it.
176
+ await import('../Tokenizer/TokenizerBottomSheet');
168
177
  render(
169
178
  <TokenizerWithPresentation
170
179
  label="Tags"
@@ -7,7 +7,7 @@
7
7
  * @input A ref to a rendered element, whether it is showing, and a token that
8
8
  * marks a new occasion to speak
9
9
  * @output Announces that element's own rendered text through the persistent
10
- * polite live region
10
+ * polite live region, or through the announcer the owner passes
11
11
  * @position Core a11y hook; mirrors on-screen content into the shared live
12
12
  * region by reading the DOM
13
13
  *
@@ -44,7 +44,11 @@
44
44
  */
45
45
 
46
46
  import {useEffect, useRef, useState, type RefObject} from 'react';
47
- import {useAnnounce, type AnnouncePoliteness} from './useAnnounce';
47
+ import {
48
+ useAnnounce,
49
+ type AnnounceFn,
50
+ type AnnouncePoliteness,
51
+ } from './useAnnounce';
48
52
  import {useIsHydrating} from './useIsHydrating';
49
53
 
50
54
  const LIVE_CONTAINER =
@@ -89,6 +93,14 @@ export interface AnnounceRenderedTextOptions {
89
93
  * every other message polite (`spec:AST-086` FR5). Defaults to polite.
90
94
  */
91
95
  politeness?: AnnouncePoliteness;
96
+ /**
97
+ * The owner's announcer to speak through, when the rendered text states
98
+ * the next value of a state that announcer states: a picker's empty-panel
99
+ * message goes through its search's `hasReplace` instance, so the two
100
+ * replace each other while not yet exposed (`spec:AST-086` FR13).
101
+ * Defaults to this hook's own instance.
102
+ */
103
+ announce?: AnnounceFn;
92
104
  }
93
105
 
94
106
  /** The rendered text an assistive technology would read from `element`. */
@@ -128,9 +140,11 @@ export function useAnnounceRenderedText(
128
140
  {
129
141
  skipFirstRender = false,
130
142
  politeness = 'polite',
143
+ announce: ownerAnnounce,
131
144
  }: AnnounceRenderedTextOptions = {},
132
145
  ): void {
133
- const announce = useAnnounce();
146
+ const ownAnnounce = useAnnounce();
147
+ const announce = ownerAnnounce ?? ownAnnounce;
134
148
  const spokenRef = useRef<string | null>(null);
135
149
  const isHydrating = useIsHydrating();
136
150
  // Captured once: an owner rendered before the document finished loading, or
@@ -32,8 +32,8 @@ import {
32
32
  enclosingModalDialog,
33
33
  takeJoinedAnnouncement,
34
34
  useAnnounce,
35
- withdrawFromModalPending,
36
35
  withdrawPendingAnnouncement,
36
+ type WithdrawAnnouncement,
37
37
  } from './useAnnounce';
38
38
 
39
39
  export function useBusyAnnouncement(
@@ -47,11 +47,9 @@ export function useBusyAnnouncement(
47
47
  // This busy start's share of the shared channel's pending text, until it
48
48
  // settles.
49
49
  const channelMessageRef = useRef<object | null>(null);
50
- // Or its write inside a modal's container, until it settles.
51
- const modalMessageRef = useRef<{
52
- dialog: HTMLDialogElement;
53
- message: string;
54
- } | null>(null);
50
+ // Or how to take back its write inside a modal, wherever the modal moves
51
+ // it, until it settles.
52
+ const modalMessageRef = useRef<WithdrawAnnouncement | null>(null);
55
53
  useEffect(() => {
56
54
  if (!isBusy) {
57
55
  hasAnnouncedRef.current = false;
@@ -74,8 +72,7 @@ export function useBusyAnnouncement(
74
72
  // nearest Astryx modal around this hook's caller.
75
73
  const dialog = enclosingModalDialog(elementRef.current);
76
74
  if (dialog != null) {
77
- announceInModal(dialog, message);
78
- modalMessageRef.current = {dialog, message};
75
+ modalMessageRef.current = announceInModal(dialog, message);
79
76
  } else {
80
77
  announce(message, 'polite');
81
78
  channelMessageRef.current = takeJoinedAnnouncement();
@@ -102,9 +99,9 @@ export function useBusyAnnouncement(
102
99
  channelMessageRef.current = null;
103
100
  }
104
101
  if (modalMessageRef.current != null) {
105
- const {dialog, message} = modalMessageRef.current;
106
- withdrawFromModalPending(dialog, message, 'polite');
102
+ const withdraw = modalMessageRef.current;
107
103
  modalMessageRef.current = null;
104
+ withdraw();
108
105
  }
109
106
  }, []);
110
107
  }
@@ -288,6 +288,20 @@ export function useMenuHover<T extends HTMLElement = HTMLElement>(
288
288
  }
289
289
  }, [hide, menuRef]);
290
290
 
291
+ // A menu placed in the content can own its own list keys (NavHeadingMenu
292
+ // runs useListFocus over the same `menuitem`s); a key it consumed must not
293
+ // move focus a second time here as it bubbles out (APG menu: one item per
294
+ // arrow press).
295
+ const handleContentKeyDown = useCallback(
296
+ (event: React.KeyboardEvent) => {
297
+ if (event.defaultPrevented) {
298
+ return;
299
+ }
300
+ handleListKeyDown(event);
301
+ },
302
+ [handleListKeyDown],
303
+ );
304
+
291
305
  useEffect(() => {
292
306
  escapeHandlerRef.current = () => {
293
307
  clearTimeouts();
@@ -535,7 +549,7 @@ export function useMenuHover<T extends HTMLElement = HTMLElement>(
535
549
  contentProps: {
536
550
  onMouseEnter: handleContentMouseEnter,
537
551
  onMouseLeave: handleMouseLeave,
538
- onKeyDown: handleListKeyDown,
552
+ onKeyDown: handleContentKeyDown,
539
553
  },
540
554
  menuRef,
541
555
  focusFirst,
@@ -230,9 +230,12 @@ const runtimeCatalog: Readonly<Record<string, string>> = {
230
230
  '@astryx.sideNav.label': 'Side navigation',
231
231
  '@astryx.sideNav.resizeSidebar': 'Resize sidebar',
232
232
  '@astryx.sideNav.heading.openMenu': 'Open menu',
233
+ '@astryx.slider.minimumThumb': 'Minimum value',
234
+ '@astryx.slider.maximumThumb': 'Maximum value',
233
235
  '@astryx.tabList.label': 'Tabs',
234
236
  '@astryx.table.label': 'Table',
235
237
  '@astryx.table.noData': 'No data',
238
+ '@astryx.table.columnResize.resizeColumn': 'Resize column {label}',
236
239
  '@astryx.table.filter.allPlaceholder': 'All',
237
240
  '@astryx.table.filter.reset': 'Reset',
238
241
  '@astryx.table.filter.apply': 'Apply',
@@ -427,6 +430,7 @@ const runtimeCatalog: Readonly<Record<string, string>> = {
427
430
  '@astryx.tableTree.expandRow': 'Expand row',
428
431
  '@astryx.tableTree.collapseAllRows': 'Collapse all rows',
429
432
  '@astryx.tableTree.expandAllRows': 'Expand all rows',
433
+ '@astryx.textArea.counter': '{count, number}/{limit, number}',
430
434
  '@astryx.textArea.charactersRemaining':
431
435
  '{count, number} {count, plural, one {character} other {characters}} remaining',
432
436
  '@astryx.textArea.charactersOverLimit':
@@ -449,6 +453,8 @@ const runtimeCatalog: Readonly<Record<string, string>> = {
449
453
  '@astryx.multiSelector.allSelected': 'All selected',
450
454
  '@astryx.multiSelector.selectionCount':
451
455
  '{count, number} of {total, number} selected',
456
+ '@astryx.multiSelector.selectedCount':
457
+ '{count, plural, one {# selected} other {# selected}}',
452
458
  '@astryx.multiSelector.createOption': 'Create "{query}"',
453
459
  '@astryx.multiSelector.optionCreated': '{label} created',
454
460
  '@astryx.multiSelector.emptySearchResults': 'No results found',