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

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 (912) hide show
  1. package/dist/AlertDialog/AlertDialog.d.ts +1 -1
  2. package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
  3. package/dist/AlertDialog/AlertDialog.js +5 -5
  4. package/dist/AppShell/AppShell.d.ts.map +1 -1
  5. package/dist/AppShell/AppShell.js +183 -5
  6. package/dist/AppShell/observeMainOverflow.d.ts +9 -0
  7. package/dist/AppShell/observeMainOverflow.d.ts.map +1 -0
  8. package/dist/AppShell/observeMainOverflow.js +125 -0
  9. package/dist/Avatar/Avatar.d.ts.map +1 -1
  10. package/dist/Avatar/Avatar.js +12 -3
  11. package/dist/Badge/Badge.d.ts.map +1 -1
  12. package/dist/Badge/Badge.js +7 -1
  13. package/dist/BottomSheet/BottomSheet.js +1 -1
  14. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
  15. package/dist/BottomSheet/BottomSheetPanel.js +2 -1
  16. package/dist/BottomSheet/useSheetGestures.d.ts +12 -0
  17. package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
  18. package/dist/BottomSheet/useSheetGestures.js +30 -3
  19. package/dist/Button/Button.js +4 -4
  20. package/dist/Carousel/Carousel.d.ts +3 -1
  21. package/dist/Carousel/Carousel.d.ts.map +1 -1
  22. package/dist/Carousel/Carousel.js +12 -3
  23. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  24. package/dist/CheckboxInput/CheckboxInput.js +6 -5
  25. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  26. package/dist/ClickableCard/ClickableCard.js +37 -4
  27. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  28. package/dist/ComplexSelector/ComplexSelector.js +41 -4
  29. package/dist/DateInput/DateInput.d.ts.map +1 -1
  30. package/dist/DateInput/DateInput.js +12 -4
  31. package/dist/DateInput/MonthScroller.d.ts.map +1 -1
  32. package/dist/DateInput/MonthScroller.js +101 -15
  33. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  34. package/dist/DateInput/TouchDateField.js +8 -3
  35. package/dist/DateInput/Wheel.d.ts.map +1 -1
  36. package/dist/DateInput/Wheel.js +11 -7
  37. package/dist/DateInput/usePointerDragScroll.d.ts +10 -1
  38. package/dist/DateInput/usePointerDragScroll.d.ts.map +1 -1
  39. package/dist/DateInput/usePointerDragScroll.js +25 -9
  40. package/dist/DateInput/useScrollSettle.d.ts +3 -1
  41. package/dist/DateInput/useScrollSettle.d.ts.map +1 -1
  42. package/dist/DateInput/useScrollSettle.js +37 -8
  43. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  44. package/dist/DateRangeInput/DateRangeInput.js +1 -1
  45. package/dist/DateTimeInput/DateTimeInput.d.ts +5 -2
  46. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  47. package/dist/DateTimeInput/DateTimeInput.js +23 -12
  48. package/dist/DateTimeInput/NativeTimeSegment.d.ts.map +1 -1
  49. package/dist/DateTimeInput/NativeTimeSegment.js +5 -4
  50. package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
  51. package/dist/DateTimeInput/TouchDateTimeField.js +4 -3
  52. package/dist/Dialog/Dialog.d.ts.map +1 -1
  53. package/dist/Dialog/Dialog.js +34 -9
  54. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  55. package/dist/Dialog/DialogHeader.js +5 -4
  56. package/dist/Divider/Divider.d.ts.map +1 -1
  57. package/dist/Divider/Divider.js +2 -1
  58. package/dist/Drawer/Drawer.d.ts +1 -0
  59. package/dist/Drawer/Drawer.d.ts.map +1 -1
  60. package/dist/Drawer/Drawer.js +7 -2
  61. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  62. package/dist/DropdownMenu/DropdownMenu.js +35 -22
  63. package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts.map +1 -1
  64. package/dist/DropdownMenu/MenuBottomSheetActionList.js +6 -5
  65. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts +20 -2
  66. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts.map +1 -1
  67. package/dist/DropdownMenu/lazyMenuBottomSheet.js +31 -3
  68. package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
  69. package/dist/DropdownMenu/renderDropdownItems.js +21 -16
  70. package/dist/EmptyState/EmptyState.d.ts.map +1 -1
  71. package/dist/EmptyState/EmptyState.js +2 -1
  72. package/dist/Field/FieldLabel.d.ts +1 -1
  73. package/dist/Field/FieldLabel.d.ts.map +1 -1
  74. package/dist/Field/FieldLabel.js +4 -4
  75. package/dist/Field/InputClearButton.js +3 -3
  76. package/dist/Field/PanelSearchInput.js +2 -2
  77. package/dist/FieldStatus/FieldStatus.d.ts +3 -0
  78. package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
  79. package/dist/FieldStatus/FieldStatus.js +3 -2
  80. package/dist/FileInput/FileInput.d.ts +3 -0
  81. package/dist/FileInput/FileInput.d.ts.map +1 -1
  82. package/dist/FileInput/FileInput.js +34 -13
  83. package/dist/Heading/Heading.js +1 -1
  84. package/dist/Icon/Icon.js +1 -1
  85. package/dist/Indicator/CheckIndicator.d.ts.map +1 -1
  86. package/dist/Indicator/CheckIndicator.js +2 -1
  87. package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -1
  88. package/dist/Indicator/CheckboxIndicator.js +3 -1
  89. package/dist/Indicator/RadioIndicator.d.ts.map +1 -1
  90. package/dist/Indicator/RadioIndicator.js +3 -1
  91. package/dist/Item/Item.d.ts.map +1 -1
  92. package/dist/Item/Item.js +21 -7
  93. package/dist/Item/ItemSwipeLayer.js +1 -1
  94. package/dist/Layer/popoverOperations.d.ts +27 -0
  95. package/dist/Layer/popoverOperations.d.ts.map +1 -0
  96. package/dist/Layer/popoverOperations.js +159 -0
  97. package/dist/Layer/useLayer.d.ts +1 -1
  98. package/dist/Layer/useLayer.d.ts.map +1 -1
  99. package/dist/Layer/useLayer.js +120 -65
  100. package/dist/Layout/Layout.js +1 -1
  101. package/dist/Layout/LayoutContent.js +1 -1
  102. package/dist/Layout/LayoutFooter.js +1 -1
  103. package/dist/Layout/LayoutHeader.js +1 -1
  104. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  105. package/dist/Lightbox/Lightbox.js +5 -0
  106. package/dist/Lightbox/LightboxViewport.a11y.browser.spec.js +5 -4
  107. package/dist/Link/Link.d.ts.map +1 -1
  108. package/dist/Link/Link.js +8 -3
  109. package/dist/List/List.js +1 -1
  110. package/dist/List/ListItem.js +3 -3
  111. package/dist/Markdown/plugins/headingLinks.a11y.chromium.spec.js +1 -1
  112. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  113. package/dist/MobileNav/MobileNav.js +7 -2
  114. package/dist/MultiSelector/CreateRow.a11y.chromium.spec.js +7 -6
  115. package/dist/MultiSelector/MultiSelector.d.ts +1 -1
  116. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  117. package/dist/MultiSelector/MultiSelector.js +26 -10
  118. package/dist/NavMenu/NavHeadingMenuItem.d.ts.map +1 -1
  119. package/dist/NavMenu/NavHeadingMenuItem.js +5 -29
  120. package/dist/NumberInput/NumberInput.d.ts +3 -1
  121. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  122. package/dist/NumberInput/NumberInput.js +26 -5
  123. package/dist/NumberInput/numberParser.d.ts +3 -0
  124. package/dist/NumberInput/numberParser.d.ts.map +1 -1
  125. package/dist/NumberInput/numberParser.js +7 -44
  126. package/dist/Outline/Outline.d.ts.map +1 -1
  127. package/dist/Outline/Outline.js +27 -0
  128. package/dist/Popover/Popover.d.ts.map +1 -1
  129. package/dist/Popover/Popover.js +32 -12
  130. package/dist/Popover/usePopover.d.ts.map +1 -1
  131. package/dist/Popover/usePopover.js +10 -3
  132. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  133. package/dist/PowerSearch/PowerSearch.js +37 -30
  134. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  135. package/dist/ProgressBar/ProgressBar.js +16 -12
  136. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  137. package/dist/RadioList/RadioListItem.js +11 -3
  138. package/dist/Resizable/useResizable.d.ts.map +1 -1
  139. package/dist/Resizable/useResizable.js +28 -2
  140. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  141. package/dist/SegmentedControl/SegmentedControlItem.js +4 -1
  142. package/dist/Selector/useSelectorPresentation.d.ts +8 -1
  143. package/dist/Selector/useSelectorPresentation.d.ts.map +1 -1
  144. package/dist/Selector/useSelectorPresentation.js +20 -4
  145. package/dist/SideNav/SideNavItem.d.ts +2 -2
  146. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  147. package/dist/SideNav/SideNavItem.js +18 -7
  148. package/dist/Skeleton/Skeleton.d.ts.map +1 -1
  149. package/dist/Skeleton/Skeleton.js +1 -1
  150. package/dist/Slider/Slider.d.ts.map +1 -1
  151. package/dist/Slider/Slider.js +10 -2
  152. package/dist/Spinner/Spinner.d.ts.map +1 -1
  153. package/dist/Spinner/Spinner.js +3 -3
  154. package/dist/Stack/Stack.js +1 -1
  155. package/dist/Stack/StackItem.js +1 -1
  156. package/dist/Stepper/Step.d.ts.map +1 -1
  157. package/dist/Stepper/Step.js +26 -6
  158. package/dist/Switch/Switch.d.ts.map +1 -1
  159. package/dist/Switch/Switch.js +10 -3
  160. package/dist/TabList/TabList.d.ts.map +1 -1
  161. package/dist/TabList/TabList.js +16 -1
  162. package/dist/Table/Table.d.ts.map +1 -1
  163. package/dist/Table/Table.js +36 -10
  164. package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
  165. package/dist/Table/plugins/columnResize/useTableColumnResize.js +9 -1
  166. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  167. package/dist/Table/plugins/sortable/useTableSortable.js +46 -58
  168. package/dist/Text/Text.js +1 -1
  169. package/dist/Text/useTruncation.d.ts.map +1 -1
  170. package/dist/Text/useTruncation.js +23 -5
  171. package/dist/TextArea/TextArea.d.ts +1 -1
  172. package/dist/TextArea/TextArea.d.ts.map +1 -1
  173. package/dist/TextArea/TextArea.js +13 -2
  174. package/dist/TextInput/TextInput.d.ts.map +1 -1
  175. package/dist/TextInput/TextInput.js +3 -3
  176. package/dist/TimeInput/TimeInput.d.ts +6 -2
  177. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  178. package/dist/TimeInput/TimeInput.js +21 -14
  179. package/dist/TimeInput/TouchTimeField.d.ts.map +1 -1
  180. package/dist/TimeInput/TouchTimeField.js +5 -4
  181. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  182. package/dist/Timestamp/Timestamp.js +2 -2
  183. package/dist/Timestamp/TimestampHoverCard.js +4 -4
  184. package/dist/Toast/Toast.d.ts.map +1 -1
  185. package/dist/Toast/Toast.js +60 -20
  186. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  187. package/dist/Toast/ToastViewport.js +101 -54
  188. package/dist/ToggleButton/ToggleButtonGroup.d.ts +7 -1
  189. package/dist/ToggleButton/ToggleButtonGroup.d.ts.map +1 -1
  190. package/dist/ToggleButton/ToggleButtonGroup.js +16 -2
  191. package/dist/Token/Token.d.ts +1 -1
  192. package/dist/Token/Token.d.ts.map +1 -1
  193. package/dist/Token/Token.js +52 -5
  194. package/dist/Token/TokenLink.d.ts.map +1 -1
  195. package/dist/Token/TokenLink.js +14 -2
  196. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  197. package/dist/Tokenizer/Tokenizer.js +44 -7
  198. package/dist/Tokenizer/TokenizerBottomSheet.js +3 -3
  199. package/dist/Tokenizer/TokenizerClearAllMessageContext.d.ts +2 -0
  200. package/dist/Tokenizer/TokenizerClearAllMessageContext.d.ts.map +1 -0
  201. package/dist/Tokenizer/TokenizerClearAllMessageContext.js +17 -0
  202. package/dist/Toolbar/Toolbar.d.ts.map +1 -1
  203. package/dist/Toolbar/Toolbar.js +2 -1
  204. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  205. package/dist/TopNav/TopNavMegaMenu.js +3 -0
  206. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  207. package/dist/TopNav/TopNavMenu.js +1 -0
  208. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  209. package/dist/TreeList/TreeListItem.js +27 -4
  210. package/dist/Typeahead/BaseTypeahead.d.ts +4 -4
  211. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  212. package/dist/Typeahead/BaseTypeahead.js +43 -7
  213. package/dist/Typeahead/Typeahead.d.ts +1 -1
  214. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  215. package/dist/Typeahead/Typeahead.js +43 -9
  216. package/dist/astryx.css +25 -4
  217. package/dist/gestures/GestureArena.d.ts +32 -1
  218. package/dist/gestures/GestureArena.d.ts.map +1 -1
  219. package/dist/gestures/GestureArena.js +110 -9
  220. package/dist/gestures/GestureHost.d.ts +351 -0
  221. package/dist/gestures/GestureHost.d.ts.map +1 -0
  222. package/dist/gestures/GestureHost.js +1773 -0
  223. package/dist/gestures/GestureRecognizer.d.ts +13 -1
  224. package/dist/gestures/GestureRecognizer.d.ts.map +1 -1
  225. package/dist/gestures/GestureRecognizer.js +19 -1
  226. package/dist/gestures/LongPressGestureRecognizer.d.ts +1 -0
  227. package/dist/gestures/LongPressGestureRecognizer.d.ts.map +1 -1
  228. package/dist/gestures/LongPressGestureRecognizer.js +3 -0
  229. package/dist/gestures/PanGestureRecognizer.d.ts +1 -0
  230. package/dist/gestures/PanGestureRecognizer.d.ts.map +1 -1
  231. package/dist/gestures/PanGestureRecognizer.js +3 -0
  232. package/dist/gestures/PinchGestureRecognizer.d.ts +31 -0
  233. package/dist/gestures/PinchGestureRecognizer.d.ts.map +1 -0
  234. package/dist/gestures/PinchGestureRecognizer.js +128 -0
  235. package/dist/gestures/PressTracker.d.ts +112 -0
  236. package/dist/gestures/PressTracker.d.ts.map +1 -0
  237. package/dist/gestures/PressTracker.js +267 -0
  238. package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts +71 -0
  239. package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts.map +1 -0
  240. package/dist/gestures/ScreenEdgePanGestureRecognizer.js +223 -0
  241. package/dist/gestures/SwipeGestureRecognizer.d.ts +37 -0
  242. package/dist/gestures/SwipeGestureRecognizer.d.ts.map +1 -0
  243. package/dist/gestures/SwipeGestureRecognizer.js +148 -0
  244. package/dist/gestures/TapGestureRecognizer.d.ts +1 -0
  245. package/dist/gestures/TapGestureRecognizer.d.ts.map +1 -1
  246. package/dist/gestures/TapGestureRecognizer.js +3 -0
  247. package/dist/gestures/VelocityTracker.d.ts +6 -2
  248. package/dist/gestures/VelocityTracker.d.ts.map +1 -1
  249. package/dist/gestures/VelocityTracker.js +7 -3
  250. package/dist/gestures/haptics.d.ts +65 -0
  251. package/dist/gestures/haptics.d.ts.map +1 -0
  252. package/dist/gestures/haptics.js +182 -0
  253. package/dist/gestures/index.d.ts +37 -0
  254. package/dist/gestures/index.d.ts.map +1 -0
  255. package/dist/gestures/index.js +25 -0
  256. package/dist/gestures/nativeScroll.d.ts +42 -0
  257. package/dist/gestures/nativeScroll.d.ts.map +1 -0
  258. package/dist/gestures/nativeScroll.js +228 -0
  259. package/dist/gestures/touchAction.d.ts +60 -0
  260. package/dist/gestures/touchAction.d.ts.map +1 -0
  261. package/dist/gestures/touchAction.js +157 -0
  262. package/dist/gestures/touchActionRule.d.ts +34 -0
  263. package/dist/gestures/touchActionRule.d.ts.map +1 -0
  264. package/dist/gestures/touchActionRule.js +140 -0
  265. package/dist/gestures/types.d.ts +18 -7
  266. package/dist/gestures/types.d.ts.map +1 -1
  267. package/dist/gestures/types.js +22 -2
  268. package/dist/gestures/useGestureRecognizer.d.ts +56 -0
  269. package/dist/gestures/useGestureRecognizer.d.ts.map +1 -0
  270. package/dist/gestures/useGestureRecognizer.js +226 -0
  271. package/dist/hooks/index.d.ts +1 -1
  272. package/dist/hooks/index.d.ts.map +1 -1
  273. package/dist/hooks/modalAnnounce.d.ts.map +1 -1
  274. package/dist/hooks/modalAnnounce.js +107 -61
  275. package/dist/hooks/scrollKeyboardDelegation.d.ts.map +1 -1
  276. package/dist/hooks/scrollKeyboardDelegation.js +7 -3
  277. package/dist/hooks/useAdaptivePresentation.d.ts.map +1 -1
  278. package/dist/hooks/useAdaptivePresentation.js +4 -1
  279. package/dist/hooks/useAnnounce.d.ts +101 -42
  280. package/dist/hooks/useAnnounce.d.ts.map +1 -1
  281. package/dist/hooks/useAnnounce.js +161 -75
  282. package/dist/hooks/useAnnounceRenderedText.d.ts +11 -3
  283. package/dist/hooks/useAnnounceRenderedText.d.ts.map +1 -1
  284. package/dist/hooks/useAnnounceRenderedText.js +5 -3
  285. package/dist/hooks/useBusyAnnouncement.d.ts.map +1 -1
  286. package/dist/hooks/useBusyAnnouncement.js +6 -12
  287. package/dist/hooks/useMenuHover.d.ts.map +1 -1
  288. package/dist/hooks/useMenuHover.js +12 -1
  289. package/dist/hooks/useScrollOverflow.d.ts +2 -1
  290. package/dist/hooks/useScrollOverflow.d.ts.map +1 -1
  291. package/dist/hooks/useScrollOverflow.js +56 -10
  292. package/dist/i18n/generated-locales/af-ZA.generated.d.ts.map +1 -1
  293. package/dist/i18n/generated-locales/af-ZA.generated.js +0 -5
  294. package/dist/i18n/generated-locales/ar-SA.generated.d.ts.map +1 -1
  295. package/dist/i18n/generated-locales/ar-SA.generated.js +0 -5
  296. package/dist/i18n/generated-locales/ca-ES.generated.d.ts.map +1 -1
  297. package/dist/i18n/generated-locales/ca-ES.generated.js +0 -5
  298. package/dist/i18n/generated-locales/cs-CZ.generated.d.ts.map +1 -1
  299. package/dist/i18n/generated-locales/cs-CZ.generated.js +0 -5
  300. package/dist/i18n/generated-locales/da-DK.generated.d.ts.map +1 -1
  301. package/dist/i18n/generated-locales/da-DK.generated.js +0 -5
  302. package/dist/i18n/generated-locales/de-DE.generated.d.ts.map +1 -1
  303. package/dist/i18n/generated-locales/de-DE.generated.js +0 -5
  304. package/dist/i18n/generated-locales/el-GR.generated.d.ts.map +1 -1
  305. package/dist/i18n/generated-locales/el-GR.generated.js +0 -5
  306. package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
  307. package/dist/i18n/generated-locales/en.generated.js +8 -5
  308. package/dist/i18n/generated-locales/es-ES.generated.d.ts.map +1 -1
  309. package/dist/i18n/generated-locales/es-ES.generated.js +0 -5
  310. package/dist/i18n/generated-locales/fi-FI.generated.d.ts.map +1 -1
  311. package/dist/i18n/generated-locales/fi-FI.generated.js +0 -5
  312. package/dist/i18n/generated-locales/fr-FR.generated.d.ts.map +1 -1
  313. package/dist/i18n/generated-locales/fr-FR.generated.js +0 -5
  314. package/dist/i18n/generated-locales/he-IL.generated.d.ts.map +1 -1
  315. package/dist/i18n/generated-locales/he-IL.generated.js +0 -5
  316. package/dist/i18n/generated-locales/hu-HU.generated.d.ts.map +1 -1
  317. package/dist/i18n/generated-locales/hu-HU.generated.js +0 -5
  318. package/dist/i18n/generated-locales/it-IT.generated.d.ts.map +1 -1
  319. package/dist/i18n/generated-locales/it-IT.generated.js +0 -5
  320. package/dist/i18n/generated-locales/ja-JP.generated.d.ts.map +1 -1
  321. package/dist/i18n/generated-locales/ja-JP.generated.js +0 -5
  322. package/dist/i18n/generated-locales/ko-KR.generated.d.ts.map +1 -1
  323. package/dist/i18n/generated-locales/ko-KR.generated.js +0 -5
  324. package/dist/i18n/generated-locales/nl-NL.generated.d.ts.map +1 -1
  325. package/dist/i18n/generated-locales/nl-NL.generated.js +0 -5
  326. package/dist/i18n/generated-locales/no-NO.generated.d.ts.map +1 -1
  327. package/dist/i18n/generated-locales/no-NO.generated.js +0 -5
  328. package/dist/i18n/generated-locales/pl-PL.generated.d.ts.map +1 -1
  329. package/dist/i18n/generated-locales/pl-PL.generated.js +0 -5
  330. package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
  331. package/dist/i18n/generated-locales/pseudo.generated.js +8 -5
  332. package/dist/i18n/generated-locales/pt-BR.generated.d.ts.map +1 -1
  333. package/dist/i18n/generated-locales/pt-BR.generated.js +0 -5
  334. package/dist/i18n/generated-locales/pt-PT.generated.d.ts.map +1 -1
  335. package/dist/i18n/generated-locales/pt-PT.generated.js +0 -5
  336. package/dist/i18n/generated-locales/ro-RO.generated.d.ts.map +1 -1
  337. package/dist/i18n/generated-locales/ro-RO.generated.js +0 -5
  338. package/dist/i18n/generated-locales/ru-RU.generated.d.ts.map +1 -1
  339. package/dist/i18n/generated-locales/ru-RU.generated.js +0 -5
  340. package/dist/i18n/generated-locales/sr-SP.generated.d.ts.map +1 -1
  341. package/dist/i18n/generated-locales/sr-SP.generated.js +0 -5
  342. package/dist/i18n/generated-locales/sv-SE.generated.d.ts.map +1 -1
  343. package/dist/i18n/generated-locales/sv-SE.generated.js +0 -5
  344. package/dist/i18n/generated-locales/tr-TR.generated.d.ts.map +1 -1
  345. package/dist/i18n/generated-locales/tr-TR.generated.js +0 -5
  346. package/dist/i18n/generated-locales/uk-UA.generated.d.ts.map +1 -1
  347. package/dist/i18n/generated-locales/uk-UA.generated.js +0 -5
  348. package/dist/i18n/generated-locales/vi-VN.generated.d.ts.map +1 -1
  349. package/dist/i18n/generated-locales/vi-VN.generated.js +0 -5
  350. package/dist/i18n/generated-locales/zh-CN.generated.d.ts.map +1 -1
  351. package/dist/i18n/generated-locales/zh-CN.generated.js +0 -5
  352. package/dist/i18n/generated-locales/zh-TW.generated.d.ts.map +1 -1
  353. package/dist/i18n/generated-locales/zh-TW.generated.js +0 -5
  354. package/dist/i18n/useListFormatter.d.ts +9 -0
  355. package/dist/i18n/useListFormatter.d.ts.map +1 -0
  356. package/dist/i18n/useListFormatter.js +41 -0
  357. package/dist/motion/animator.d.ts +83 -8
  358. package/dist/motion/animator.d.ts.map +1 -1
  359. package/dist/motion/animator.js +701 -119
  360. package/dist/motion/coast.d.ts +4 -1
  361. package/dist/motion/coast.d.ts.map +1 -1
  362. package/dist/motion/coast.js +4 -2
  363. package/dist/motion/reducedMotion.d.ts.map +1 -1
  364. package/dist/motion/reducedMotion.js +6 -2
  365. package/dist/motion/reducedMotionPlan.d.ts +7 -0
  366. package/dist/motion/reducedMotionPlan.d.ts.map +1 -1
  367. package/dist/motion/reducedMotionPlan.js +14 -1
  368. package/dist/motion/resolveMotion.d.ts +42 -0
  369. package/dist/motion/resolveMotion.d.ts.map +1 -0
  370. package/dist/motion/resolveMotion.js +43 -0
  371. package/dist/motion/roleValue.d.ts +2 -1
  372. package/dist/motion/roleValue.d.ts.map +1 -1
  373. package/dist/motion/roleValue.js +2 -1
  374. package/dist/motion/uikit/timing.d.ts +7 -1
  375. package/dist/motion/uikit/timing.d.ts.map +1 -1
  376. package/dist/motion/uikit/timing.js +19 -1
  377. package/dist/theme/defineTheme.d.ts +19 -5
  378. package/dist/theme/defineTheme.d.ts.map +1 -1
  379. package/dist/theme/defineTheme.js +64 -4
  380. package/dist/theme/domainTokens/domainTokenDefaults.d.ts +3 -0
  381. package/dist/theme/domainTokens/domainTokenDefaults.d.ts.map +1 -0
  382. package/dist/theme/domainTokens/domainTokenDefaults.js +19 -0
  383. package/dist/theme/domainTokens/index.d.ts +5 -4
  384. package/dist/theme/domainTokens/index.d.ts.map +1 -1
  385. package/dist/theme/domainTokens/index.js +5 -9
  386. package/dist/theme/index.d.ts +1 -0
  387. package/dist/theme/index.d.ts.map +1 -1
  388. package/dist/theme/motionKnobs.d.ts +56 -0
  389. package/dist/theme/motionKnobs.d.ts.map +1 -0
  390. package/dist/theme/motionKnobs.js +48 -0
  391. package/dist/theme/resolveThemeValues.d.ts +11 -4
  392. package/dist/theme/resolveThemeValues.d.ts.map +1 -1
  393. package/dist/theme/resolveThemeValues.js +40 -4
  394. package/dist/theme/themeAdaptations.d.ts +7 -3
  395. package/dist/theme/themeAdaptations.d.ts.map +1 -1
  396. package/dist/theme/themeAdaptations.js +36 -7
  397. package/dist/theme/themeMotion.d.ts +96 -0
  398. package/dist/theme/themeMotion.d.ts.map +1 -0
  399. package/dist/theme/themeMotion.js +177 -0
  400. package/dist/theme/tokenReferences.d.ts +31 -0
  401. package/dist/theme/tokenReferences.d.ts.map +1 -0
  402. package/dist/theme/tokenReferences.js +132 -0
  403. package/dist/theme/tokens.d.ts +1 -0
  404. package/dist/theme/tokens.d.ts.map +1 -1
  405. package/dist/theme/tokens.js +9 -129
  406. package/dist/theme/tokens.stylex.d.ts +12 -0
  407. package/dist/theme/tokens.stylex.d.ts.map +1 -1
  408. package/dist/theme/tokens.stylex.js +12 -0
  409. package/dist/utils/focusOutline.stylex.d.ts +6 -0
  410. package/dist/utils/focusOutline.stylex.d.ts.map +1 -1
  411. package/dist/utils/focusOutline.stylex.js +7 -0
  412. package/dist/utils/focusReturn.d.ts +17 -1
  413. package/dist/utils/focusReturn.d.ts.map +1 -1
  414. package/dist/utils/focusReturn.js +11 -4
  415. package/dist/utils/getNodeText.d.ts +8 -0
  416. package/dist/utils/getNodeText.d.ts.map +1 -0
  417. package/dist/utils/getNodeText.js +37 -0
  418. package/dist/utils/interactionModality.d.ts +11 -2
  419. package/dist/utils/interactionModality.d.ts.map +1 -1
  420. package/dist/utils/interactionModality.js +58 -5
  421. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
  422. package/dist/utils/interactionOverlay.stylex.js +17 -8
  423. package/dist/utils/plainDate.d.ts +2 -0
  424. package/dist/utils/plainDate.d.ts.map +1 -1
  425. package/dist/utils/plainDate.js +46 -3
  426. package/dist/utils/presentation.d.ts +50 -0
  427. package/dist/utils/presentation.d.ts.map +1 -0
  428. package/dist/utils/presentation.js +125 -0
  429. package/dist/utils/pressFeedback.d.ts.map +1 -1
  430. package/dist/utils/pressFeedback.js +20 -1
  431. package/dist/utils/primaryClick.d.ts +11 -0
  432. package/dist/utils/primaryClick.d.ts.map +1 -0
  433. package/dist/utils/primaryClick.js +25 -0
  434. package/dist/utils/sharedMutationObserver.d.ts +19 -11
  435. package/dist/utils/sharedMutationObserver.d.ts.map +1 -1
  436. package/dist/utils/sharedMutationObserver.js +66 -26
  437. package/dist/utils/timeFormat.d.ts +47 -0
  438. package/dist/utils/timeFormat.d.ts.map +1 -0
  439. package/dist/utils/timeFormat.js +240 -0
  440. package/dist/utils/touchPresentation.d.ts +2 -2
  441. package/dist/utils/touchPresentation.d.ts.map +1 -1
  442. package/dist/utils/touchPresentation.js +13 -8
  443. package/dist/utils/touchPresentation.stylex.d.ts +15 -0
  444. package/dist/utils/touchPresentation.stylex.d.ts.map +1 -0
  445. package/dist/utils/touchPresentation.stylex.js +33 -0
  446. package/dist/utils/touchQueries.d.ts +13 -0
  447. package/dist/utils/touchQueries.d.ts.map +1 -0
  448. package/dist/utils/touchQueries.js +15 -0
  449. package/dist/utils/unicodeDigits.d.ts +20 -0
  450. package/dist/utils/unicodeDigits.d.ts.map +1 -0
  451. package/dist/utils/unicodeDigits.js +70 -0
  452. package/dist/utils/useFocusAcrossSwap.d.ts +19 -0
  453. package/dist/utils/useFocusAcrossSwap.d.ts.map +1 -0
  454. package/dist/utils/useFocusAcrossSwap.js +41 -0
  455. package/locales/af-ZA.json +0 -21
  456. package/locales/ar-SA.json +0 -21
  457. package/locales/ca-ES.json +0 -21
  458. package/locales/cs-CZ.json +0 -21
  459. package/locales/da-DK.json +0 -21
  460. package/locales/de-DE.json +0 -21
  461. package/locales/el-GR.json +0 -21
  462. package/locales/en.json +35 -23
  463. package/locales/es-ES.json +0 -21
  464. package/locales/fi-FI.json +0 -21
  465. package/locales/fr-FR.json +0 -21
  466. package/locales/he-IL.json +0 -21
  467. package/locales/hu-HU.json +0 -21
  468. package/locales/it-IT.json +0 -21
  469. package/locales/ja-JP.json +0 -21
  470. package/locales/ko-KR.json +0 -21
  471. package/locales/nl-NL.json +0 -21
  472. package/locales/no-NO.json +0 -21
  473. package/locales/pl-PL.json +0 -21
  474. package/locales/pseudo.json +23 -14
  475. package/locales/pt-BR.json +0 -21
  476. package/locales/pt-PT.json +0 -21
  477. package/locales/ro-RO.json +0 -21
  478. package/locales/ru-RU.json +0 -21
  479. package/locales/sr-SP.json +0 -21
  480. package/locales/sv-SE.json +0 -21
  481. package/locales/tr-TR.json +0 -21
  482. package/locales/uk-UA.json +0 -21
  483. package/locales/vi-VN.json +0 -21
  484. package/locales/zh-CN.json +0 -21
  485. package/locales/zh-TW.json +0 -21
  486. package/package.json +5 -4
  487. package/src/AlertDialog/AlertDialog.tsx +6 -5
  488. package/src/AlertDialog/__tests__/AlertDialog.a11y.chromium.spec.ts +18 -6
  489. package/src/AppShell/AppShell.doc.mjs +1 -1
  490. package/src/AppShell/AppShell.spec.md +9 -12
  491. package/src/AppShell/AppShell.test.tsx +164 -2
  492. package/src/AppShell/AppShell.tsx +225 -5
  493. package/src/AppShell/__tests__/AppShellMainKeyboard.a11y.browser.spec.ts +534 -0
  494. package/src/AppShell/observeMainOverflow.test.ts +173 -0
  495. package/src/AppShell/observeMainOverflow.ts +143 -0
  496. package/src/Avatar/Avatar.spec.md +22 -22
  497. package/src/Avatar/Avatar.tsx +18 -1
  498. package/src/Avatar/__tests__/AvatarForcedColors.a11y.chromium.spec.ts +126 -0
  499. package/src/Badge/Badge.doc.mjs +1 -1
  500. package/src/Badge/Badge.tsx +19 -2
  501. package/src/Badge/__tests__/BadgeLargerText.a11y.chromium.spec.ts +260 -0
  502. package/src/BottomSheet/BottomSheet.test.tsx +46 -0
  503. package/src/BottomSheet/BottomSheet.tsx +1 -1
  504. package/src/BottomSheet/BottomSheetPanel.tsx +2 -1
  505. package/src/BottomSheet/useSheetGestures.test.ts +52 -0
  506. package/src/BottomSheet/useSheetGestures.ts +37 -6
  507. package/src/Breadcrumbs/__tests__/Breadcrumbs.a11y.chromium.spec.ts +18 -6
  508. package/src/Button/Button.tsx +4 -4
  509. package/src/Calendar/Calendar.spec.md +87 -48
  510. package/src/Calendar/__tests__/Calendar.a11y.chromium.spec.ts +21 -7
  511. package/src/Carousel/Carousel.doc.mjs +1 -1
  512. package/src/Carousel/Carousel.spec.md +9 -9
  513. package/src/Carousel/Carousel.test.tsx +124 -3
  514. package/src/Carousel/Carousel.tsx +10 -2
  515. package/src/Carousel/__tests__/Carousel.a11y.chromium.spec.ts +21 -7
  516. package/src/Carousel/__tests__/Carousel.a11y.known-failures.ts +1 -16
  517. package/src/Chat/ChatComposer.spec.md +75 -59
  518. package/src/Chat/ChatComposerTokenElement.spec.md +45 -33
  519. package/src/Chat/ChatDictationButton.spec.md +126 -81
  520. package/src/Chat/ChatLayout.spec.md +41 -36
  521. package/src/Chat/ChatLayoutScrollButton.spec.md +87 -103
  522. package/src/Chat/ChatMessage.spec.md +64 -65
  523. package/src/Chat/ChatSendButton.spec.md +78 -67
  524. package/src/CheckboxInput/CheckboxInput.tsx +6 -5
  525. package/src/Citation/Citation.spec.md +60 -47
  526. package/src/ClickableCard/ClickableCard.test.tsx +96 -0
  527. package/src/ClickableCard/ClickableCard.tsx +48 -4
  528. package/src/CodeBlock/__tests__/CodeBlockCopyClearance.a11y.chromium.spec.ts +38 -3
  529. package/src/Collapsible/Collapsible.spec.md +2 -0
  530. package/src/Collapsible/CollapsibleGroup.spec.md +57 -29
  531. package/src/Collapsible/__tests__/Collapsible.a11y.chromium.spec.ts +18 -7
  532. package/src/Collapsible/__tests__/CollapsibleGroupAccordion.a11y.chromium.spec.ts +18 -6
  533. package/src/ComplexSelector/ComplexSelector.test.tsx +148 -0
  534. package/src/ComplexSelector/ComplexSelector.tsx +41 -4
  535. package/src/ContextMenu/ContextMenu.spec.md +84 -56
  536. package/src/ContextMenu/ContextMenu.test.tsx +35 -0
  537. package/src/ContextMenu/ContextMenuItem.spec.md +132 -0
  538. package/src/DateInput/DateInput.spec.md +74 -57
  539. package/src/DateInput/DateInput.test.tsx +115 -3
  540. package/src/DateInput/DateInput.tsx +29 -14
  541. package/src/DateInput/DateInputTouch.test.tsx +120 -0
  542. package/src/DateInput/MonthScroller.tsx +106 -20
  543. package/src/DateInput/MonthScrollerSettle.test.tsx +165 -0
  544. package/src/DateInput/TouchDateField.tsx +14 -3
  545. package/src/DateInput/Wheel.tsx +9 -6
  546. package/src/DateInput/__tests__/MonthScrollerSteps.interaction.browser.spec.ts +312 -0
  547. package/src/DateInput/usePointerDragScroll.ts +34 -10
  548. package/src/DateInput/useScrollSettle.ts +38 -7
  549. package/src/DateRangeInput/DateRangeInput.test.tsx +46 -3
  550. package/src/DateRangeInput/DateRangeInput.tsx +16 -12
  551. package/src/DateTimeInput/DateTimeInput.doc.mjs +10 -8
  552. package/src/DateTimeInput/DateTimeInput.spec.md +75 -51
  553. package/src/DateTimeInput/DateTimeInput.test.tsx +81 -0
  554. package/src/DateTimeInput/DateTimeInput.tsx +46 -24
  555. package/src/DateTimeInput/NativeTimeSegment.tsx +4 -6
  556. package/src/DateTimeInput/TouchDateTimeField.tsx +3 -7
  557. package/src/Dialog/Dialog.test.tsx +216 -2
  558. package/src/Dialog/Dialog.tsx +42 -9
  559. package/src/Dialog/DialogHeader.tsx +5 -4
  560. package/src/Dialog/__tests__/DialogSecondDocument.a11y.browser.spec.ts +202 -0
  561. package/src/Divider/Divider.tsx +2 -1
  562. package/src/Drawer/Drawer.spec.md +111 -80
  563. package/src/Drawer/Drawer.test.tsx +35 -0
  564. package/src/Drawer/Drawer.tsx +13 -2
  565. package/src/Drawer/DrawerHeader.spec.md +181 -0
  566. package/src/Drawer/__tests__/DrawerNonModalPageScroll.a11y.chromium.spec.ts +267 -0
  567. package/src/DropdownMenu/DropdownMenu.spec.md +198 -218
  568. package/src/DropdownMenu/DropdownMenu.test.tsx +158 -0
  569. package/src/DropdownMenu/DropdownMenu.tsx +43 -21
  570. package/src/DropdownMenu/DropdownMenuCheckboxItem.spec.md +192 -0
  571. package/src/DropdownMenu/DropdownMenuDivider.spec.md +25 -31
  572. package/src/DropdownMenu/DropdownMenuGroup.spec.md +145 -0
  573. package/src/DropdownMenu/DropdownMenuItem.spec.md +48 -42
  574. package/src/DropdownMenu/DropdownMenuRadioGroup.spec.md +34 -37
  575. package/src/DropdownMenu/DropdownMenuRadioItem.spec.md +54 -53
  576. package/src/DropdownMenu/DropdownMenuSubMenu.spec.md +47 -41
  577. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +34 -0
  578. package/src/DropdownMenu/MenuBottomSheetActionList.tsx +6 -5
  579. package/src/DropdownMenu/__tests__/Menu.a11y.chromium.spec.ts +19 -7
  580. package/src/DropdownMenu/__tests__/MenuButton.a11y.chromium.spec.ts +21 -9
  581. package/src/DropdownMenu/lazyMenuBottomSheet.test.ts +60 -0
  582. package/src/DropdownMenu/lazyMenuBottomSheet.ts +36 -7
  583. package/src/DropdownMenu/renderDropdownItems.tsx +24 -19
  584. package/src/EmptyState/EmptyState.spec.md +35 -29
  585. package/src/EmptyState/EmptyState.tsx +2 -1
  586. package/src/Field/FieldLabel.tsx +5 -4
  587. package/src/Field/InputClearButton.tsx +3 -3
  588. package/src/Field/PanelSearchInput.tsx +2 -2
  589. package/src/FieldStatus/FieldStatus.tsx +9 -2
  590. package/src/FieldStatus/__tests__/FieldStatusAudit.a11y.chromium.spec.ts +477 -0
  591. package/src/FileInput/FileInput.test.tsx +159 -0
  592. package/src/FileInput/FileInput.tsx +34 -6
  593. package/src/FileInput/__tests__/FileInputAudit.a11y.chromium.spec.ts +796 -0
  594. package/src/FormLayout/FormLayout.spec.md +11 -20
  595. package/src/Heading/Heading.tsx +1 -1
  596. package/src/Icon/Icon.tsx +1 -1
  597. package/src/Indicator/CheckIndicator.spec.md +47 -42
  598. package/src/Indicator/CheckIndicator.tsx +2 -1
  599. package/src/Indicator/CheckboxIndicator.spec.md +40 -37
  600. package/src/Indicator/CheckboxIndicator.tsx +3 -1
  601. package/src/Indicator/Indicator.spec.md +188 -0
  602. package/src/Indicator/RadioIndicator.tsx +3 -1
  603. package/src/Item/Item.test.tsx +60 -0
  604. package/src/Item/Item.tsx +16 -8
  605. package/src/Item/ItemSwipeLayer.tsx +1 -1
  606. package/src/Kbd/Kbd.spec.md +81 -38
  607. package/src/Layer/__tests__/LayerBrowserHide.a11y.chromium.spec.ts +126 -0
  608. package/src/Layer/popoverOperations.test.ts +205 -0
  609. package/src/Layer/popoverOperations.ts +172 -0
  610. package/src/Layer/useLayer.test.tsx +426 -4
  611. package/src/Layer/useLayer.tsx +145 -77
  612. package/src/Layout/Layout.spec.md +127 -131
  613. package/src/Layout/Layout.tsx +1 -1
  614. package/src/Layout/LayoutContent.spec.md +205 -0
  615. package/src/Layout/LayoutContent.tsx +1 -1
  616. package/src/Layout/LayoutFooter.spec.md +190 -0
  617. package/src/Layout/LayoutFooter.tsx +1 -1
  618. package/src/Layout/LayoutHeader.spec.md +193 -0
  619. package/src/Layout/LayoutHeader.tsx +1 -1
  620. package/src/Layout/LayoutPanel.spec.md +194 -0
  621. package/src/Layout/__tests__/Layout.a11y.chromium.spec.ts +18 -6
  622. package/src/Lightbox/Lightbox.test.tsx +18 -0
  623. package/src/Lightbox/Lightbox.tsx +5 -0
  624. package/src/Lightbox/LightboxViewport.a11y.browser.spec.ts +8 -4
  625. package/src/Link/Link.spec.md +3 -2
  626. package/src/Link/Link.tsx +11 -0
  627. package/src/Link/__tests__/Link.a11y.chromium.spec.ts +18 -8
  628. package/src/Link/__tests__/Link.truncation.a11y.chromium.spec.ts +58 -0
  629. package/src/List/List.tsx +1 -1
  630. package/src/List/ListItem.spec.md +205 -0
  631. package/src/List/ListItem.tsx +3 -3
  632. package/src/Markdown/plugins/headingLinks.a11y.chromium.spec.ts +1 -1
  633. package/src/MetadataList/MetadataList.spec.md +187 -0
  634. package/src/MetadataList/MetadataListItem.spec.md +165 -0
  635. package/src/MobileNav/MobileNav.test.tsx +15 -0
  636. package/src/MobileNav/MobileNav.tsx +9 -1
  637. package/src/MobileNav/__tests__/MobileNavHeader.a11y.chromium.spec.ts +89 -0
  638. package/src/MoreMenu/MoreMenu.test.tsx +11 -0
  639. package/src/MultiSelector/CreateRow.a11y.chromium.spec.ts +7 -8
  640. package/src/MultiSelector/MultiSelector.spec.md +7 -4
  641. package/src/MultiSelector/MultiSelector.test.tsx +270 -1
  642. package/src/MultiSelector/MultiSelector.tsx +25 -10
  643. package/src/MultiSelector/__tests__/MultiSelector.listbox.a11y.test.tsx +8 -1
  644. package/src/NavMenu/NavHeadingMenu.spec.md +1 -5
  645. package/src/NavMenu/NavHeadingMenuItem.tsx +5 -39
  646. package/src/NumberInput/NumberInput.doc.mjs +13 -7
  647. package/src/NumberInput/NumberInput.spec.md +59 -37
  648. package/src/NumberInput/NumberInput.test.tsx +68 -7
  649. package/src/NumberInput/NumberInput.tsx +44 -4
  650. package/src/NumberInput/__tests__/NumberInput.coarse-pointer.a11y.chromium.spec.ts +102 -0
  651. package/src/NumberInput/numberParser.ts +7 -45
  652. package/src/Outline/Outline.spec.md +165 -69
  653. package/src/Outline/Outline.test.tsx +67 -2
  654. package/src/Outline/Outline.tsx +23 -0
  655. package/src/Outline/modules/parseOutlineFromMarkdown.spec.md +3 -4
  656. package/src/OverflowList/OverflowList.spec.md +102 -55
  657. package/src/Pagination/Pagination.spec.md +158 -84
  658. package/src/Popover/Popover.test.tsx +84 -0
  659. package/src/Popover/Popover.tsx +34 -14
  660. package/src/Popover/__tests__/PopoverSecondDocument.a11y.chromium.spec.ts +70 -8
  661. package/src/Popover/usePopover.tsx +10 -3
  662. package/src/PowerSearch/PowerSearch.test.tsx +24 -0
  663. package/src/PowerSearch/PowerSearch.tsx +42 -31
  664. package/src/ProgressBar/ProgressBar.spec.md +143 -119
  665. package/src/ProgressBar/ProgressBar.test.tsx +108 -32
  666. package/src/ProgressBar/ProgressBar.tsx +58 -10
  667. package/src/ProgressBar/__tests__/ProgressBar.a11y.chromium.spec.ts +21 -9
  668. package/src/ProgressBar/__tests__/ProgressBarMotion.a11y.chromium.spec.ts +831 -0
  669. package/src/RadioList/RadioList.spec.md +1 -1
  670. package/src/RadioList/RadioList.test.tsx +84 -0
  671. package/src/RadioList/RadioListItem.tsx +11 -2
  672. package/src/Resizable/Resizable.spec.md +144 -124
  673. package/src/Resizable/__tests__/ResizeHandle.a11y.chromium.spec.ts +21 -14
  674. package/src/Resizable/useResizable.test.ts +43 -0
  675. package/src/Resizable/useResizable.ts +32 -9
  676. package/src/SegmentedControl/SegmentedControl.test.tsx +84 -0
  677. package/src/SegmentedControl/SegmentedControlItem.tsx +11 -5
  678. package/src/Selector/Selector.test.tsx +90 -1
  679. package/src/Selector/__tests__/Selector.combobox.a11y.test.tsx +8 -1
  680. package/src/Selector/__tests__/Selector.listbox.a11y.test.tsx +8 -1
  681. package/src/Selector/useSelectorPresentation.ts +31 -3
  682. package/src/SideNav/SideNav.test.tsx +151 -4
  683. package/src/SideNav/SideNavItem.spec.md +14 -24
  684. package/src/SideNav/SideNavItem.tsx +27 -10
  685. package/src/SideNav/__tests__/SideNavRailMotion.interaction.browser.spec.ts +176 -51
  686. package/src/Skeleton/Skeleton.tsx +3 -1
  687. package/src/Slider/Slider.test.tsx +31 -0
  688. package/src/Slider/Slider.tsx +8 -3
  689. package/src/Slider/__tests__/Slider.a11y.chromium.spec.ts +19 -7
  690. package/src/Spinner/Spinner.tsx +5 -3
  691. package/src/Stack/Stack.tsx +1 -1
  692. package/src/Stack/StackItem.tsx +1 -1
  693. package/src/Stepper/Step.spec.md +36 -42
  694. package/src/Stepper/Step.tsx +33 -6
  695. package/src/Stepper/Stepper.doc.mjs +1 -1
  696. package/src/Stepper/Stepper.test.tsx +69 -7
  697. package/src/Switch/Switch.spec.md +1 -1
  698. package/src/Switch/Switch.test.tsx +66 -1
  699. package/src/Switch/Switch.tsx +11 -3
  700. package/src/TabList/TabList.test.tsx +58 -4
  701. package/src/TabList/TabList.tsx +16 -1
  702. package/src/TabList/__tests__/TabPressPointer.interaction.browser.spec.ts +163 -0
  703. package/src/Table/Table.spec.md +1 -1
  704. package/src/Table/Table.test.tsx +32 -0
  705. package/src/Table/Table.tsx +43 -11
  706. package/src/Table/__tests__/Table.a11y.chromium.spec.ts +18 -6
  707. package/src/Table/__tests__/Table.a11y.states.ts +1 -5
  708. package/src/Table/plugins/columnResize/useTableColumnResize.test.tsx +22 -0
  709. package/src/Table/plugins/columnResize/useTableColumnResize.tsx +8 -4
  710. package/src/Table/plugins/sortable/useTableSortable.test.tsx +73 -144
  711. package/src/Table/plugins/sortable/useTableSortable.tsx +44 -73
  712. package/src/Table/plugins/sortable/useTableSortableState.test.tsx +9 -21
  713. package/src/Text/Text.tsx +1 -1
  714. package/src/Text/useTruncation.test.tsx +128 -1
  715. package/src/Text/useTruncation.ts +23 -5
  716. package/src/TextArea/TextArea.spec.md +10 -13
  717. package/src/TextArea/TextArea.test.tsx +60 -0
  718. package/src/TextArea/TextArea.tsx +15 -1
  719. package/src/TextInput/TextInput.test.tsx +21 -0
  720. package/src/TextInput/TextInput.tsx +3 -1
  721. package/src/TimeInput/NativeTimeInput.test.tsx +17 -0
  722. package/src/TimeInput/Presentation.test.tsx +21 -0
  723. package/src/TimeInput/TimeInput.doc.mjs +8 -8
  724. package/src/TimeInput/TimeInput.spec.md +58 -61
  725. package/src/TimeInput/TimeInput.test.tsx +76 -0
  726. package/src/TimeInput/TimeInput.tsx +36 -18
  727. package/src/TimeInput/TouchTimeField.tsx +4 -6
  728. package/src/Timestamp/Timestamp.spec.md +6 -12
  729. package/src/Timestamp/Timestamp.test.tsx +30 -5
  730. package/src/Timestamp/Timestamp.tsx +6 -2
  731. package/src/Timestamp/TimestampHoverCard.tsx +4 -4
  732. package/src/Toast/Toast.spec.md +15 -24
  733. package/src/Toast/Toast.tsx +104 -36
  734. package/src/Toast/ToastViewport.test.tsx +798 -1
  735. package/src/Toast/ToastViewport.tsx +121 -53
  736. package/src/ToggleButton/ToggleButton.test.tsx +27 -0
  737. package/src/ToggleButton/ToggleButtonGroup.tsx +20 -1
  738. package/src/Token/Token.doc.mjs +2 -2
  739. package/src/Token/Token.spec.md +52 -61
  740. package/src/Token/Token.test.tsx +104 -0
  741. package/src/Token/Token.tsx +75 -5
  742. package/src/Token/TokenLink.tsx +21 -7
  743. package/src/Tokenizer/Tokenizer.spec.md +18 -4
  744. package/src/Tokenizer/Tokenizer.test.tsx +176 -0
  745. package/src/Tokenizer/Tokenizer.tsx +48 -12
  746. package/src/Tokenizer/TokenizerBottomSheet.test.tsx +23 -4
  747. package/src/Tokenizer/TokenizerBottomSheet.tsx +3 -3
  748. package/src/Tokenizer/TokenizerClearAllMessageContext.ts +21 -0
  749. package/src/Toolbar/Toolbar.spec.md +5 -6
  750. package/src/Toolbar/Toolbar.test.tsx +30 -0
  751. package/src/Toolbar/Toolbar.tsx +2 -1
  752. package/src/Toolbar/__tests__/Toolbar.a11y.chromium.spec.ts +18 -6
  753. package/src/Tooltip/__tests__/Tooltip.a11y.chromium.spec.ts +18 -7
  754. package/src/TopNav/TopNav.test.tsx +27 -0
  755. package/src/TopNav/TopNavMegaMenu.test.tsx +21 -0
  756. package/src/TopNav/TopNavMegaMenu.tsx +4 -1
  757. package/src/TopNav/TopNavMenu.test.tsx +17 -0
  758. package/src/TopNav/TopNavMenu.tsx +1 -0
  759. package/src/TreeList/TreeList.test.tsx +26 -0
  760. package/src/TreeList/TreeListItem.tsx +26 -4
  761. package/src/Typeahead/BaseTypeahead.doc.mjs +3 -3
  762. package/src/Typeahead/BaseTypeahead.spec.md +45 -45
  763. package/src/Typeahead/BaseTypeahead.tsx +48 -9
  764. package/src/Typeahead/Typeahead.test.tsx +294 -11
  765. package/src/Typeahead/Typeahead.tsx +51 -9
  766. package/src/__tests__/internalModulesNotExperimental.test.ts +88 -0
  767. package/src/__tests__/pressState.ts +8 -4
  768. package/src/gestures/GestureArena.ts +111 -11
  769. package/src/gestures/GestureHost.ts +2064 -0
  770. package/src/gestures/GestureRecognizer.ts +21 -1
  771. package/src/gestures/LongPressGestureRecognizer.ts +4 -0
  772. package/src/gestures/PanGestureRecognizer.ts +4 -0
  773. package/src/gestures/PinchGestureRecognizer.ts +148 -0
  774. package/src/gestures/PressTracker.ts +386 -0
  775. package/src/gestures/README.md +420 -0
  776. package/src/gestures/ScreenEdgePanGestureRecognizer.ts +256 -0
  777. package/src/gestures/SwipeGestureRecognizer.ts +197 -0
  778. package/src/gestures/TapGestureRecognizer.ts +4 -0
  779. package/src/gestures/VelocityTracker.ts +10 -3
  780. package/src/gestures/__tests__/GestureHost.test.ts +2136 -0
  781. package/src/gestures/__tests__/PanGestureRecognizer.test.ts +4 -4
  782. package/src/gestures/__tests__/PinchGestureRecognizer.test.ts +74 -0
  783. package/src/gestures/__tests__/PressTracker.test.ts +275 -0
  784. package/src/gestures/__tests__/ScreenEdgePanGestureRecognizer.test.ts +498 -0
  785. package/src/gestures/__tests__/SwipeGestureRecognizer.test.ts +108 -0
  786. package/src/gestures/__tests__/arena.test.ts +40 -0
  787. package/src/gestures/__tests__/arenaPinchSwipeEdge.test.ts +193 -0
  788. package/src/gestures/__tests__/browser/build-fixture.mjs +46 -0
  789. package/src/gestures/__tests__/browser/fixture.ts +307 -0
  790. package/src/gestures/__tests__/browser/gestures.interaction.browser.spec.ts +1137 -0
  791. package/src/gestures/__tests__/browserNegotiation.test.ts +293 -0
  792. package/src/gestures/__tests__/haptics.test.ts +187 -0
  793. package/src/gestures/__tests__/harness.ts +52 -4
  794. package/src/gestures/__tests__/pressTrackerFactory.test.ts +59 -0
  795. package/src/gestures/__tests__/recognizerKind.test.ts +78 -0
  796. package/src/gestures/__tests__/touchActionRule.test.ts +54 -0
  797. package/src/gestures/__tests__/useGestureRecognizer.test.tsx +570 -0
  798. package/src/gestures/haptics.ts +203 -0
  799. package/src/gestures/index.ts +79 -0
  800. package/src/gestures/nativeScroll.ts +277 -0
  801. package/src/gestures/touchAction.ts +191 -0
  802. package/src/gestures/touchActionRule.ts +157 -0
  803. package/src/gestures/types.ts +30 -9
  804. package/src/gestures/useGestureRecognizer.ts +305 -0
  805. package/src/hooks/index.ts +5 -1
  806. package/src/hooks/modalAnnounce.ts +129 -72
  807. package/src/hooks/scrollKeyboardDelegation.test.ts +33 -0
  808. package/src/hooks/scrollKeyboardDelegation.ts +9 -3
  809. package/src/hooks/useAdaptivePresentation.ts +4 -1
  810. package/src/hooks/useAnnounce.doc.mjs +35 -3
  811. package/src/hooks/useAnnounce.replace.test.tsx +516 -0
  812. package/src/hooks/useAnnounce.ts +209 -102
  813. package/src/hooks/useAnnounceRenderedText.adopters.test.tsx +10 -1
  814. package/src/hooks/useAnnounceRenderedText.ts +17 -3
  815. package/src/hooks/useBusyAnnouncement.ts +7 -10
  816. package/src/hooks/useMenuHover.ts +15 -1
  817. package/src/hooks/useScrollOverflow.doc.mjs +1 -1
  818. package/src/hooks/useScrollOverflow.test.tsx +102 -1
  819. package/src/hooks/useScrollOverflow.ts +59 -10
  820. package/src/i18n/__tests__/useListFormatter.test.tsx +58 -0
  821. package/src/i18n/generated-locales/af-ZA.generated.ts +0 -7
  822. package/src/i18n/generated-locales/ar-SA.generated.ts +0 -6
  823. package/src/i18n/generated-locales/ca-ES.generated.ts +0 -7
  824. package/src/i18n/generated-locales/cs-CZ.generated.ts +0 -6
  825. package/src/i18n/generated-locales/da-DK.generated.ts +0 -6
  826. package/src/i18n/generated-locales/de-DE.generated.ts +0 -6
  827. package/src/i18n/generated-locales/el-GR.generated.ts +0 -7
  828. package/src/i18n/generated-locales/en.generated.ts +9 -6
  829. package/src/i18n/generated-locales/es-ES.generated.ts +0 -7
  830. package/src/i18n/generated-locales/fi-FI.generated.ts +0 -6
  831. package/src/i18n/generated-locales/fr-FR.generated.ts +0 -7
  832. package/src/i18n/generated-locales/he-IL.generated.ts +0 -6
  833. package/src/i18n/generated-locales/hu-HU.generated.ts +0 -6
  834. package/src/i18n/generated-locales/it-IT.generated.ts +0 -7
  835. package/src/i18n/generated-locales/ja-JP.generated.ts +0 -6
  836. package/src/i18n/generated-locales/ko-KR.generated.ts +0 -6
  837. package/src/i18n/generated-locales/nl-NL.generated.ts +0 -6
  838. package/src/i18n/generated-locales/no-NO.generated.ts +0 -6
  839. package/src/i18n/generated-locales/pl-PL.generated.ts +0 -7
  840. package/src/i18n/generated-locales/pseudo.generated.ts +9 -6
  841. package/src/i18n/generated-locales/pt-BR.generated.ts +0 -7
  842. package/src/i18n/generated-locales/pt-PT.generated.ts +0 -7
  843. package/src/i18n/generated-locales/ro-RO.generated.ts +0 -6
  844. package/src/i18n/generated-locales/ru-RU.generated.ts +0 -7
  845. package/src/i18n/generated-locales/sr-SP.generated.ts +0 -6
  846. package/src/i18n/generated-locales/sv-SE.generated.ts +0 -6
  847. package/src/i18n/generated-locales/tr-TR.generated.ts +0 -7
  848. package/src/i18n/generated-locales/uk-UA.generated.ts +0 -7
  849. package/src/i18n/generated-locales/vi-VN.generated.ts +0 -6
  850. package/src/i18n/generated-locales/zh-CN.generated.ts +0 -6
  851. package/src/i18n/generated-locales/zh-TW.generated.ts +0 -6
  852. package/src/i18n/useListFormatter.ts +42 -0
  853. package/src/motion/MEASUREMENTS.md +2 -1
  854. package/src/motion/README.md +113 -33
  855. package/src/motion/__tests__/animator.interaction.browser.spec.ts +843 -0
  856. package/src/motion/__tests__/motionBundle.ts +14 -0
  857. package/src/motion/animator.test.ts +1125 -32
  858. package/src/motion/animator.ts +932 -130
  859. package/src/motion/coast.ts +10 -3
  860. package/src/motion/reducedMotion.ts +12 -2
  861. package/src/motion/reducedMotionPlan.test.ts +26 -0
  862. package/src/motion/reducedMotionPlan.ts +20 -1
  863. package/src/motion/resolveMotion.test.ts +123 -0
  864. package/src/motion/resolveMotion.ts +68 -0
  865. package/src/motion/roleValue.ts +2 -1
  866. package/src/motion/roles.test.ts +21 -4
  867. package/src/motion/uikit/tableImports.test.ts +293 -0
  868. package/src/motion/uikit/timing.ts +15 -1
  869. package/src/motion/uikit/values.test.ts +23 -12
  870. package/src/theme/Theme.doc.mjs +1 -1
  871. package/src/theme/defineTheme.ts +117 -8
  872. package/src/theme/derivedVarRegistry.test.ts +4 -0
  873. package/src/theme/domainTokens/domainTokenDefaults.ts +19 -0
  874. package/src/theme/domainTokens/index.ts +6 -10
  875. package/src/theme/expandMotionScale.test.ts +1 -1
  876. package/src/theme/index.ts +5 -0
  877. package/src/theme/motionKnobs.ts +82 -0
  878. package/src/theme/resolveThemeValues.ts +68 -6
  879. package/src/theme/themeAdaptations.ts +52 -12
  880. package/src/theme/themeMotion.test.ts +620 -0
  881. package/src/theme/themeMotion.ts +221 -0
  882. package/src/theme/tokenReferences.ts +149 -0
  883. package/src/theme/tokens.stylex.ts +10 -0
  884. package/src/theme/tokens.ts +15 -158
  885. package/src/utils/focusOutline.stylex.ts +28 -0
  886. package/src/utils/focusReturn.ts +17 -6
  887. package/src/utils/getNodeText.test.ts +24 -0
  888. package/src/utils/getNodeText.ts +37 -0
  889. package/src/utils/interactionModality.test.ts +45 -1
  890. package/src/utils/interactionModality.ts +64 -5
  891. package/src/utils/interactionOverlay.stylex.ts +12 -3
  892. package/src/utils/plainDate.test.ts +90 -0
  893. package/src/utils/plainDate.ts +58 -3
  894. package/src/utils/presentation.test.ts +380 -0
  895. package/src/utils/presentation.ts +180 -0
  896. package/src/utils/pressFeedback.test.ts +138 -0
  897. package/src/utils/pressFeedback.ts +34 -11
  898. package/src/utils/pressGesture.test.ts +9 -0
  899. package/src/utils/pressPaintPriority.test.ts +80 -0
  900. package/src/utils/primaryClick.test.ts +38 -0
  901. package/src/utils/primaryClick.ts +28 -0
  902. package/src/utils/sharedMutationObserver.test.ts +54 -1
  903. package/src/utils/sharedMutationObserver.ts +87 -29
  904. package/src/utils/timeFormat.test.ts +204 -0
  905. package/src/utils/timeFormat.ts +314 -0
  906. package/src/utils/touchPresentation.stylex.ts +43 -0
  907. package/src/utils/touchPresentation.test.ts +140 -1
  908. package/src/utils/touchPresentation.ts +13 -8
  909. package/src/utils/touchQueries.ts +15 -0
  910. package/src/utils/unicodeDigits.test.ts +44 -0
  911. package/src/utils/unicodeDigits.ts +71 -0
  912. package/src/utils/useFocusAcrossSwap.ts +55 -0
@@ -42,14 +42,16 @@
42
42
  * current value with the current velocity (`spec:AST-094` FR6). A gesture's release velocity
43
43
  * can be handed in explicitly instead.
44
44
  *
45
- * End state without a flicker frame: the element's inline style always holds
46
- * the values the animations END on, and the keyframes hold that end state for
47
- * a while after the curve ends (END_HOLD_MS). The main thread drops a finished
48
- * animation as soon as it runs after the curve's end; the inline style already
49
- * shows the same values, so nothing moves. The hold matters when the curve
50
- * ends during a main-thread block: WebKit's compositor ends an animation by
51
- * falling back to the value its main thread last committed, which is
52
- * mid-flight.
45
+ * No frame shows a value the element is not at. While a curve runs, the
46
+ * element's inline style holds the value the curve starts from (the value on
47
+ * screen when it was built), so a frame painted before the compositor has the
48
+ * curve (WebKit can receive a new curve a few updates late) shows the element
49
+ * where it is, never where it is going. The keyframes hold the end state for a
50
+ * while after the curve ends (END_HOLD_MS); the main thread retires a finished
51
+ * animation as soon as it runs after the curve's end, writing the end values
52
+ * inline in the same task that cancels it, so nothing moves. The hold matters
53
+ * when the curve ends during a main-thread block: WebKit's compositor ends an
54
+ * animation by falling back to the value its main thread last committed.
53
55
  *
54
56
  * Start time: a call that starts from rest (nothing on its channels moving,
55
57
  * no `options.at`) gets no start time, so the browser starts it when it
@@ -62,20 +64,40 @@
62
64
  * `options.at` to line several animators up, so the new curve continues
63
65
  * from the frame on screen. Keyframes are sampled from the call's start, so
64
66
  * a value that keeps moving through a rebuild stays on its curve to the
65
- * frame.
67
+ * frame. `options.start` changes that per call: `'commit'` dates a retarget
68
+ * by the browser's commit as well, and `'presented'` creates the animations
69
+ * of a call from rest two frames later, once its element at rest has been
70
+ * presented (a UI process that applies commits late); a retarget still starts
71
+ * now, from the value and velocity on screen.
72
+ * `handle.curve(property)` hands out the curve a call plays, so a
73
+ * companion can follow it on the same clock.
74
+ * `options.additive` retargets as UIKit does: the old curve keeps going and a
75
+ * curve of the change between the targets is added on top, baked into one
76
+ * animation (two animations on one property leave the compositor in both
77
+ * engines), so the retarget keeps the velocity on screen.
66
78
  *
67
- * WebKit starts an animation created just before a block at its last frame
68
- * time before the block, so there the motion still skips into its curve;
69
- * Chromium starts it after the block.
79
+ * WebKit dates an animation created just before a block at its last frame
80
+ * time before the block, where the first frame after it would show the
81
+ * motion skipped into its curve; when the call's own task ran on more than
82
+ * two frames, the call's first read of that start moves it to that read, so
83
+ * WebKit delays the motion as Chromium's commit does (startAfterBlock). Every
84
+ * call of that task moves together, and a shorter task or a read that other
85
+ * tasks delay keeps the browser's start, so a sequence chained on a call's
86
+ * end (a Reduce Motion cross-fade's second half) keeps its clock.
70
87
  *
71
88
  * Promotion: Mobile Safari runs an animation whose start time is set from
72
- * script on its compositor at its first commit only if the element already
73
- * has a compositing layer; without one, a block right after that commit
74
- * freezes it (iOS 26.2 simulator: 2 of 7 runs kept moving). Every animation
75
- * the animator creates, and every `set`, therefore promotes its channels in
76
- * the same task: inline `will-change` on the element, merged with the
77
- * element's own. That is enough (5 of 5, and 4 of 4 through the animator);
78
- * promotion ends PROMOTION_LINGER_MS after the last motion.
89
+ * script on its compositor at its first commit only if the element (or the
90
+ * pseudo-element) already has a compositing layer; without one, a block
91
+ * right after that commit freezes it (iOS 26.2 simulator: 2 of 7 runs kept
92
+ * moving, 0 of 5 on a ::before). Every animation the animator creates, and
93
+ * every `set` (unless it passes `{promote: false}`), therefore promotes its
94
+ * channels in the same task: inline
95
+ * `will-change` on the element, merged with the element's own, or the custom
96
+ * property `--astryx-motion-will-change-<pseudo>` on the host for a
97
+ * pseudo-element, whose style opts in with
98
+ * `will-change: var(--astryx-motion-will-change-before, auto)`. That is
99
+ * enough (5 of 5, and 4 of 4 through the animator); promotion ends
100
+ * PROMOTION_LINGER_MS after the last motion.
79
101
  *
80
102
  * Known limits, iOS Safari (measured on the iOS 26.2 simulator):
81
103
  * - a block in the task that starts a motion delays it: it starts when the
@@ -112,8 +134,8 @@
112
134
  * call that lands too carries a landing still waiting (two calls in one
113
135
  * frame land together), and a later opacity change lands it at once;
114
136
  * - on any other primary pointer (DR3) it completes at once.
115
- * No call option and no theme value lengthens the fade or keeps travel (DR4):
116
- * the fade's length is not a theme role.
137
+ * No call option and no role value lengthens the fade or keeps travel (DR4):
138
+ * the fade's length is not a role.
117
139
  *
118
140
  * Momentum under Reduce Motion (`design:reduced-motion` DR2, DEC-2): a
119
141
  * decay's momentum continues the velocity a finger handed it on release
@@ -125,18 +147,38 @@
125
147
  * Motion policy above, a cross-fade on a coarse pointer or after a touch
126
148
  * release (`touchRelease`) and at once elsewhere (DR2, DR3).
127
149
  *
150
+ * Roles: every spring and curve the animator plays passes through
151
+ * resolveMotion.ts, which names the motion role it plays (`springs.settle`
152
+ * once `registerSpringsTable()` has run, the Reduce Motion fade's curve,
153
+ * which the animator registers alone). The per-role tables stay internal
154
+ * (`spec:AST-094` DEC-15), so a role plays its table value: nothing reads a
155
+ * CSS variable or the element's style for it. A spring written inline at the call
156
+ * site, and a table never registered, play as given; the fade's length is not
157
+ * a role.
158
+ *
159
+ * A pseudo-element (`options.pseudoElement`, a dialog's `::backdrop`) has no
160
+ * inline style: its end value is held by a static filling animation (after a
161
+ * curve ends, and after `set`) until the next animation replaces it, and for
162
+ * as long as the pseudo-element exists. The browser makes a `::backdrop`
163
+ * again each time its dialog opens, without the hold, so a presentation
164
+ * calls `set` with its starting value right after `showModal()`, in the same
165
+ * task: a `set` before it lands on the backdrop the open replaces.
166
+ *
128
167
  * SSR-safe: nothing touches `window` or `document` at module scope, and an
129
168
  * animator created without an element only keeps state until one is attached.
130
169
  *
131
170
  * SYNC: When modified, update:
132
171
  * - /packages/core/src/motion/animator.test.ts
133
172
  * - /packages/core/src/motion/reducedMotionPlan.ts (the Reduce Motion plan)
173
+ * - /packages/core/src/motion/__tests__/animator.interaction.browser.spec.ts
174
+ * - /packages/core/src/motion/resolveMotion.ts (the roles it resolves)
134
175
  * - /packages/core/src/motion/README.md
135
176
  */
136
177
 
137
178
  import { cubicBezier } from "./bezier.js";
138
179
  import { solveSpring, toSpring } from "./spring.js";
139
- import { reducedMotionCrossFade } from "./uikit/timing.js";
180
+ import { resolveMotion } from "./resolveMotion.js";
181
+ import { reducedMotionCrossFade, registerReducedMotionCrossFade } from "./uikit/timing.js";
140
182
  import { planReducedMotion } from "./reducedMotionPlan.js";
141
183
 
142
184
  /**
@@ -167,6 +209,7 @@ import { planReducedMotion } from "./reducedMotionPlan.js";
167
209
  /**
168
210
  * Options of `createAnimator`.
169
211
  */
212
+ /** How `set` puts values in place. */
170
213
 
171
214
  /**
172
215
  * One `animate` / `decay` call's animations.
@@ -225,32 +268,97 @@ export const SETTLE_THRESHOLD = {
225
268
  opacity: 0.001
226
269
  };
227
270
 
228
- /** Keyframes are added until linear interpolation is within this. */
271
+ /**
272
+ * Keyframes are added until linear interpolation is within this: a quarter of
273
+ * a device pixel (this quarter of a CSS pixel, divided by the device pixel
274
+ * ratio where it is above 1), a twentieth of a degree, a 2000th of the size,
275
+ * about one step of an 8-bit alpha. Every one is below what a moving element
276
+ * can show.
277
+ */
229
278
  const SAMPLE_TOLERANCE = {
230
- x: 0.05,
231
- y: 0.05,
232
- rotate: 0.02,
233
- scaleX: 0.0002,
234
- scaleY: 0.0002,
235
- opacity: 0.002
279
+ x: 0.25,
280
+ y: 0.25,
281
+ rotate: 0.05,
282
+ scaleX: 0.0005,
283
+ scaleY: 0.0005,
284
+ opacity: 0.004
236
285
  };
237
286
 
287
+ /** Keyframes start on this grid (ms) and are split where the curve needs it. */
288
+ const SAMPLE_GRID_MS = 1000 / 30;
289
+
238
290
  /** A curve that has not settled by then (an undamped spring) snaps. */
239
291
  const MAX_DURATION_MS = 30_000;
292
+
293
+ /**
294
+ * How long a task must run on past its first call from rest before that
295
+ * counts as a block (WebKit; startAfterBlock): two frames at 60 Hz.
296
+ */
297
+ // Browser start times are frame times and a task's end a live clock, so only a block longer than a frame plus the task's own length can be told apart from that quantization.
298
+ const LATE_START_MS = 34;
299
+
300
+ /**
301
+ * The task calls from rest are made in, shared by every call made in it
302
+ * (every animator's), so one motion's parts that are separate calls start
303
+ * together (startAfterBlock).
304
+ */
305
+
306
+ /** The task the current calls from rest are made in, until it ends. */
307
+ let openTask = null;
308
+
309
+ /** The mark of the running task, opened by its first call from rest. */
310
+ function markTask(time, clock) {
311
+ if (openTask == null) {
312
+ const task = {
313
+ first: time
314
+ };
315
+ openTask = task;
316
+ queueMicrotask(() => {
317
+ task.ended = clock();
318
+ openTask = null;
319
+ });
320
+ }
321
+ return openTask;
322
+ }
323
+
240
324
  /** Above this many keyframes the tolerance is relaxed. */
241
325
  const MAX_KEYFRAMES = 1200;
242
326
  /**
243
327
  * The keyframes hold the end state this long after a curve ends. An engine
244
328
  * whose compositor ends an animation while the main thread is blocked falls
245
- * back to the value its main thread last committed, mid-flight (WebKit); the
246
- * hold keeps the end state on screen through such a block. The main thread
247
- * drops the animation as soon as it runs after the curve's end.
329
+ * back to the value its main thread last committed, the curve's start
330
+ * (WebKit on Linux); the hold keeps the end state on screen through any such
331
+ * block. It only stretches the last keyframe. The main thread retires the
332
+ * animation as soon as it runs after the curve's end.
333
+ *
334
+ * Why a tail inside the curve's own animation, with a bound (measured Oct 24
335
+ * 2026; do not replace it without these proofs):
336
+ * - WebKit on Linux (WebKitGTK and WPE) ignores `fill` on its compositor:
337
+ * a 400 ms move that ends during a 1 s main-thread block snaps back to the
338
+ * block-start position 13 ms after its end, with `fill: forwards` or with
339
+ * no fill, and holds with this tail. iOS 26.2 Mobile Safari holds the end
340
+ * in all three forms, so there the tail is unneeded but harmless (measured
341
+ * Oct 25 2026). The browser proof "a spring that ends inside the block
342
+ * keeps showing its end state" catches it.
343
+ * - A separate static animation of the end state under the curve would hold
344
+ * it without a bound, but two animations on one property push Chromium to
345
+ * run the curve on the main thread: the 1 s block proof moved in 0 of 57
346
+ * frames, the start-before-a-block proof failed, and seeking the curve
347
+ * broke.
248
348
  */
249
- export const END_HOLD_MS = 5000;
349
+ export const END_HOLD_MS = 60_000;
250
350
 
251
351
  /** How often a paused animation is looked at again for retiring, ms. */
252
352
  const RETIRE_RECHECK_MS = 100;
253
353
 
354
+ /**
355
+ * The soonest a running animation's end is looked for again, ms: a frame at
356
+ * 60 Hz. WebKit moves an animation's currentTime once per frame, so a look
357
+ * within a frame reads the frame's time, a fraction of a ms short of the end,
358
+ * and a timer for that fraction would fire again before anything moved.
359
+ */
360
+ const END_RECHECK_MS = 1000 / 60;
361
+
254
362
  /** How long an element stays promoted after its last motion, ms. */
255
363
  export const PROMOTION_LINGER_MS = 500;
256
364
  const CHANNELS = {
@@ -285,7 +393,7 @@ function format(channel, value) {
285
393
  const shared = new WeakMap();
286
394
 
287
395
  /**
288
- * The one animator for `element`, created on
396
+ * The one animator for `element` (and `options.pseudoElement`), created on
289
397
  * first use. Code that animates one element from several places (a swipe on
290
398
  * x, a removal on y) shares it, so their curves compose in one `translate`
291
399
  * track and retargeting one axis leaves the other on its curve; two
@@ -294,10 +402,16 @@ const shared = new WeakMap();
294
402
  * elsewhere or `dispose` it: it lives as long as the element.
295
403
  */
296
404
  export function animatorFor(element, options = {}) {
297
- let animator = shared.get(element);
405
+ let byPseudo = shared.get(element);
406
+ if (byPseudo == null) {
407
+ byPseudo = new Map();
408
+ shared.set(element, byPseudo);
409
+ }
410
+ const key = options.pseudoElement ?? '';
411
+ let animator = byPseudo.get(key);
298
412
  if (animator == null) {
299
413
  animator = createAnimator(element, options);
300
- shared.set(element, animator);
414
+ byPseudo.set(key, animator);
301
415
  }
302
416
  return animator;
303
417
  }
@@ -401,8 +515,9 @@ const REDUCED_TRANSITION = {
401
515
  * @example
402
516
  * ```
403
517
  * const animator = createAnimator(sheet);
404
- * // finger lifts at 1200 px/s heading for the detent at 0:
405
- * animator.animate({y: 0}, {spring: springs.sheetDetent, velocity: {y: 1200}});
518
+ * // finger lifts at 1200 px/s heading for the detent at 0 (a component
519
+ * // passes the spring of its motion role):
520
+ * animator.animate({y: 0}, {spring: {response: 0.45, dampingRatio: 0.9}, velocity: {y: 1200}});
406
521
  * // the finger lands again: where is it right now?
407
522
  * const y = animator.get('y', event.timeStamp);
408
523
  * animator.stop(['y']);
@@ -413,6 +528,7 @@ export function createAnimator(element, options = {}) {
413
528
  const requestFrame = options.requestFrame ?? (typeof requestAnimationFrame === 'function' ? callback => {
414
529
  requestAnimationFrame(() => callback());
415
530
  } : null);
531
+ const pseudoElement = options.pseudoElement;
416
532
  // Reduced Motion reads the person's settings and nothing else: no option
417
533
  // overrides them (design:reduced-motion DR4).
418
534
  const prefersReducedMotion = defaultPrefersReducedMotion;
@@ -462,7 +578,18 @@ export function createAnimator(element, options = {}) {
462
578
  let ownWillChange = null;
463
579
  /** The stylesheet's will-change when there is no inline value. */
464
580
  let sheetWillChange = '';
581
+ /**
582
+ * Whether sheetWillChange holds a read of the element's current style: it
583
+ * is read in the task after the element is attached, and again after each
584
+ * demotion, so a promotion (a drag's first move) reads no style in its
585
+ * own task.
586
+ */
587
+ let sheetWillChangeRead = false;
588
+ /** The pending read of sheetWillChange, cancelled with its element. */
589
+ let sheetReadTimer = null;
465
590
  let demoteTimer = null;
591
+ /** A pseudo-element is promoted through a custom property on its host. */
592
+ const promotionProperty = pseudoElement == null ? null : `--astryx-motion-will-change-${pseudoElement.replace(/^:+/, '')}`;
466
593
  /** Channels whose identity the last node held inline (see `attach`). */
467
594
  let heldIdentity = new Set();
468
595
 
@@ -532,18 +659,21 @@ export function createAnimator(element, options = {}) {
532
659
  // -- writing --------------------------------------------------------------
533
660
 
534
661
  const finalValue = property => segments.get(property)?.target ?? resting[property];
535
- const writeInline = (channel, value) => {
536
- if (target == null) {
662
+ const writeInline = (channel, value, release = true) => {
663
+ if (target == null || pseudoElement != null) {
537
664
  return;
538
665
  }
539
666
  touched.add(channel);
540
667
  const text = inlineText(channel, value);
541
- if (text === IDENTITY_TEXT[channel]) {
542
- // Identity leaves the element when nothing else would move it.
668
+ // An unchanged value is not written: a style write invalidates the
669
+ // element, and WebKit can repaint sticky content stale when that lands in
670
+ // the frame a scroll commits.
671
+ if (target.style.getPropertyValue(channel) !== text) {
543
672
  target.style.setProperty(channel, text);
673
+ }
674
+ if (release && text === IDENTITY_TEXT[channel]) {
675
+ // Identity leaves the element when nothing else would move it.
544
676
  releaseIdentity(channel);
545
- } else {
546
- target.style.setProperty(channel, text);
547
677
  }
548
678
  };
549
679
  const sampleTimes = (property, from, to, tolerance) => {
@@ -563,9 +693,9 @@ export function createAnimator(element, options = {}) {
563
693
  for (let e = 0; e + 1 < edges.length; e++) {
564
694
  const a = edges[e];
565
695
  const b = edges[e + 1];
566
- // A 120 Hz grid, each interval split until the chord is within the
696
+ // A 30 Hz grid, each interval split until the chord is within the
567
697
  // tolerance at its quarter points.
568
- const steps = Math.max(1, Math.ceil((b - a) / (1000 / 120)));
698
+ const steps = Math.max(1, Math.ceil((b - a) / SAMPLE_GRID_MS));
569
699
  const split = (t0, t1, depth) => {
570
700
  const v0 = value(t0);
571
701
  const v1 = t1 === b && breaks.includes(b) ? valueBefore(property, b) : value(t1);
@@ -588,14 +718,37 @@ export function createAnimator(element, options = {}) {
588
718
  }
589
719
  return times;
590
720
  };
721
+
722
+ /** A pseudo-element's resting value, held by a static filling animation. */
723
+ const hold = (channel, time) => {
724
+ if (target == null) {
725
+ return;
726
+ }
727
+ const value = format(channel, finalValue);
728
+ const animation = target.animate([{
729
+ [channel]: value
730
+ }, {
731
+ [channel]: value
732
+ }], {
733
+ duration: 1,
734
+ fill: 'both',
735
+ pseudoElement
736
+ });
737
+ animation.startTime = time;
738
+ running.set(channel, animation);
739
+ };
591
740
  const rebuild = (channel, time) => {
592
741
  const previous = running.get(channel);
593
742
  running.delete(channel);
594
743
  clearTimeout(retireTimers.get(channel));
595
744
  retireTimers.delete(channel);
596
- // The element's inline style holds the end state, so its old animation
597
- // can go first.
598
- previous?.cancel();
745
+ // An element's inline style takes the value on screen below, so its old
746
+ // animation can go first. A pseudo-element has none: its old animation
747
+ // keeps holding the value until the new one exists (same task, no frame in
748
+ // between).
749
+ if (pseudoElement == null) {
750
+ previous?.cancel();
751
+ }
599
752
  const properties = CHANNELS[channel];
600
753
  // Settled curves become resting values.
601
754
  for (const property of properties) {
@@ -605,13 +758,23 @@ export function createAnimator(element, options = {}) {
605
758
  segments.delete(property);
606
759
  }
607
760
  }
608
- writeInline(channel, finalValue);
609
761
  const moving = properties.filter(p => segments.has(p));
762
+ if (moving.length === 0 || target == null || typeof target.animate !== 'function') {
763
+ writeInline(channel, finalValue);
764
+ } else {
765
+ // The value on screen as the curve starts: what a frame painted before
766
+ // the compositor has the curve shows. The end is written at retire.
767
+ writeInline(channel, p => valueAt(p, time));
768
+ }
610
769
  if (target == null || typeof target.animate !== 'function') {
611
770
  previous?.cancel();
612
771
  return;
613
772
  }
614
773
  if (moving.length === 0) {
774
+ if (pseudoElement != null) {
775
+ hold(channel, time);
776
+ }
777
+ previous?.cancel();
615
778
  return;
616
779
  }
617
780
  // A channel rebuilt by an explicit call (set, rebase, a retarget of
@@ -624,6 +787,10 @@ export function createAnimator(element, options = {}) {
624
787
  const from = waiting?.provisional ?? time;
625
788
  const end = Math.min(from + MAX_DURATION_MS, Math.max(...moving.map(p => segments.get(p).start + segments.get(p).duration)));
626
789
  if (end <= from) {
790
+ if (pseudoElement != null) {
791
+ hold(channel, time);
792
+ }
793
+ previous?.cancel();
627
794
  return;
628
795
  }
629
796
  if (callGroup != null) {
@@ -646,10 +813,14 @@ export function createAnimator(element, options = {}) {
646
813
  }
647
814
  }
648
815
  }
816
+ // Read where the keyframes are baked: a page moved to another screen
817
+ // bakes its next motion for that screen.
818
+ const devicePixel = 1 / Math.max(1, globalThis.devicePixelRatio || 1);
649
819
  const collect = scale => {
650
820
  const times = new Set([from, end]);
651
821
  for (const property of moving) {
652
- for (const t of sampleTimes(property, from, end, SAMPLE_TOLERANCE[property] * scale)) {
822
+ const tolerance = SAMPLE_TOLERANCE[property] * scale * (property === 'x' || property === 'y' ? devicePixel : 1);
823
+ for (const t of sampleTimes(property, from, end, tolerance)) {
653
824
  times.add(t);
654
825
  }
655
826
  }
@@ -699,10 +870,13 @@ export function createAnimator(element, options = {}) {
699
870
  duration: span,
700
871
  // The last keyframes hold the end state (END_HOLD_MS); filling both
701
872
  // ways also keeps it where an engine honors the fill on its compositor.
702
- // The main thread drops the animation once it runs after the end; the
703
- // inline style already holds the same values, so that changes no pixel.
873
+ // The main thread retires the animation once it runs after the end,
874
+ // writing the end inline in that task, so that changes no pixel.
704
875
  fill: 'both',
705
- easing: 'linear'
876
+ easing: 'linear',
877
+ ...(pseudoElement != null ? {
878
+ pseudoElement
879
+ } : {})
706
880
  });
707
881
  if (waiting != null) {
708
882
  // From rest: no start time, so the browser starts the animation when
@@ -723,7 +897,16 @@ export function createAnimator(element, options = {}) {
723
897
 
724
898
  /**
725
899
  * Once the main thread runs after the curve's end, the animation leaves the
726
- * running state: the element's inline style already shows the end values.
900
+ * running state: an element's end values are written inline in the task
901
+ * that cancels it; a pseudo-element's end value moves to a static holding
902
+ * animation, created before the long one goes.
903
+ *
904
+ * Why a timer at the curve's end: no browser event reports that an
905
+ * animation's time has reached a point inside its effect, and its
906
+ * `finished` comes only after the END_HOLD_MS tail, which would keep the
907
+ * element promoted and the animation alive for a minute. The timer is set
908
+ * on the curve's own clock and re-armed while a sampler pauses or seeks the
909
+ * animation, so it never retires a held one.
727
910
  */
728
911
  const scheduleRetire = (channel, animation, end) => {
729
912
  clearTimeout(retireTimers.get(channel));
@@ -736,11 +919,34 @@ export function createAnimator(element, options = {}) {
736
919
  // reaches the curve's end, never from the wall clock.
737
920
  const remaining = remainingCurve(animation);
738
921
  if (remaining != null && remaining > 0) {
739
- retireTimers.set(channel, setTimeout(retire, animation.playState === 'paused' ? RETIRE_RECHECK_MS : remaining));
922
+ retireTimers.set(channel, setTimeout(retire, animation.playState === 'paused' ? RETIRE_RECHECK_MS : Math.max(remaining, END_RECHECK_MS)));
740
923
  return;
741
924
  }
742
925
  running.delete(channel);
926
+ // A pseudo-element holds its resting value, unless the stylesheet
927
+ // takes it back now (a borrowed dip that has ended).
928
+ const handsBack = channel === 'opacity' && borrowedOpacity != null && ![...landings].some(landing => landing.fadeIn?.isBorrowed === true);
929
+ if (pseudoElement != null && !handsBack) {
930
+ hold(channel, now());
931
+ } else {
932
+ // The end goes inline in the task that cancels the animation. Whether
933
+ // an identity end may leave the element is judged after the cancel:
934
+ // until then the end-state tail still holds the end, so the computed
935
+ // style would hide a stylesheet value (an opacity 0) under it.
936
+ writeInline(channel, finalValue, false);
937
+ }
938
+ // A call from rest the browser never started (finished from outside
939
+ // before its first frame, a sampler's finish()): read its start from the
940
+ // animation before the cancel takes it, and with nothing left to wait
941
+ // on the call keeps its own clock, so its landing is still armed.
942
+ const waiting = [...pendingGroups].filter(group => group.animations.includes(animation));
943
+ for (const group of waiting) {
944
+ syncGroup(group);
945
+ }
743
946
  animation.cancel();
947
+ for (const group of waiting) {
948
+ resolveGroup(group, group.provisional);
949
+ }
744
950
  releaseIdentity(channel);
745
951
  flushReleases();
746
952
  };
@@ -750,20 +956,30 @@ export function createAnimator(element, options = {}) {
750
956
  /** The element's own (stylesheet) opacity, read once when a dip starts. */
751
957
  const ownOpacity = () => {
752
958
  const view = target?.ownerDocument.defaultView;
753
- const value = target == null ? NaN : Number.parseFloat(view?.getComputedStyle(target).getPropertyValue('opacity') ?? '');
959
+ const value = target == null ? NaN : Number.parseFloat(view?.getComputedStyle(target, pseudoElement ?? null).getPropertyValue('opacity') ?? '');
754
960
  return Number.isFinite(value) ? Math.min(1, Math.max(0, value)) : 1;
755
961
  };
756
962
 
757
963
  /**
758
964
  * Whether the animator holds an opacity of its own on the element: an inline
759
- * value it wrote (a `set` over a stylesheet that hides or dims it). A dip
760
- * returns to that value.
965
+ * value it wrote, or a pseudo-element's holding animation (a `set` over a
966
+ * stylesheet that hides or dims it). A dip returns to that value.
761
967
  */
762
- const writesOwnOpacity = () => (target?.style.getPropertyValue('opacity') ?? '') !== '';
968
+ const writesOwnOpacity = () => pseudoElement == null ? (target?.style.getPropertyValue('opacity') ?? '') !== '' : running.has('opacity');
763
969
 
764
- /** Gives the element's opacity back to its stylesheet: its inline value goes. */
970
+ /**
971
+ * Gives the element's opacity back to its stylesheet: an element's inline
972
+ * value goes; a pseudo-element, which has no inline style, loses the
973
+ * animation holding its value.
974
+ */
765
975
  const releaseOwnOpacity = () => {
766
- target?.style.removeProperty('opacity');
976
+ if (pseudoElement == null) {
977
+ target?.style.removeProperty('opacity');
978
+ return;
979
+ }
980
+ const held = running.get('opacity');
981
+ running.delete('opacity');
982
+ held?.cancel();
767
983
  };
768
984
 
769
985
  /**
@@ -844,6 +1060,9 @@ export function createAnimator(element, options = {}) {
844
1060
  releaseOwnOpacity();
845
1061
  return;
846
1062
  }
1063
+ if (pseudoElement != null) {
1064
+ return;
1065
+ }
847
1066
  if (target.style.getPropertyValue(channel) !== IDENTITY_TEXT[channel]) {
848
1067
  return;
849
1068
  }
@@ -903,9 +1122,17 @@ export function createAnimator(element, options = {}) {
903
1122
 
904
1123
  // -- promotion -------------------------------------------------------------
905
1124
 
906
- /** Writes the promoted channels as will-change. */
1125
+ /** Writes the promoted channels as will-change (or the pseudo's property). */
907
1126
  const writePromotion = element => {
908
1127
  const list = [...promoted].join(', ');
1128
+ if (promotionProperty != null) {
1129
+ if (list === '') {
1130
+ element.style.removeProperty(promotionProperty);
1131
+ } else {
1132
+ element.style.setProperty(promotionProperty, list);
1133
+ }
1134
+ return;
1135
+ }
909
1136
  if (list === '') {
910
1137
  element.style.willChange = ownWillChange ?? '';
911
1138
  ownWillChange = null;
@@ -914,8 +1141,12 @@ export function createAnimator(element, options = {}) {
914
1141
  if (ownWillChange == null) {
915
1142
  ownWillChange = element.style.willChange;
916
1143
  // Without an inline value, the stylesheet's reasons stay alongside the
917
- // promotion's (read once, as the promotion starts).
918
- sheetWillChange = ownWillChange === '' ? element.ownerDocument.defaultView?.getComputedStyle(element).getPropertyValue('will-change') ?? '' : '';
1144
+ // promotion's. They were read in the task after the element was
1145
+ // attached; a promotion that comes first (an element attached in this
1146
+ // task that moves at once) reads them now.
1147
+ if (ownWillChange === '' && !sheetWillChangeRead) {
1148
+ readSheetWillChange(element);
1149
+ }
919
1150
  }
920
1151
  const base = ownWillChange !== '' ? ownWillChange : sheetWillChange;
921
1152
  const own = base === 'auto' ? '' : base;
@@ -923,8 +1154,46 @@ export function createAnimator(element, options = {}) {
923
1154
  element.style.willChange = [...reasons, ...promoted].join(', ');
924
1155
  };
925
1156
 
1157
+ /** Reads the element's own will-change while no promotion of ours is written. */
1158
+ const readSheetWillChange = element => {
1159
+ sheetWillChange = element.ownerDocument.defaultView?.getComputedStyle(element).getPropertyValue('will-change') ?? '';
1160
+ sheetWillChangeRead = true;
1161
+ };
1162
+
926
1163
  /**
927
- * Gives the element a compositing layer for
1164
+ * Reads sheetWillChange in a task of its own, so a later promotion reads no
1165
+ * style in its own task. Skipped while a promotion of ours is written,
1166
+ * which the read would see (demote asks again), and for a node out of the
1167
+ * document. A pseudo-element's promotion is its own property, with
1168
+ * nothing to read.
1169
+ */
1170
+ const readSheetWillChangeLater = () => {
1171
+ cancelSheetWillChangeRead();
1172
+ sheetWillChangeRead = false;
1173
+ if (target == null || promotionProperty != null) {
1174
+ return;
1175
+ }
1176
+ const element = target;
1177
+ sheetReadTimer = setTimeout(() => {
1178
+ sheetReadTimer = null;
1179
+ // A node out of the document has no style to read, and reading one
1180
+ // still costs a style pass: a shared animator (animatorFor) is never
1181
+ // detached, so its node can leave with this read waiting. Skipped, the
1182
+ // read waits for a promotion that needs it.
1183
+ if (target === element && promoted.size === 0 && element.isConnected) {
1184
+ readSheetWillChange(element);
1185
+ }
1186
+ }, 0);
1187
+ };
1188
+ const cancelSheetWillChangeRead = () => {
1189
+ if (sheetReadTimer != null) {
1190
+ clearTimeout(sheetReadTimer);
1191
+ sheetReadTimer = null;
1192
+ }
1193
+ };
1194
+
1195
+ /**
1196
+ * Gives the element (or its pseudo-element) a compositing layer for
928
1197
  * `channel` from the task that starts the motion: Mobile Safari runs an
929
1198
  * animation whose start time is set from script on its compositor at its
930
1199
  * first commit only if the element already has a layer.
@@ -971,6 +1240,8 @@ export function createAnimator(element, options = {}) {
971
1240
  promoted.clear();
972
1241
  if (target != null) {
973
1242
  writePromotion(target);
1243
+ // Its stylesheet may have changed its will-change since.
1244
+ readSheetWillChangeLater();
974
1245
  }
975
1246
  };
976
1247
 
@@ -982,7 +1253,7 @@ export function createAnimator(element, options = {}) {
982
1253
  * pins its clock (`at`). Returns its start group, or null for an explicit
983
1254
  * start.
984
1255
  */
985
- const beginGroup = (time, properties, at) => {
1256
+ const beginGroup = (time, properties, at, start) => {
986
1257
  if (target == null || typeof target.animate !== 'function') {
987
1258
  return null;
988
1259
  }
@@ -1009,7 +1280,11 @@ export function createAnimator(element, options = {}) {
1009
1280
  }
1010
1281
  return null;
1011
1282
  }
1012
- for (const channel of channels) {
1283
+ // A call that continues motion starts now unless it asks for the
1284
+ // browser's start (`commit`). `presented` asks only for a call from rest:
1285
+ // an element still moving is not at rest, so a retarget starts now, from
1286
+ // the value and velocity on screen (spec:AST-094 FR6).
1287
+ for (const channel of start === 'commit' ? [] : channels) {
1013
1288
  for (const property of CHANNELS[channel]) {
1014
1289
  const segment = segments.get(property);
1015
1290
  if (segment != null && time < segment.start + segment.duration && (segment.group == null || segment.group.resolved)) {
@@ -1023,6 +1298,7 @@ export function createAnimator(element, options = {}) {
1023
1298
  });
1024
1299
  return {
1025
1300
  provisional: time,
1301
+ fresh: false,
1026
1302
  segments: [],
1027
1303
  animations: [],
1028
1304
  channels: new Set(),
@@ -1033,7 +1309,7 @@ export function createAnimator(element, options = {}) {
1033
1309
  };
1034
1310
 
1035
1311
  /** Commits a call's changes, from rest when it has a start group. */
1036
- const commitCall = (group, owner, changed, time) => {
1312
+ const commitCall = (group, owner, changed, time, presented = false) => {
1037
1313
  if (group != null) {
1038
1314
  for (const property of changed) {
1039
1315
  const segment = segments.get(property);
@@ -1043,6 +1319,88 @@ export function createAnimator(element, options = {}) {
1043
1319
  }
1044
1320
  }
1045
1321
  }
1322
+ if (presented && group != null && requestFrame != null) {
1323
+ // At rest until then: the animations, and the layer they promote, come
1324
+ // two frames later. Promoting now, a layer at rest for two frames, left
1325
+ // a stale paint of the element's rest in WebKit on iOS 26.2 (a title in
1326
+ // a scroller inside a clipped card) after the motion ended.
1327
+ // Each call waits its own two frames: one queued after another change
1328
+ // flushed the queue, or after an earlier call's first frame, still
1329
+ // waits its two.
1330
+ const call = {
1331
+ group,
1332
+ changed
1333
+ };
1334
+ deferredCalls.push(call);
1335
+ requestFrame(() => requestFrame(() => flushDeferredThrough(call)));
1336
+ return;
1337
+ }
1338
+ startCall(group, changed, time);
1339
+ };
1340
+
1341
+ /** Calls with `start: 'presented'` waiting for their second frame. */
1342
+ const deferredCalls = [];
1343
+
1344
+ /** Creates the animations of the given waiting calls, in call order. */
1345
+ const startDeferred = calls => {
1346
+ for (const {
1347
+ group,
1348
+ changed
1349
+ } of calls) {
1350
+ // Not a channel that holds the curve of a later call still waiting: a
1351
+ // later presented call that took a property over starts that channel
1352
+ // with its own two frames. Every other property starts here, whatever
1353
+ // its segment's group: a value Reduce Motion writes at once, or lands
1354
+ // under a dip, has no curve of this call's.
1355
+ const own = [];
1356
+ let handedTo = null;
1357
+ for (const property of changed) {
1358
+ const holder = CHANNELS[CHANNEL_OF[property]].map(other => segments.get(other)?.group).find(waiting => waiting != null && waiting !== group && deferredCalls.some(call => call.group === waiting));
1359
+ if (holder == null) {
1360
+ own.push(property);
1361
+ continue;
1362
+ }
1363
+ // A curve of this call's in that channel never ran: the element held
1364
+ // it at its start. It starts with the later call, which creates the
1365
+ // channel, dated from that call's start, so the model reads what the
1366
+ // screen shows.
1367
+ const segment = segments.get(property);
1368
+ if (segment != null && segment.group === group) {
1369
+ segment.start += holder.provisional - group.provisional;
1370
+ segment.group = holder;
1371
+ holder.segments.push(segment);
1372
+ group.segments.splice(group.segments.indexOf(segment), 1);
1373
+ handedTo = holder;
1374
+ }
1375
+ }
1376
+ if (own.length === 0 && handedTo != null) {
1377
+ // Everything this call still plays starts with the later call.
1378
+ const adopter = handedTo;
1379
+ group.adoptedBy = adopter;
1380
+ void adopter.started.then(start => resolveGroup(group, start));
1381
+ continue;
1382
+ }
1383
+ // From the call's own time: the curve starts at the browser's commit.
1384
+ startCall(group, own, group.provisional);
1385
+ }
1386
+ };
1387
+
1388
+ /** Creates the animations of every waiting call, in call order. */
1389
+ const flushDeferred = () => {
1390
+ startDeferred(deferredCalls.splice(0));
1391
+ };
1392
+
1393
+ /**
1394
+ * A call's second frame: it starts, with every call queued before it (in
1395
+ * call order), unless another change created it already.
1396
+ */
1397
+ const flushDeferredThrough = call => {
1398
+ const index = deferredCalls.indexOf(call);
1399
+ if (index >= 0) {
1400
+ startDeferred(deferredCalls.splice(0, index + 1));
1401
+ }
1402
+ };
1403
+ const startCall = (group, changed, time) => {
1046
1404
  callGroup = group;
1047
1405
  try {
1048
1406
  commit(changed, time);
@@ -1057,6 +1415,14 @@ export function createAnimator(element, options = {}) {
1057
1415
  return;
1058
1416
  }
1059
1417
  pendingGroups.add(group);
1418
+ group.fresh = true;
1419
+ // The task that creates the animations, not the call's: a presented
1420
+ // call's is its second frame's callback, wherever in its frame the call
1421
+ // was made.
1422
+ group.task = markTask(now(), now);
1423
+ queueMicrotask(() => {
1424
+ group.fresh = false;
1425
+ });
1060
1426
  for (const animation of group.animations) {
1061
1427
  // A cancel before the first frame rejects each one's ready promise.
1062
1428
  animation.ready?.catch(() => {});
@@ -1070,7 +1436,10 @@ export function createAnimator(element, options = {}) {
1070
1436
  // or when its compositor starts them (Chromium). Read it in that first
1071
1437
  // frame, ahead of anything that might pause or seek the animations, and
1072
1438
  // when `ready` settles.
1073
- requestFrame?.(() => syncGroup(group));
1439
+ requestFrame?.(() => {
1440
+ syncGroup(group);
1441
+ group.framed = true;
1442
+ });
1074
1443
  ready.then(() => syncGroup(group), () => settleCancelled(group));
1075
1444
  };
1076
1445
 
@@ -1118,7 +1487,7 @@ export function createAnimator(element, options = {}) {
1118
1487
  }
1119
1488
  for (const animation of group.animations) {
1120
1489
  if (animation.startTime != null) {
1121
- resolveGroup(group, Number(animation.startTime));
1490
+ resolveGroup(group, startAfterBlock(group, Number(animation.startTime)));
1122
1491
  return;
1123
1492
  }
1124
1493
  }
@@ -1139,10 +1508,16 @@ export function createAnimator(element, options = {}) {
1139
1508
  }
1140
1509
  };
1141
1510
 
1142
- /** Reads the start of every call whose first frame has been committed. */
1511
+ /**
1512
+ * Reads the start of every call whose first frame may have been committed:
1513
+ * not those created in the running task, whose start the browser cannot
1514
+ * have set (reading it there can cost a style update per call).
1515
+ */
1143
1516
  const syncPending = () => {
1144
1517
  for (const group of pendingGroups) {
1145
- syncGroup(group);
1518
+ if (!group.fresh) {
1519
+ syncGroup(group);
1520
+ }
1146
1521
  }
1147
1522
  syncFinished();
1148
1523
  };
@@ -1170,6 +1545,50 @@ export function createAnimator(element, options = {}) {
1170
1545
  }
1171
1546
  };
1172
1547
 
1548
+ /**
1549
+ * The start of a call from rest, on the frame that commits it. Chromium,
1550
+ * like Core Animation, starts a pending animation when it commits it, so a
1551
+ * main-thread block later in the call's task delays the motion; WebKit
1552
+ * dates it at its last frame time before that task, so the first frame
1553
+ * after the block would show it skipped into its curve. When the task ran
1554
+ * on more than LATE_START_MS past its first call, a start the browser put
1555
+ * by the task's first animations (a presented call's second frame, not the
1556
+ * call) and more than LATE_START_MS before the call's first read (its
1557
+ * `ready`, once the task has ended, or the first frame after it) moves to
1558
+ * that read, with every animation of the call, and every call of the task
1559
+ * moves to the same read. A shorter task, or a read other tasks delay,
1560
+ * keeps the browser's start.
1561
+ */
1562
+ const startAfterBlock = (group, start) => {
1563
+ const timeline = typeof document === 'undefined' ? null : document.timeline?.currentTime;
1564
+ // A start well after the animations were created is the browser's
1565
+ // commit of them.
1566
+ if (timeline == null || group.framed === true || start > (group.task?.first ?? group.provisional) + LATE_START_MS) {
1567
+ return start;
1568
+ }
1569
+ const {
1570
+ task
1571
+ } = group;
1572
+ // A read in the task's first microtasks comes after its end too.
1573
+ const ended = task?.ended ?? now();
1574
+ if (task == null || ended - task.first <= LATE_START_MS) {
1575
+ return start;
1576
+ }
1577
+ // Read once the task has ended (its `ready`) or in the first frame after
1578
+ // it, both after the block; the task's other calls take the same read.
1579
+ const at = task.at ?? Math.max(now(), timeline);
1580
+ if (at - start <= LATE_START_MS) {
1581
+ return start;
1582
+ }
1583
+ task.at = at;
1584
+ for (const animation of group.animations) {
1585
+ if (animation.playState !== 'idle') {
1586
+ animation.startTime = at;
1587
+ }
1588
+ }
1589
+ return at;
1590
+ };
1591
+
1173
1592
  /** Moves a call from rest onto the time the browser started it. */
1174
1593
  const resolveGroup = (group, start) => {
1175
1594
  if (group.resolved) {
@@ -1208,10 +1627,7 @@ export function createAnimator(element, options = {}) {
1208
1627
  }
1209
1628
  clearTimeout(owner.timer);
1210
1629
  const ends = group.segments.filter(segment => segment.owner === owner).map(segment => segment.start + segment.duration);
1211
- owner.timer = setTimeout(() => {
1212
- owner.timer = null;
1213
- settle(owner, true);
1214
- }, Math.max(0, Math.max(start, ...ends) - now()));
1630
+ owner.timer = setTimeout(() => settleAtEnd(owner), Math.max(0, Math.max(start, ...ends) - now()));
1215
1631
  }
1216
1632
  }
1217
1633
  group.resolve(start);
@@ -1241,26 +1657,70 @@ export function createAnimator(element, options = {}) {
1241
1657
  }
1242
1658
  owner.resolve(finished);
1243
1659
  };
1244
- const makeHandle = (owner, properties, finished, time, group = null) => {
1660
+
1661
+ /**
1662
+ * A handle whose curves have reached their end on the wall clock finishes,
1663
+ * unless a sampler holds one of its animations (paused, or sought back):
1664
+ * then it waits on that animation's own time, as retiring does
1665
+ * (scheduleRetire), so `finished` never resolves under motion still on
1666
+ * screen.
1667
+ */
1668
+ const settleAtEnd = owner => {
1669
+ owner.timer = null;
1670
+ let wait = 0;
1671
+ for (const [channel, animation] of running) {
1672
+ if (!CHANNELS[channel].some(property => segments.get(property)?.owner === owner)) {
1673
+ continue;
1674
+ }
1675
+ const remaining = remainingCurve(animation);
1676
+ if (remaining != null && remaining > 0) {
1677
+ wait = Math.max(wait, animation.playState === 'paused' ? RETIRE_RECHECK_MS : Math.max(remaining, END_RECHECK_MS));
1678
+ }
1679
+ }
1680
+ if (wait > 0) {
1681
+ owner.timer = setTimeout(() => settleAtEnd(owner), wait);
1682
+ return;
1683
+ }
1684
+ settle(owner, true);
1685
+ };
1686
+ const makeHandle = (owner, properties, finished, time, group = null, settlesWithLanding = false) => {
1245
1687
  const ends = properties.map(p => {
1246
1688
  const segment = segments.get(p);
1247
1689
  return segment != null && segment.owner === owner ? segment.start + segment.duration : time;
1248
1690
  });
1249
1691
  const end = Math.max(time, ...ends);
1250
- if (properties.length === 0 || end <= time) {
1692
+ if (settlesWithLanding) {
1693
+ // The landing it joined settles it.
1694
+ } else if (properties.length === 0 || end <= time) {
1251
1695
  settle(owner, true);
1252
1696
  } else {
1253
1697
  // Interruptions settle false as they happen (interrupt); reaching the
1254
1698
  // end untouched is completion.
1255
- owner.timer = setTimeout(() => {
1256
- owner.timer = null;
1257
- settle(owner, true);
1258
- }, Math.max(0, end - now()));
1699
+ owner.timer = setTimeout(() => settleAtEnd(owner), Math.max(0, end - now()));
1700
+ }
1701
+ // The call's own curves, as it started them.
1702
+ const curves = new Map();
1703
+ for (const property of properties) {
1704
+ const segment = segments.get(property);
1705
+ if (segment != null && segment.owner === owner) {
1706
+ curves.set(property, segment);
1707
+ }
1259
1708
  }
1260
1709
  const handle = {
1261
1710
  properties,
1262
1711
  finished,
1263
1712
  started: group?.started ?? Promise.resolve(time),
1713
+ curve: property => {
1714
+ const segment = curves.get(property === 'scale' ? 'scaleX' : property);
1715
+ if (segment == null) {
1716
+ return null;
1717
+ }
1718
+ return {
1719
+ duration: segment.duration / 1000,
1720
+ at: t => t * 1000 >= segment.duration ? segment.target : segment.at(Math.max(0, t * 1000)),
1721
+ velocity: t => t * 1000 >= segment.duration ? 0 : segment.speed(t * 1000)
1722
+ };
1723
+ },
1264
1724
  value: (property, at = now()) => {
1265
1725
  syncPending();
1266
1726
  return valueAt(property, at);
@@ -1309,7 +1769,9 @@ export function createAnimator(element, options = {}) {
1309
1769
  if (from === to && velocity === 0) {
1310
1770
  return null;
1311
1771
  }
1312
- const curve = solveSpring(toSpring(spring), {
1772
+ // The motion role it plays: its table value (DEC-15).
1773
+ const resolved = resolveMotion(target, spring);
1774
+ const curve = solveSpring(toSpring(resolved), {
1313
1775
  from,
1314
1776
  to,
1315
1777
  velocity
@@ -1323,11 +1785,58 @@ export function createAnimator(element, options = {}) {
1323
1785
  speed: t => curve.velocity(t / 1000),
1324
1786
  jumps: [],
1325
1787
  owner,
1326
- spring
1788
+ spring: resolved
1789
+ };
1790
+ };
1791
+
1792
+ /** The retarget of `additive`: the old curve plus a spring of the difference. */
1793
+ const additiveSegment = (owner, property, start, to, spring, old) => {
1794
+ const oldEnd = old.start + old.duration;
1795
+ const resolved = resolveMotion(target, spring);
1796
+ const delta = solveSpring(toSpring(resolved), {
1797
+ from: 0,
1798
+ to: to - old.target,
1799
+ velocity: 0
1800
+ });
1801
+ const deltaMs = Math.min(MAX_DURATION_MS, delta.settleTime(SETTLE_THRESHOLD[property]) * 1000);
1802
+ const ownAt = t => t >= deltaMs ? to - old.target : delta.value(t / 1000);
1803
+ const oldAt = time => time >= oldEnd ? old.target : old.at(Math.max(0, time - old.start));
1804
+ return {
1805
+ start,
1806
+ duration: Math.min(MAX_DURATION_MS, Math.max(oldEnd - start, deltaMs)),
1807
+ target: to,
1808
+ at: t => oldAt(start + t) + ownAt(t),
1809
+ speed: t => (start + t >= oldEnd ? 0 : old.speed(start + t - old.start)) + (t >= deltaMs ? 0 : delta.velocity(t / 1000)),
1810
+ jumps: old.jumps.map(jump => old.start + jump - start).filter(jump => jump > 0),
1811
+ owner,
1812
+ spring: resolved
1813
+ };
1814
+ };
1815
+
1816
+ /**
1817
+ * `additive` for a played curve: the old curve plus the new curve's shape,
1818
+ * scaled to the difference between the two targets.
1819
+ */
1820
+ const additiveCurveSegment = (owner, start, curve, old) => {
1821
+ const from = curve.at(0);
1822
+ const to = curve.at(curve.duration);
1823
+ const scale = (to - old.target) / (to - from);
1824
+ const ms = Math.min(MAX_DURATION_MS, curve.duration * 1000);
1825
+ const oldEnd = old.start + old.duration;
1826
+ const oldAt = time => time >= oldEnd ? old.target : old.at(Math.max(0, time - old.start));
1827
+ return {
1828
+ start,
1829
+ duration: Math.min(MAX_DURATION_MS, Math.max(oldEnd - start, ms)),
1830
+ target: to,
1831
+ at: t => oldAt(start + t) + (t >= ms ? to - old.target : (curve.at(t / 1000) - from) * scale),
1832
+ speed: t => (start + t >= oldEnd ? 0 : old.speed(start + t - old.start)) + (t >= ms ? 0 : curve.velocity(t / 1000) * scale),
1833
+ jumps: old.jumps.map(jump => old.start + jump - start).filter(jump => jump > 0),
1834
+ owner
1327
1835
  };
1328
1836
  };
1329
1837
  const fadeSegment = (owner, start, stops, jumps = []) => {
1330
- const ease = cubicBezier(reducedMotionCrossFade.curve);
1838
+ registerReducedMotionCrossFade();
1839
+ const ease = cubicBezier(resolveMotion(target, reducedMotionCrossFade.curve));
1331
1840
  const duration = stops[stops.length - 1].at;
1332
1841
  const at = t => {
1333
1842
  for (let i = 0; i + 1 < stops.length; i++) {
@@ -1447,6 +1956,27 @@ export function createAnimator(element, options = {}) {
1447
1956
  };
1448
1957
  };
1449
1958
 
1959
+ /**
1960
+ * A call joins the newest waiting dip: it takes the landing over and
1961
+ * settles when the dip ends, and the call it replaces lands with it. Each
1962
+ * value keeps the call whose move it is.
1963
+ */
1964
+ const joinWaitingDip = owner => {
1965
+ const dip = [...landings].reverse().find(landing => landing.fadeIn != null);
1966
+ if (dip == null) {
1967
+ settle(owner, true);
1968
+ return;
1969
+ }
1970
+ for (const property of dip.values.keys()) {
1971
+ if (!dip.owners.has(property)) {
1972
+ dip.owners.set(property, dip.owner);
1973
+ }
1974
+ }
1975
+ dip.carried.push(dip.owner);
1976
+ carriedOwners.add(dip.owner);
1977
+ dip.owner = owner;
1978
+ };
1979
+
1450
1980
  /** Where opacity is heading: past a waiting landing's fade back in. */
1451
1981
  const opacityHeading = () => {
1452
1982
  let to = finalValue('opacity');
@@ -1500,8 +2030,9 @@ export function createAnimator(element, options = {}) {
1500
2030
  * never an animation (DR2: opacity only), so it is never shown in the wrong
1501
2031
  * place. In a dip the fade back in starts from here and takes what is left
1502
2032
  * of the cross-fade, so the dip ends when it was due even when a busy main
1503
- * thread runs this timer late; past the whole fade back in (over 100 ms
1504
- * late) the element appears at once where it landed.
2033
+ * thread runs this timer late; past the whole fade back in (100 ms late or
2034
+ * more) the element appears at once where it landed, with no animation,
2035
+ * and the call settles then.
1505
2036
  */
1506
2037
  const land = landing => {
1507
2038
  landings.delete(landing);
@@ -1514,13 +2045,16 @@ export function createAnimator(element, options = {}) {
1514
2045
  changed.push(property);
1515
2046
  }
1516
2047
  let end = time;
1517
- if (landing.fadeIn != null) {
1518
- // The fade back in takes what is left of the cross-fade: a timer that
1519
- // a busy main thread runs late shortens it, so the dip still ends
1520
- // when it was due (design:reduced-motion DR2, 200 ms or less), and the
1521
- // element is never shown before it lands.
1522
- const late = landing.due == null ? 0 : Math.max(0, time - landing.due);
1523
- const ms = Math.max(1, landing.fadeIn.ms - late);
2048
+ // The fade back in takes what is left of the cross-fade: a timer that a
2049
+ // busy main thread runs late shortens it, so the dip still ends when it
2050
+ // was due (design:reduced-motion DR2, 200 ms or less), and the element is
2051
+ // never shown before it lands. Past the whole fade back in nothing is
2052
+ // left: the element appears at once, a plain write with no fade for the
2053
+ // browser to start a frame later, so the call settles showing it.
2054
+ const late = landing.due == null ? 0 : Math.max(0, time - landing.due);
2055
+ const appears = landing.fadeIn != null && late >= landing.fadeIn.ms;
2056
+ if (landing.fadeIn != null && !appears) {
2057
+ const ms = landing.fadeIn.ms - late;
1524
2058
  segments.set('opacity', fadeSegment(landing.owner, time, [{
1525
2059
  at: 0,
1526
2060
  value: valueAt('opacity', time)
@@ -1530,17 +2064,20 @@ export function createAnimator(element, options = {}) {
1530
2064
  }]));
1531
2065
  changed.push('opacity');
1532
2066
  end = time + ms;
2067
+ } else if (landing.fadeIn != null) {
2068
+ segments.delete('opacity');
2069
+ resting.opacity = landing.fadeIn.isBorrowed === true ? IDENTITY.opacity : landing.fadeIn.to;
2070
+ changed.push('opacity');
1533
2071
  } else if (landing.restore != null) {
1534
2072
  segments.delete('opacity');
1535
2073
  resting.opacity = landing.restoreIsBorrowed === true ? IDENTITY.opacity : landing.restore;
1536
2074
  changed.push('opacity');
1537
2075
  }
1538
2076
  commit(changed, time);
1539
- if (landing.restoreIsBorrowed === true) {
2077
+ if (landing.restoreIsBorrowed === true || appears && landing.fadeIn?.isBorrowed === true) {
1540
2078
  // The stylesheet owns its opacity again.
1541
2079
  releaseOwnOpacity();
1542
- }
1543
- if (landing.fadeIn?.isBorrowed === true) {
2080
+ } else if (landing.fadeIn?.isBorrowed === true) {
1544
2081
  // The fade back in returns to the stylesheet's opacity: it owns it
1545
2082
  // again once the fade ends (releaseIdentity).
1546
2083
  borrowedOpacity = landing.fadeIn.to;
@@ -1561,10 +2098,7 @@ export function createAnimator(element, options = {}) {
1561
2098
  if (end <= time) {
1562
2099
  settle(owner, true);
1563
2100
  } else {
1564
- owner.timer = setTimeout(() => {
1565
- owner.timer = null;
1566
- settle(owner, true);
1567
- }, Math.max(0, end - now()));
2101
+ owner.timer = setTimeout(() => settleAtEnd(owner), Math.max(0, end - now()));
1568
2102
  }
1569
2103
  };
1570
2104
 
@@ -1645,6 +2179,9 @@ export function createAnimator(element, options = {}) {
1645
2179
  },
1646
2180
  get hasPendingLanding() {
1647
2181
  return landings.size > 0;
2182
+ },
2183
+ get hasWaitingDip() {
2184
+ return [...landings].some(landing => landing.fadeIn != null);
1648
2185
  }
1649
2186
  };
1650
2187
 
@@ -1677,7 +2214,8 @@ export function createAnimator(element, options = {}) {
1677
2214
  next,
1678
2215
  holds: plan.holds,
1679
2216
  landing: plan.landing,
1680
- borrowed: plan.borrowed
2217
+ borrowed: plan.borrowed,
2218
+ joins: plan.joins
1681
2219
  };
1682
2220
  };
1683
2221
  const animator = {
@@ -1694,6 +2232,7 @@ export function createAnimator(element, options = {}) {
1694
2232
  if (next === target) {
1695
2233
  return;
1696
2234
  }
2235
+ flushDeferred();
1697
2236
  if (next == null) {
1698
2237
  // Unmount, unless a node replaces this one in the same task (React's
1699
2238
  // replacement order: attach(null), then the new node): nothing is
@@ -1729,6 +2268,9 @@ export function createAnimator(element, options = {}) {
1729
2268
  }
1730
2269
  retireTimers.clear();
1731
2270
  demote();
2271
+ // demote() asks for a fresh will-change read of the node it
2272
+ // demotes; a detached node gets none.
2273
+ cancelSheetWillChangeRead();
1732
2274
  });
1733
2275
  lastDetached = null;
1734
2276
  const time = now();
@@ -1747,7 +2289,11 @@ export function createAnimator(element, options = {}) {
1747
2289
  }
1748
2290
  // After the landing's commit, which can promote the element again.
1749
2291
  demote();
2292
+ // A pseudo-element holds an identity with a static animation, which the
2293
+ // cancel below drops: note the channels to hold again on the next node
2294
+ // (never a borrowed opacity, which is the stylesheet's).
1750
2295
  const isOpacityBorrowed = borrowedOpacity != null || [...landings].some(landing => landing.restoreIsBorrowed === true);
2296
+ const pseudoHeld = pseudoElement == null || target == null ? null : new Set(Object.keys(CHANNELS).filter(channel => running.has(channel) && !(channel === 'opacity' && isOpacityBorrowed) && CHANNELS[channel].every(p => !segments.has(p) && resting[p] === IDENTITY[p])));
1751
2297
  for (const animation of running.values()) {
1752
2298
  animation.cancel();
1753
2299
  }
@@ -1767,10 +2313,13 @@ export function createAnimator(element, options = {}) {
1767
2313
  // differs, kept through a detach for the node that comes next.
1768
2314
  if (target != null) {
1769
2315
  const outgoing = target;
1770
- heldIdentity = new Set(Object.keys(CHANNELS).filter(channel => outgoing.style.getPropertyValue(channel) === IDENTITY_TEXT[channel]));
2316
+ heldIdentity = pseudoHeld ?? new Set(Object.keys(CHANNELS).filter(channel => outgoing.style.getPropertyValue(channel) === IDENTITY_TEXT[channel]));
1771
2317
  }
1772
2318
  const held = heldIdentity;
1773
2319
  target = next;
2320
+ // A new node: its own will-change is read again.
2321
+ cancelSheetWillChangeRead();
2322
+ sheetWillChangeRead = false;
1774
2323
  if (target == null) {
1775
2324
  return;
1776
2325
  }
@@ -1792,11 +2341,17 @@ export function createAnimator(element, options = {}) {
1792
2341
  } else if (held.has(channel)) {
1793
2342
  // An identity the animator held inline over a stylesheet that
1794
2343
  // differs goes onto the new node too (writeInline keeps it only
1795
- // where the new node's stylesheet still differs).
1796
- writeInline(channel, property => resting[property]);
2344
+ // where the new node's stylesheet still differs); a pseudo-element's
2345
+ // is held again.
2346
+ if (pseudoElement != null) {
2347
+ hold(channel, time);
2348
+ } else {
2349
+ writeInline(channel, property => resting[property]);
2350
+ }
1797
2351
  }
1798
2352
  }
1799
2353
  flushReleases();
2354
+ readSheetWillChangeLater();
1800
2355
  },
1801
2356
  get(property, time = now()) {
1802
2357
  syncPending();
@@ -1806,8 +2361,9 @@ export function createAnimator(element, options = {}) {
1806
2361
  syncPending();
1807
2362
  return velocityAt(property === 'scale' ? 'scaleX' : property, time);
1808
2363
  },
1809
- set(values) {
2364
+ set(values, setOptions = {}) {
1810
2365
  syncPending();
2366
+ flushDeferred();
1811
2367
  const time = now();
1812
2368
  const next = expand(values);
1813
2369
  for (const [property, value] of Object.entries(next)) {
@@ -1816,13 +2372,18 @@ export function createAnimator(element, options = {}) {
1816
2372
  resting[property] = value;
1817
2373
  }
1818
2374
  // Direct manipulation: the layer makes each write a composite only.
1819
- for (const property of Object.keys(next)) {
1820
- promote(CHANNEL_OF[property]);
2375
+ if (setOptions.promote !== false) {
2376
+ for (const property of Object.keys(next)) {
2377
+ promote(CHANNEL_OF[property]);
2378
+ }
1821
2379
  }
1822
2380
  commit(Object.keys(next), time);
1823
2381
  },
1824
2382
  animate(to, transition, animateOptions = {}) {
1825
2383
  syncPending();
2384
+ if (animateOptions.start !== 'presented') {
2385
+ flushDeferred();
2386
+ }
1826
2387
  const time = animateOptions.at ?? now();
1827
2388
  const targets = expand(to);
1828
2389
  const velocities = expand(transition.velocity ?? {});
@@ -1839,11 +2400,16 @@ export function createAnimator(element, options = {}) {
1839
2400
  Object.assign(next, plan.next);
1840
2401
  } else {
1841
2402
  for (const property of properties) {
2403
+ const running = animateOptions.additive === true && velocities[property] == null ? segmentAt(property, time) : null;
2404
+ if (running != null && !isHeld(running)) {
2405
+ next[property] = additiveSegment(owner, property, time, targets[property], transition.spring, running);
2406
+ continue;
2407
+ }
1842
2408
  const velocity = velocities[property] ?? velocityAt(property, time);
1843
2409
  next[property] = springSegment(owner, property, time, targets[property], transition.spring, velocity);
1844
2410
  }
1845
2411
  }
1846
- const group = beginGroup(time, Object.keys(next), animateOptions.at);
2412
+ const group = beginGroup(time, Object.keys(next), animateOptions.at, animateOptions.start);
1847
2413
  const adopted = plan?.landing != null ? adoptLandings(plan.landing, Object.keys(next)) : null;
1848
2414
  const changed = [];
1849
2415
  for (const [property, segment] of Object.entries(next)) {
@@ -1858,12 +2424,15 @@ export function createAnimator(element, options = {}) {
1858
2424
  segments.set(property, segment);
1859
2425
  }
1860
2426
  }
1861
- commitCall(group, owner, changed, time);
2427
+ commitCall(group, owner, changed, time, animateOptions.start === 'presented' && animateOptions.at == null);
1862
2428
  if (plan?.borrowed != null) {
1863
2429
  // The dip's own commit cleared it; the borrow lasts the dip.
1864
2430
  borrowedOpacity = plan.borrowed;
1865
2431
  }
1866
- const handle = makeHandle(owner, changed, finished, time, group);
2432
+ if (plan?.joins === true) {
2433
+ joinWaitingDip(owner);
2434
+ }
2435
+ const handle = plan?.joins === true ? makeHandle(owner, ['opacity'], finished, time, group, true) : makeHandle(owner, changed, finished, time, group);
1867
2436
  if (plan?.landing != null) {
1868
2437
  scheduleLanding(owner, handle.started, plan.landing, adopted);
1869
2438
  }
@@ -1871,6 +2440,9 @@ export function createAnimator(element, options = {}) {
1871
2440
  },
1872
2441
  play(curves, playOptions = {}) {
1873
2442
  syncPending();
2443
+ if (playOptions.start !== 'presented') {
2444
+ flushDeferred();
2445
+ }
1874
2446
  const time = playOptions.at ?? now();
1875
2447
  const {
1876
2448
  owner,
@@ -1905,6 +2477,11 @@ export function createAnimator(element, options = {}) {
1905
2477
  continue;
1906
2478
  }
1907
2479
  const curve = byProperty[property];
2480
+ const running = playOptions.additive === true ? segmentAt(property, time) : null;
2481
+ if (running != null && !isHeld(running) && curve.duration > 0 && Math.abs(curve.at(curve.duration) - curve.at(0)) > 1e-9) {
2482
+ next[property] = additiveCurveSegment(owner, time, curve, running);
2483
+ continue;
2484
+ }
1908
2485
  next[property] = curve.duration === 0 ? null : {
1909
2486
  start: time,
1910
2487
  duration: Math.min(MAX_DURATION_MS, curve.duration * 1000),
@@ -1915,7 +2492,7 @@ export function createAnimator(element, options = {}) {
1915
2492
  owner
1916
2493
  };
1917
2494
  }
1918
- const group = beginGroup(time, Object.keys(next), playOptions.at);
2495
+ const group = beginGroup(time, Object.keys(next), playOptions.at, playOptions.start);
1919
2496
  const adopted = plan?.landing != null ? adoptLandings(plan.landing, Object.keys(next)) : null;
1920
2497
  const changed = [];
1921
2498
  for (const [property, segment] of Object.entries(next)) {
@@ -1930,12 +2507,15 @@ export function createAnimator(element, options = {}) {
1930
2507
  segments.set(property, segment);
1931
2508
  }
1932
2509
  }
1933
- commitCall(group, owner, changed, time);
2510
+ commitCall(group, owner, changed, time, playOptions.start === 'presented' && playOptions.at == null);
1934
2511
  if (plan?.borrowed != null) {
1935
2512
  // The dip's own commit cleared it; the borrow lasts the dip.
1936
2513
  borrowedOpacity = plan.borrowed;
1937
2514
  }
1938
- const handle = makeHandle(owner, changed, finished, time, group);
2515
+ if (plan?.joins === true) {
2516
+ joinWaitingDip(owner);
2517
+ }
2518
+ const handle = plan?.joins === true ? makeHandle(owner, ['opacity'], finished, time, group, true) : makeHandle(owner, changed, finished, time, group);
1939
2519
  if (plan?.landing != null) {
1940
2520
  scheduleLanding(owner, handle.started, plan.landing, adopted);
1941
2521
  }
@@ -1943,6 +2523,7 @@ export function createAnimator(element, options = {}) {
1943
2523
  },
1944
2524
  decay(curves, decayOptions = {}) {
1945
2525
  syncPending();
2526
+ flushDeferred();
1946
2527
  const time = decayOptions.at ?? now();
1947
2528
  // Under Reduce Motion only momentum keeps moving (DR2, DEC-2): a curve
1948
2529
  // that is a transition plays as `animate` does, a cross-fade or at once.
@@ -2009,6 +2590,7 @@ export function createAnimator(element, options = {}) {
2009
2590
  },
2010
2591
  stop(properties) {
2011
2592
  syncPending();
2593
+ flushDeferred();
2012
2594
  const time = now();
2013
2595
  const list = properties == null ? PROPERTIES : expandList(properties);
2014
2596
  const changed = [];
@@ -2037,6 +2619,7 @@ export function createAnimator(element, options = {}) {
2037
2619
  },
2038
2620
  rebase(deltas, rebaseOptions = {}) {
2039
2621
  syncPending();
2622
+ flushDeferred();
2040
2623
  const time = rebaseOptions.at ?? now();
2041
2624
  const changed = [];
2042
2625
  const owners = new Set();
@@ -2108,10 +2691,7 @@ export function createAnimator(element, options = {}) {
2108
2691
  end = Math.max(end, segment.start + segment.duration);
2109
2692
  }
2110
2693
  }
2111
- owner.timer = setTimeout(() => {
2112
- owner.timer = null;
2113
- settle(owner, true);
2114
- }, Math.max(0, end - now()));
2694
+ owner.timer = setTimeout(() => settleAtEnd(owner), Math.max(0, end - now()));
2115
2695
  }
2116
2696
  },
2117
2697
  async atRest(properties) {
@@ -2155,6 +2735,7 @@ export function createAnimator(element, options = {}) {
2155
2735
  });
2156
2736
  },
2157
2737
  dispose() {
2738
+ flushDeferred();
2158
2739
  // A Reduce Motion move still waiting to land is written at its end
2159
2740
  // state, so the element is left visible where it was going (the node
2160
2741
  // just detached, when an unmount is pending); its call and the calls
@@ -2183,6 +2764,7 @@ export function createAnimator(element, options = {}) {
2183
2764
  retireTimers.clear();
2184
2765
  handBackBorrow();
2185
2766
  demote();
2767
+ cancelSheetWillChangeRead();
2186
2768
  target = null;
2187
2769
  }
2188
2770
  };