@astryxdesign/core 0.7.5-canary.fccd771 → 0.7.5

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 (1346) hide show
  1. package/CHANGELOG.md +211 -10
  2. package/README.md +15 -12
  3. package/dist/AlertDialog/AlertDialog.js +1 -1
  4. package/dist/AppShell/AppShell.d.ts +0 -22
  5. package/dist/AppShell/AppShell.d.ts.map +1 -1
  6. package/dist/AppShell/AppShell.js +155 -1
  7. package/dist/Avatar/AvatarStatusDot.js +2 -2
  8. package/dist/Badge/Badge.d.ts.map +1 -1
  9. package/dist/Badge/Badge.js +18 -2
  10. package/dist/Banner/Banner.d.ts +1 -0
  11. package/dist/Banner/Banner.d.ts.map +1 -1
  12. package/dist/Banner/Banner.js +64 -9
  13. package/dist/BottomSheet/BottomSheet.d.ts +53 -5
  14. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  15. package/dist/BottomSheet/BottomSheet.js +435 -198
  16. package/dist/BottomSheet/BottomSheetHostContext.d.ts +8 -0
  17. package/dist/BottomSheet/BottomSheetHostContext.d.ts.map +1 -0
  18. package/dist/BottomSheet/BottomSheetHostContext.js +35 -0
  19. package/dist/BottomSheet/BottomSheetPanel.d.ts +9 -1
  20. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
  21. package/dist/BottomSheet/BottomSheetPanel.js +77 -23
  22. package/dist/BottomSheet/BottomSheetSwitcher.d.ts +53 -14
  23. package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
  24. package/dist/BottomSheet/BottomSheetSwitcher.js +229 -27
  25. package/dist/BottomSheet/BottomSheetSwitcherContext.d.ts +6 -0
  26. package/dist/BottomSheet/BottomSheetSwitcherContext.d.ts.map +1 -1
  27. package/dist/BottomSheet/bottomSheetEscape.d.ts +3 -0
  28. package/dist/BottomSheet/bottomSheetEscape.d.ts.map +1 -0
  29. package/dist/BottomSheet/bottomSheetEscape.js +20 -0
  30. package/dist/BottomSheet/bottomSheetStack.d.ts +262 -0
  31. package/dist/BottomSheet/bottomSheetStack.d.ts.map +1 -0
  32. package/dist/BottomSheet/bottomSheetStack.js +1675 -0
  33. package/dist/BottomSheet/useSheetGestures.d.ts +19 -3
  34. package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
  35. package/dist/BottomSheet/useSheetGestures.js +43 -14
  36. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  37. package/dist/Breadcrumbs/BreadcrumbItem.js +36 -3
  38. package/dist/Button/Button.d.ts.map +1 -1
  39. package/dist/Button/Button.js +18 -7
  40. package/dist/Chat/ChatComposer.d.ts.map +1 -1
  41. package/dist/Chat/ChatComposer.js +25 -32
  42. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  43. package/dist/Chat/ChatComposerInput.js +55 -16
  44. package/dist/Chat/ChatMessageMetadata.js +2 -2
  45. package/dist/Chat/ChatPastedTextToken.d.ts.map +1 -1
  46. package/dist/Chat/ChatPastedTextToken.js +7 -6
  47. package/dist/Chat/ChatToolCalls.js +4 -4
  48. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  49. package/dist/ClickableCard/ClickableCard.js +10 -6
  50. package/dist/CodeBlock/CodeBlock.d.ts +25 -2
  51. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  52. package/dist/CodeBlock/CodeBlock.js +58 -19
  53. package/dist/CodeBlock/grammar.d.ts +134 -0
  54. package/dist/CodeBlock/grammar.d.ts.map +1 -0
  55. package/dist/CodeBlock/grammar.js +219 -0
  56. package/dist/CodeBlock/index.d.ts +2 -0
  57. package/dist/CodeBlock/index.d.ts.map +1 -1
  58. package/dist/CodeBlock/index.js +1 -0
  59. package/dist/CodeBlock/languages/dockerfile.d.ts +3 -0
  60. package/dist/CodeBlock/languages/dockerfile.d.ts.map +1 -0
  61. package/dist/CodeBlock/languages/dockerfile.js +45 -0
  62. package/dist/CodeBlock/languages/graphql.d.ts +3 -0
  63. package/dist/CodeBlock/languages/graphql.d.ts.map +1 -0
  64. package/dist/CodeBlock/languages/graphql.js +27 -0
  65. package/dist/CodeBlock/languages/java.d.ts +3 -0
  66. package/dist/CodeBlock/languages/java.d.ts.map +1 -0
  67. package/dist/CodeBlock/languages/java.js +24 -0
  68. package/dist/CodeBlock/languages/lua.d.ts +3 -0
  69. package/dist/CodeBlock/languages/lua.d.ts.map +1 -0
  70. package/dist/CodeBlock/languages/lua.js +21 -0
  71. package/dist/CodeBlock/languages/objective-c.d.ts +3 -0
  72. package/dist/CodeBlock/languages/objective-c.d.ts.map +1 -0
  73. package/dist/CodeBlock/languages/objective-c.js +27 -0
  74. package/dist/CodeBlock/languages/powershell.d.ts +3 -0
  75. package/dist/CodeBlock/languages/powershell.d.ts.map +1 -0
  76. package/dist/CodeBlock/languages/powershell.js +30 -0
  77. package/dist/CodeBlock/languages/ruby.d.ts +3 -0
  78. package/dist/CodeBlock/languages/ruby.d.ts.map +1 -0
  79. package/dist/CodeBlock/languages/ruby.js +24 -0
  80. package/dist/CodeBlock/languages/thrift.d.ts +3 -0
  81. package/dist/CodeBlock/languages/thrift.d.ts.map +1 -0
  82. package/dist/CodeBlock/languages/thrift.js +18 -0
  83. package/dist/CodeBlock/languages/toml.d.ts +3 -0
  84. package/dist/CodeBlock/languages/toml.d.ts.map +1 -0
  85. package/dist/CodeBlock/languages/toml.js +53 -0
  86. package/dist/CodeBlock/tokenizer.d.ts +8 -4
  87. package/dist/CodeBlock/tokenizer.d.ts.map +1 -1
  88. package/dist/CodeBlock/tokenizer.js +158 -8
  89. package/dist/Collapsible/Collapsible.d.ts +8 -1
  90. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  91. package/dist/Collapsible/Collapsible.js +84 -2
  92. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  93. package/dist/CommandPalette/CommandPalette.js +15 -1
  94. package/dist/CommandPalette/CommandPaletteEmpty.d.ts.map +1 -1
  95. package/dist/CommandPalette/CommandPaletteEmpty.js +1 -0
  96. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  97. package/dist/CommandPalette/CommandPaletteInput.js +14 -2
  98. package/dist/CommandPalette/busyStartSettle.d.ts +4 -0
  99. package/dist/CommandPalette/busyStartSettle.d.ts.map +1 -0
  100. package/dist/CommandPalette/busyStartSettle.js +23 -0
  101. package/dist/ComplexSelector/ComplexSelector.d.ts +20 -2
  102. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  103. package/dist/ComplexSelector/ComplexSelector.js +42 -7
  104. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  105. package/dist/ContextMenu/ContextMenu.js +48 -13
  106. package/dist/DateInput/DateInput.d.ts.map +1 -1
  107. package/dist/DateInput/DateInput.js +12 -5
  108. package/dist/DateInput/NativeDateField.d.ts.map +1 -1
  109. package/dist/DateInput/NativeDateField.js +2 -1
  110. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  111. package/dist/DateInput/TouchDateField.js +2 -1
  112. package/dist/DateInput/Wheel.d.ts.map +1 -1
  113. package/dist/DateInput/Wheel.js +1 -1
  114. package/dist/Dialog/Dialog.d.ts +4 -0
  115. package/dist/Dialog/Dialog.d.ts.map +1 -1
  116. package/dist/Dialog/Dialog.js +20 -8
  117. package/dist/Drawer/Drawer.d.ts.map +1 -1
  118. package/dist/Drawer/Drawer.js +18 -13
  119. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  120. package/dist/DropdownMenu/DropdownMenu.js +34 -30
  121. package/dist/DropdownMenu/DropdownMenuGroup.d.ts +7 -4
  122. package/dist/DropdownMenu/DropdownMenuGroup.d.ts.map +1 -1
  123. package/dist/DropdownMenu/DropdownMenuGroup.js +10 -4
  124. package/dist/DropdownMenu/DropdownMenuItem.js +3 -3
  125. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +10 -5
  126. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
  127. package/dist/DropdownMenu/DropdownMenuRadioItem.js +13 -5
  128. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +6 -6
  129. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  130. package/dist/DropdownMenu/DropdownMenuSubMenu.js +0 -3
  131. package/dist/DropdownMenu/MenuBottomSheet.d.ts +11 -4
  132. package/dist/DropdownMenu/MenuBottomSheet.d.ts.map +1 -1
  133. package/dist/DropdownMenu/MenuBottomSheet.js +35 -9
  134. package/dist/DropdownMenu/MenuBottomSheetActionList.js +3 -3
  135. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts +2 -0
  136. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts.map +1 -1
  137. package/dist/DropdownMenu/lazyMenuBottomSheet.js +25 -3
  138. package/dist/DropdownMenu/menuBottomSheet.stylex.d.ts +23 -0
  139. package/dist/DropdownMenu/menuBottomSheet.stylex.d.ts.map +1 -0
  140. package/dist/DropdownMenu/menuBottomSheet.stylex.js +29 -0
  141. package/dist/DropdownMenu/menuItemHover.d.ts +3 -0
  142. package/dist/DropdownMenu/menuItemHover.d.ts.map +1 -1
  143. package/dist/DropdownMenu/menuItemHover.js +14 -1
  144. package/dist/DropdownMenu/menuTouchAction.stylex.d.ts +25 -0
  145. package/dist/DropdownMenu/menuTouchAction.stylex.d.ts.map +1 -0
  146. package/dist/DropdownMenu/menuTouchAction.stylex.js +29 -0
  147. package/dist/DropdownMenu/useMenuDrillIn.d.ts.map +1 -1
  148. package/dist/DropdownMenu/useMenuDrillIn.js +7 -5
  149. package/dist/EmptyState/EmptyState.d.ts +4 -2
  150. package/dist/EmptyState/EmptyState.d.ts.map +1 -1
  151. package/dist/EmptyState/EmptyState.js +6 -4
  152. package/dist/Field/Field.js +1 -1
  153. package/dist/Field/FieldLabel.js +1 -1
  154. package/dist/Field/PanelSearchInput.d.ts +9 -1
  155. package/dist/Field/PanelSearchInput.d.ts.map +1 -1
  156. package/dist/Field/PanelSearchInput.js +31 -22
  157. package/dist/Field/inputDisabledFocus.d.ts +14 -0
  158. package/dist/Field/inputDisabledFocus.d.ts.map +1 -0
  159. package/dist/Field/inputDisabledFocus.js +19 -0
  160. package/dist/Field/inputStyles.stylex.d.ts +9 -9
  161. package/dist/Field/inputStyles.stylex.js +9 -9
  162. package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
  163. package/dist/FieldStatus/FieldStatus.js +7 -3
  164. package/dist/FileInput/FileInput.d.ts.map +1 -1
  165. package/dist/FileInput/FileInput.js +22 -12
  166. package/dist/Icon/Icon.d.ts +37 -5
  167. package/dist/Icon/Icon.d.ts.map +1 -1
  168. package/dist/Icon/Icon.js +65 -11
  169. package/dist/Icon/IconSize.stylex.d.ts +16 -11
  170. package/dist/Icon/IconSize.stylex.d.ts.map +1 -1
  171. package/dist/Icon/IconSize.stylex.js +27 -11
  172. package/dist/Icon/globalIconRegistry.d.ts +71 -4
  173. package/dist/Icon/globalIconRegistry.d.ts.map +1 -1
  174. package/dist/Icon/globalIconRegistry.js +163 -23
  175. package/dist/Icon/index.d.ts +26 -2
  176. package/dist/Icon/index.d.ts.map +1 -1
  177. package/dist/Icon/index.js +24 -1
  178. package/dist/Icon/useIcon.d.ts +5 -1
  179. package/dist/Icon/useIcon.d.ts.map +1 -1
  180. package/dist/Icon/useIcon.js +5 -1
  181. package/dist/InputGroup/InputGroup.d.ts +1 -1
  182. package/dist/InputGroup/InputGroup.d.ts.map +1 -1
  183. package/dist/InputGroup/InputGroup.js +46 -36
  184. package/dist/InputGroup/InputGroupInternalContext.d.ts +4 -0
  185. package/dist/InputGroup/InputGroupInternalContext.d.ts.map +1 -0
  186. package/dist/InputGroup/InputGroupInternalContext.js +15 -0
  187. package/dist/InputGroup/InputGroupText.d.ts.map +1 -1
  188. package/dist/InputGroup/InputGroupText.js +2 -0
  189. package/dist/InputGroup/groupStyles.d.ts +9 -0
  190. package/dist/InputGroup/groupStyles.d.ts.map +1 -1
  191. package/dist/InputGroup/groupStyles.js +28 -14
  192. package/dist/Item/Item.d.ts +5 -1
  193. package/dist/Item/Item.d.ts.map +1 -1
  194. package/dist/Item/Item.js +23 -7
  195. package/dist/Item/ItemMarkerColumns.a11y.chromium.spec.d.ts +2 -0
  196. package/dist/Item/ItemMarkerColumns.a11y.chromium.spec.d.ts.map +1 -0
  197. package/dist/Item/ItemMarkerColumns.a11y.chromium.spec.js +132 -0
  198. package/dist/Item/ItemMarkerColumnsContext.d.ts +14 -0
  199. package/dist/Item/ItemMarkerColumnsContext.d.ts.map +1 -0
  200. package/dist/Item/ItemMarkerColumnsContext.js +18 -0
  201. package/dist/Item/ItemSwipeLayer.d.ts.map +1 -1
  202. package/dist/Item/ItemSwipeLayer.js +3 -0
  203. package/dist/Item/useSwipeAction.d.ts.map +1 -1
  204. package/dist/Item/useSwipeAction.js +60 -5
  205. package/dist/Kbd/Kbd.d.ts +2 -2
  206. package/dist/Kbd/Kbd.d.ts.map +1 -1
  207. package/dist/Kbd/Kbd.js +18 -11
  208. package/dist/Layer/layerAnimations.stylex.d.ts +9 -5
  209. package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
  210. package/dist/Layer/layerAnimations.stylex.js +23 -10
  211. package/dist/Layer/layerSlideRules.d.ts +62 -2
  212. package/dist/Layer/layerSlideRules.d.ts.map +1 -1
  213. package/dist/Layer/layerSlideRules.js +124 -3
  214. package/dist/Layer/layerStack.d.ts +12 -9
  215. package/dist/Layer/layerStack.d.ts.map +1 -1
  216. package/dist/Layer/layerStack.js +116 -53
  217. package/dist/Layer/modalOutlet.d.ts +44 -6
  218. package/dist/Layer/modalOutlet.d.ts.map +1 -1
  219. package/dist/Layer/modalOutlet.js +150 -14
  220. package/dist/Layer/preserveAnimations.d.ts +11 -0
  221. package/dist/Layer/preserveAnimations.d.ts.map +1 -0
  222. package/dist/Layer/preserveAnimations.js +245 -0
  223. package/dist/Layer/useLayer.d.ts +19 -2
  224. package/dist/Layer/useLayer.d.ts.map +1 -1
  225. package/dist/Layer/useLayer.js +531 -44
  226. package/dist/Layer/useLayerDismissal.d.ts +10 -7
  227. package/dist/Layer/useLayerDismissal.d.ts.map +1 -1
  228. package/dist/Layer/useLayerDismissal.js +8 -8
  229. package/dist/Layer/useTouchTrigger.d.ts +14 -1
  230. package/dist/Layer/useTouchTrigger.d.ts.map +1 -1
  231. package/dist/Layer/useTouchTrigger.js +72 -17
  232. package/dist/Layout/Layout.d.ts.map +1 -1
  233. package/dist/Layout/Layout.js +4 -0
  234. package/dist/Layout/LayoutContent.d.ts.map +1 -1
  235. package/dist/Layout/LayoutContent.js +2 -2
  236. package/dist/Layout/LayoutFooter.d.ts.map +1 -1
  237. package/dist/Layout/LayoutFooter.js +2 -1
  238. package/dist/Layout/LayoutHeader.d.ts.map +1 -1
  239. package/dist/Layout/LayoutHeader.js +2 -1
  240. package/dist/Layout/layoutEdges.stylex.d.ts +20 -0
  241. package/dist/Layout/layoutEdges.stylex.d.ts.map +1 -0
  242. package/dist/Layout/layoutEdges.stylex.js +28 -0
  243. package/dist/Lightbox/Lightbox.d.ts +5 -2
  244. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  245. package/dist/Lightbox/Lightbox.js +111 -89
  246. package/dist/Lightbox/LightboxKeyboard.a11y.browser.spec.d.ts +2 -0
  247. package/dist/Lightbox/LightboxKeyboard.a11y.browser.spec.d.ts.map +1 -0
  248. package/dist/Lightbox/LightboxKeyboard.a11y.browser.spec.js +78 -0
  249. package/dist/Lightbox/LightboxViewport.a11y.browser.spec.d.ts +2 -0
  250. package/dist/Lightbox/LightboxViewport.a11y.browser.spec.d.ts.map +1 -0
  251. package/dist/Lightbox/LightboxViewport.a11y.browser.spec.js +65 -0
  252. package/dist/List/List.d.ts +2 -1
  253. package/dist/List/List.d.ts.map +1 -1
  254. package/dist/List/List.js +9 -2
  255. package/dist/List/ListContext.d.ts +16 -4
  256. package/dist/List/ListContext.d.ts.map +1 -1
  257. package/dist/List/ListContext.js +10 -5
  258. package/dist/List/ListItem.d.ts +7 -1
  259. package/dist/List/ListItem.d.ts.map +1 -1
  260. package/dist/List/ListItem.js +52 -8
  261. package/dist/List/ListMarkers.a11y.chromium.spec.d.ts +2 -0
  262. package/dist/List/ListMarkers.a11y.chromium.spec.d.ts.map +1 -0
  263. package/dist/List/ListMarkers.a11y.chromium.spec.js +677 -0
  264. package/dist/Markdown/Markdown.d.ts +11 -1
  265. package/dist/Markdown/Markdown.d.ts.map +1 -1
  266. package/dist/Markdown/Markdown.fr23.bench.js +3 -1
  267. package/dist/Markdown/Markdown.fr23.sampling.d.ts +16 -0
  268. package/dist/Markdown/Markdown.fr23.sampling.d.ts.map +1 -1
  269. package/dist/Markdown/Markdown.fr23.sampling.js +13 -4
  270. package/dist/Markdown/Markdown.js +41 -14
  271. package/dist/Markdown/MarkdownTable.a11y.chromium.spec.js +1 -0
  272. package/dist/MobileNav/MobileNav.d.ts +2 -1
  273. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  274. package/dist/MobileNav/MobileNav.js +46 -37
  275. package/dist/MobileNav/MobileNavPinchZoom.a11y.chromium.spec.js +1 -0
  276. package/dist/MobileNav/MobileNavToggle.d.ts +7 -3
  277. package/dist/MobileNav/MobileNavToggle.d.ts.map +1 -1
  278. package/dist/MobileNav/MobileNavToggle.js +11 -3
  279. package/dist/MultiSelector/CreateRow.a11y.chromium.spec.js +53 -6
  280. package/dist/MultiSelector/MultiSelector.d.ts +1 -1
  281. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  282. package/dist/MultiSelector/MultiSelector.disabledFocus.a11y.chromium.spec.js +1 -0
  283. package/dist/MultiSelector/MultiSelector.js +21 -5
  284. package/dist/MultiSelector/OptionActions.a11y.chromium.spec.js +1 -0
  285. package/dist/NavMenu/NavHeadingMenu.d.ts +1 -1
  286. package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
  287. package/dist/NavMenu/NavHeadingMenu.js +29 -5
  288. package/dist/NavMenu/NavHeadingMenuItem.d.ts.map +1 -1
  289. package/dist/NavMenu/NavHeadingMenuItem.js +51 -7
  290. package/dist/NavMenu/NavMenuContext.d.ts +9 -0
  291. package/dist/NavMenu/NavMenuContext.d.ts.map +1 -1
  292. package/dist/NavMenu/NavMenuContext.js +9 -0
  293. package/dist/NumberInput/NumberInput.d.ts +4 -4
  294. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  295. package/dist/NumberInput/NumberInput.js +61 -24
  296. package/dist/Overlay/Overlay.d.ts +3 -3
  297. package/dist/Overlay/Overlay.d.ts.map +1 -1
  298. package/dist/Overlay/Overlay.js +12 -5
  299. package/dist/Popover/Popover.d.ts +41 -2
  300. package/dist/Popover/Popover.d.ts.map +1 -1
  301. package/dist/Popover/Popover.js +276 -44
  302. package/dist/Popover/index.d.ts +1 -1
  303. package/dist/Popover/index.d.ts.map +1 -1
  304. package/dist/Popover/lazyPopoverBottomSheet.d.ts +23 -0
  305. package/dist/Popover/lazyPopoverBottomSheet.d.ts.map +1 -0
  306. package/dist/Popover/lazyPopoverBottomSheet.js +40 -0
  307. package/dist/Popover/usePopover.d.ts.map +1 -1
  308. package/dist/Popover/usePopover.js +11 -5
  309. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  310. package/dist/PowerSearch/PowerSearch.js +7 -5
  311. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  312. package/dist/ProgressBar/ProgressBar.js +8 -0
  313. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  314. package/dist/RadioList/RadioListItem.js +10 -2
  315. package/dist/ScrollableArea/ScrollableArea.d.ts.map +1 -1
  316. package/dist/ScrollableArea/ScrollableArea.js +1 -1
  317. package/dist/SegmentedControl/SegmentedControl.d.ts +1 -1
  318. package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  319. package/dist/SegmentedControl/SegmentedControl.js +6 -2
  320. package/dist/SelectableCard/SelectableCard.d.ts +5 -5
  321. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  322. package/dist/SelectableCard/SelectableCard.js +15 -11
  323. package/dist/Selector/Selector.d.ts.map +1 -1
  324. package/dist/Selector/Selector.js +27 -8
  325. package/dist/Selector/hooks.d.ts +52 -6
  326. package/dist/Selector/hooks.d.ts.map +1 -1
  327. package/dist/Selector/hooks.js +145 -2
  328. package/dist/SideNav/SideNav.d.ts.map +1 -1
  329. package/dist/SideNav/SideNav.js +58 -2
  330. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  331. package/dist/SideNav/SideNavHeading.js +79 -3
  332. package/dist/SideNav/SideNavItem.d.ts +5 -1
  333. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  334. package/dist/SideNav/SideNavItem.js +36 -13
  335. package/dist/SideNav/railMotion.d.ts +54 -0
  336. package/dist/SideNav/railMotion.d.ts.map +1 -0
  337. package/dist/SideNav/railMotion.js +253 -0
  338. package/dist/Skeleton/Skeleton.d.ts.map +1 -1
  339. package/dist/Skeleton/Skeleton.js +12 -3
  340. package/dist/Slider/Slider.d.ts.map +1 -1
  341. package/dist/Slider/Slider.js +52 -15
  342. package/dist/StatusDot/StatusDot.d.ts.map +1 -1
  343. package/dist/StatusDot/StatusDot.js +12 -0
  344. package/dist/Stepper/Step.d.ts.map +1 -1
  345. package/dist/Stepper/Step.js +10 -6
  346. package/dist/Switch/Switch.d.ts.map +1 -1
  347. package/dist/Switch/Switch.js +5 -5
  348. package/dist/Switch/switch.markers.stylex.d.ts +7 -2
  349. package/dist/Switch/switch.markers.stylex.d.ts.map +1 -1
  350. package/dist/Switch/switch.markers.stylex.js +8 -3
  351. package/dist/TabList/Tab.d.ts.map +1 -1
  352. package/dist/TabList/Tab.js +5 -1
  353. package/dist/TabList/TabMenu.d.ts.map +1 -1
  354. package/dist/TabList/TabMenu.js +25 -3
  355. package/dist/Table/TableCell.d.ts.map +1 -1
  356. package/dist/Table/TableCell.js +5 -1
  357. package/dist/Table/TableHeaderCell.d.ts.map +1 -1
  358. package/dist/Table/TableHeaderCell.js +1 -0
  359. package/dist/Table/TableRow.d.ts.map +1 -1
  360. package/dist/Table/TableRow.js +3 -0
  361. package/dist/Table/glidingDivider.d.ts +96 -0
  362. package/dist/Table/glidingDivider.d.ts.map +1 -0
  363. package/dist/Table/glidingDivider.js +275 -0
  364. package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
  365. package/dist/Table/plugins/columnResize/useTableColumnResize.js +11 -2
  366. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts +8 -0
  367. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  368. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +374 -13
  369. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
  370. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +244 -6
  371. package/dist/Table/rowDivider.d.ts +34 -0
  372. package/dist/Table/rowDivider.d.ts.map +1 -0
  373. package/dist/Table/rowDivider.js +118 -0
  374. package/dist/TextArea/TextArea.d.ts +6 -4
  375. package/dist/TextArea/TextArea.d.ts.map +1 -1
  376. package/dist/TextArea/TextArea.js +15 -12
  377. package/dist/TextInput/TextInput.d.ts +7 -5
  378. package/dist/TextInput/TextInput.d.ts.map +1 -1
  379. package/dist/TextInput/TextInput.js +43 -22
  380. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  381. package/dist/Thumbnail/Thumbnail.js +45 -11
  382. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  383. package/dist/TimeInput/TimeInput.js +12 -4
  384. package/dist/TimeInput/TouchTimeField.d.ts.map +1 -1
  385. package/dist/TimeInput/TouchTimeField.js +2 -1
  386. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  387. package/dist/Toast/ToastViewport.js +62 -6
  388. package/dist/Tokenizer/Tokenizer.d.ts +71 -4
  389. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  390. package/dist/Tokenizer/Tokenizer.js +430 -45
  391. package/dist/Tokenizer/TokenizerBottomSheet.d.ts +98 -0
  392. package/dist/Tokenizer/TokenizerBottomSheet.d.ts.map +1 -0
  393. package/dist/Tokenizer/TokenizerBottomSheet.js +721 -0
  394. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  395. package/dist/Tooltip/useTooltip.js +9 -3
  396. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  397. package/dist/TopNav/TopNavHeading.js +26 -0
  398. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  399. package/dist/TopNav/TopNavMegaMenu.js +4 -4
  400. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  401. package/dist/TopNav/TopNavMenu.js +32 -4
  402. package/dist/TreeList/TreeList.d.ts +8 -23
  403. package/dist/TreeList/TreeList.d.ts.map +1 -1
  404. package/dist/TreeList/TreeList.js +175 -3
  405. package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
  406. package/dist/TreeList/TreeListBranches.js +7 -5
  407. package/dist/TreeList/TreeListItem.d.ts +7 -1
  408. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  409. package/dist/TreeList/TreeListItem.js +5 -3
  410. package/dist/Typeahead/BaseTypeahead.d.ts +1 -1
  411. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  412. package/dist/Typeahead/BaseTypeahead.emptyState.a11y.chromium.spec.d.ts +2 -0
  413. package/dist/Typeahead/BaseTypeahead.emptyState.a11y.chromium.spec.d.ts.map +1 -0
  414. package/dist/Typeahead/BaseTypeahead.emptyState.a11y.chromium.spec.js +118 -0
  415. package/dist/Typeahead/BaseTypeahead.js +27 -11
  416. package/dist/Typeahead/Typeahead.d.ts +1 -1
  417. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  418. package/dist/Typeahead/Typeahead.js +31 -14
  419. package/dist/astryx.css +164 -41
  420. package/dist/gestures/GestureArena.d.ts +175 -0
  421. package/dist/gestures/GestureArena.d.ts.map +1 -0
  422. package/dist/gestures/GestureArena.js +816 -0
  423. package/dist/gestures/GestureRecognizer.d.ts +239 -0
  424. package/dist/gestures/GestureRecognizer.d.ts.map +1 -0
  425. package/dist/gestures/GestureRecognizer.js +487 -0
  426. package/dist/gestures/LongPressGestureRecognizer.d.ts +32 -0
  427. package/dist/gestures/LongPressGestureRecognizer.d.ts.map +1 -0
  428. package/dist/gestures/LongPressGestureRecognizer.js +135 -0
  429. package/dist/gestures/PanGestureRecognizer.d.ts +117 -0
  430. package/dist/gestures/PanGestureRecognizer.d.ts.map +1 -0
  431. package/dist/gestures/PanGestureRecognizer.js +349 -0
  432. package/dist/gestures/TapGestureRecognizer.d.ts +39 -0
  433. package/dist/gestures/TapGestureRecognizer.d.ts.map +1 -0
  434. package/dist/gestures/TapGestureRecognizer.js +151 -0
  435. package/dist/gestures/VelocityTracker.d.ts +51 -0
  436. package/dist/gestures/VelocityTracker.d.ts.map +1 -0
  437. package/dist/gestures/VelocityTracker.js +186 -0
  438. package/dist/gestures/geometry.d.ts +17 -0
  439. package/dist/gestures/geometry.d.ts.map +1 -0
  440. package/dist/gestures/geometry.js +55 -0
  441. package/dist/gestures/types.d.ts +139 -0
  442. package/dist/gestures/types.d.ts.map +1 -0
  443. package/dist/gestures/types.js +67 -0
  444. package/dist/hooks/AnnounceRenderedText.d.ts +17 -0
  445. package/dist/hooks/AnnounceRenderedText.d.ts.map +1 -0
  446. package/dist/hooks/AnnounceRenderedText.js +32 -0
  447. package/dist/hooks/ModalAnnounceProvider.d.ts +41 -0
  448. package/dist/hooks/ModalAnnounceProvider.d.ts.map +1 -0
  449. package/dist/hooks/ModalAnnounceProvider.js +133 -0
  450. package/dist/hooks/actionGroupTracker.d.ts +98 -0
  451. package/dist/hooks/actionGroupTracker.d.ts.map +1 -0
  452. package/dist/hooks/actionGroupTracker.js +338 -0
  453. package/dist/hooks/index.d.ts +2 -0
  454. package/dist/hooks/index.d.ts.map +1 -1
  455. package/dist/hooks/index.js +1 -0
  456. package/dist/hooks/menuPressOnItems.d.ts +19 -0
  457. package/dist/hooks/menuPressOnItems.d.ts.map +1 -0
  458. package/dist/hooks/menuPressOnItems.js +32 -0
  459. package/dist/hooks/modalAnnounce.d.ts +18 -0
  460. package/dist/hooks/modalAnnounce.d.ts.map +1 -0
  461. package/dist/hooks/modalAnnounce.js +382 -0
  462. package/dist/hooks/scrollGeometry.d.ts +28 -0
  463. package/dist/hooks/scrollGeometry.d.ts.map +1 -1
  464. package/dist/hooks/scrollGeometry.js +36 -2
  465. package/dist/hooks/useAdaptivePresentation.d.ts +9 -1
  466. package/dist/hooks/useAdaptivePresentation.d.ts.map +1 -1
  467. package/dist/hooks/useAdaptivePresentation.js +33 -8
  468. package/dist/hooks/useAnimatedLayout.d.ts +42 -0
  469. package/dist/hooks/useAnimatedLayout.d.ts.map +1 -0
  470. package/dist/hooks/useAnimatedLayout.js +46 -0
  471. package/dist/hooks/useAnnounce.d.ts +132 -1
  472. package/dist/hooks/useAnnounce.d.ts.map +1 -1
  473. package/dist/hooks/useAnnounce.js +356 -27
  474. package/dist/hooks/useAnnounceRenderedText.d.ts +19 -2
  475. package/dist/hooks/useAnnounceRenderedText.d.ts.map +1 -1
  476. package/dist/hooks/useAnnounceRenderedText.js +52 -11
  477. package/dist/hooks/useBusyAnnouncement.d.ts +9 -5
  478. package/dist/hooks/useBusyAnnouncement.d.ts.map +1 -1
  479. package/dist/hooks/useBusyAnnouncement.js +58 -46
  480. package/dist/hooks/useFocusTrap.d.ts +1 -1
  481. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  482. package/dist/hooks/useFocusTrap.js +57 -26
  483. package/dist/hooks/useMenuHover.d.ts.map +1 -1
  484. package/dist/hooks/useMenuHover.js +6 -2
  485. package/dist/hooks/useMenuPress.d.ts +4 -2
  486. package/dist/hooks/useMenuPress.d.ts.map +1 -1
  487. package/dist/hooks/useMenuPress.js +58 -33
  488. package/dist/hooks/usePressFeedback.d.ts +5 -2
  489. package/dist/hooks/usePressFeedback.d.ts.map +1 -1
  490. package/dist/hooks/usePressFeedback.js +5 -2
  491. package/dist/hooks/useScrollableArea.d.ts +5 -0
  492. package/dist/hooks/useScrollableArea.d.ts.map +1 -1
  493. package/dist/hooks/useScrollableArea.js +104 -11
  494. package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
  495. package/dist/i18n/generated-locales/en.generated.js +33 -0
  496. package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
  497. package/dist/i18n/generated-locales/pseudo.generated.js +33 -0
  498. package/dist/internal/tokenizer-presentation.d.ts +21 -0
  499. package/dist/internal/tokenizer-presentation.d.ts.map +1 -0
  500. package/dist/internal/tokenizer-presentation.js +21 -0
  501. package/dist/internal/touch.d.ts +26 -0
  502. package/dist/internal/touch.d.ts.map +1 -0
  503. package/dist/internal/touch.js +28 -0
  504. package/dist/motion/LayoutChangeSnapshot.d.ts +33 -0
  505. package/dist/motion/LayoutChangeSnapshot.d.ts.map +1 -0
  506. package/dist/motion/LayoutChangeSnapshot.js +37 -0
  507. package/dist/motion/animatedLayout.d.ts +190 -0
  508. package/dist/motion/animatedLayout.d.ts.map +1 -0
  509. package/dist/motion/animatedLayout.js +1502 -0
  510. package/dist/motion/animator.d.ts +240 -0
  511. package/dist/motion/animator.d.ts.map +1 -0
  512. package/dist/motion/animator.js +2203 -0
  513. package/dist/motion/bezier.d.ts +18 -0
  514. package/dist/motion/bezier.d.ts.map +1 -0
  515. package/dist/motion/bezier.js +60 -0
  516. package/dist/motion/coast.d.ts +61 -0
  517. package/dist/motion/coast.d.ts.map +1 -0
  518. package/dist/motion/coast.js +107 -0
  519. package/dist/motion/decay.d.ts +41 -0
  520. package/dist/motion/decay.d.ts.map +1 -0
  521. package/dist/motion/decay.js +90 -0
  522. package/dist/motion/projection.d.ts +36 -0
  523. package/dist/motion/projection.d.ts.map +1 -0
  524. package/dist/motion/projection.js +92 -0
  525. package/dist/motion/reducedMotion.d.ts +25 -0
  526. package/dist/motion/reducedMotion.d.ts.map +1 -0
  527. package/dist/motion/reducedMotion.js +85 -0
  528. package/dist/motion/reducedMotion.stylex.d.ts +19 -0
  529. package/dist/motion/reducedMotion.stylex.d.ts.map +1 -0
  530. package/dist/motion/reducedMotion.stylex.js +37 -0
  531. package/dist/motion/reducedMotionPlan.d.ts +89 -0
  532. package/dist/motion/reducedMotionPlan.d.ts.map +1 -0
  533. package/dist/motion/reducedMotionPlan.js +194 -0
  534. package/dist/motion/resolveSnapPoint.d.ts +52 -0
  535. package/dist/motion/resolveSnapPoint.d.ts.map +1 -0
  536. package/dist/motion/resolveSnapPoint.js +135 -0
  537. package/dist/motion/roleValue.d.ts +33 -0
  538. package/dist/motion/roleValue.d.ts.map +1 -0
  539. package/dist/motion/roleValue.js +84 -0
  540. package/dist/motion/roles.d.ts +79 -0
  541. package/dist/motion/roles.d.ts.map +1 -0
  542. package/dist/motion/roles.js +199 -0
  543. package/dist/motion/rubberBand.d.ts +20 -0
  544. package/dist/motion/rubberBand.d.ts.map +1 -0
  545. package/dist/motion/rubberBand.js +91 -0
  546. package/dist/motion/selectPage.d.ts +26 -0
  547. package/dist/motion/selectPage.d.ts.map +1 -0
  548. package/dist/motion/selectPage.js +55 -0
  549. package/dist/motion/spring.d.ts +193 -0
  550. package/dist/motion/spring.d.ts.map +1 -0
  551. package/dist/motion/spring.js +442 -0
  552. package/dist/motion/transientCopy.d.ts +33 -0
  553. package/dist/motion/transientCopy.d.ts.map +1 -0
  554. package/dist/motion/transientCopy.js +314 -0
  555. package/dist/motion/uikit/gestures.d.ts +642 -0
  556. package/dist/motion/uikit/gestures.d.ts.map +1 -0
  557. package/dist/motion/uikit/gestures.js +428 -0
  558. package/dist/motion/uikit/index.d.ts +24 -0
  559. package/dist/motion/uikit/index.d.ts.map +1 -0
  560. package/dist/motion/uikit/index.js +26 -0
  561. package/dist/motion/uikit/navigation.d.ts +54 -0
  562. package/dist/motion/uikit/navigation.d.ts.map +1 -0
  563. package/dist/motion/uikit/navigation.js +83 -0
  564. package/dist/motion/uikit/scroll.d.ts +116 -0
  565. package/dist/motion/uikit/scroll.d.ts.map +1 -0
  566. package/dist/motion/uikit/scroll.js +146 -0
  567. package/dist/motion/uikit/springs.d.ts +545 -0
  568. package/dist/motion/uikit/springs.d.ts.map +1 -0
  569. package/dist/motion/uikit/springs.js +548 -0
  570. package/dist/motion/uikit/timing.d.ts +202 -0
  571. package/dist/motion/uikit/timing.d.ts.map +1 -0
  572. package/dist/motion/uikit/timing.js +201 -0
  573. package/dist/reset.a11y.chromium.spec.js +1 -0
  574. package/dist/reset.until-found.a11y.browser.spec.js +1 -0
  575. package/dist/theme/declarationBoundary.d.ts +13 -0
  576. package/dist/theme/declarationBoundary.d.ts.map +1 -1
  577. package/dist/theme/declarationBoundary.js +264 -1
  578. package/dist/theme/defineTheme.d.ts +111 -11
  579. package/dist/theme/defineTheme.d.ts.map +1 -1
  580. package/dist/theme/defineTheme.js +97 -7
  581. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  582. package/dist/theme/derivedVarRegistry.js +9 -0
  583. package/dist/theme/generateThemeRules.d.ts +6 -2
  584. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  585. package/dist/theme/generateThemeRules.js +468 -24
  586. package/dist/theme/index.d.ts +2 -2
  587. package/dist/theme/index.d.ts.map +1 -1
  588. package/dist/theme/index.js +1 -1
  589. package/dist/theme/statusColor.d.ts +48 -0
  590. package/dist/theme/statusColor.d.ts.map +1 -0
  591. package/dist/theme/statusColor.js +203 -0
  592. package/dist/theme/statusRoleDerivation.d.ts +11 -0
  593. package/dist/theme/statusRoleDerivation.d.ts.map +1 -0
  594. package/dist/theme/statusRoleDerivation.js +236 -0
  595. package/dist/theme/syntax/SyntaxTheme.d.ts +1 -1
  596. package/dist/theme/syntax/SyntaxTheme.js +1 -1
  597. package/dist/theme/syntax/defineSyntaxTheme.js +1 -1
  598. package/dist/theme/syntax/presets.d.ts +1 -1
  599. package/dist/theme/syntax/presets.js +1 -1
  600. package/dist/theme/syntax/tokens.d.ts +1 -1
  601. package/dist/theme/syntax/tokens.js +1 -1
  602. package/dist/theme/themeAdaptations.d.ts +25 -1
  603. package/dist/theme/themeAdaptations.d.ts.map +1 -1
  604. package/dist/theme/themeAdaptations.js +30 -1
  605. package/dist/theme/tokens.d.ts.map +1 -1
  606. package/dist/theme/tokens.js +16 -1
  607. package/dist/theme/tokens.stylex.d.ts +42 -2
  608. package/dist/theme/tokens.stylex.d.ts.map +1 -1
  609. package/dist/theme/tokens.stylex.js +54 -3
  610. package/dist/theme/useTheme.d.ts +4 -2
  611. package/dist/theme/useTheme.d.ts.map +1 -1
  612. package/dist/theme/useTheme.js +10 -4
  613. package/dist/utils/edgeAutoscroll.d.ts +53 -0
  614. package/dist/utils/edgeAutoscroll.d.ts.map +1 -0
  615. package/dist/utils/edgeAutoscroll.js +81 -0
  616. package/dist/utils/hitArea.d.ts +72 -0
  617. package/dist/utils/hitArea.d.ts.map +1 -0
  618. package/dist/utils/hitArea.js +681 -0
  619. package/dist/utils/interactionOverlay.stylex.d.ts +4 -1
  620. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
  621. package/dist/utils/interactionOverlay.stylex.js +4 -1
  622. package/dist/utils/pressFeedback.d.ts +5 -1
  623. package/dist/utils/pressFeedback.d.ts.map +1 -1
  624. package/dist/utils/pressFeedback.js +285 -54
  625. package/dist/utils/pressGesture.d.ts +13 -1
  626. package/dist/utils/pressGesture.d.ts.map +1 -1
  627. package/dist/utils/pressGesture.js +40 -1
  628. package/dist/utils/touchPresentation.d.ts +48 -0
  629. package/dist/utils/touchPresentation.d.ts.map +1 -0
  630. package/dist/utils/touchPresentation.js +133 -0
  631. package/locales/af-ZA.json +1 -1
  632. package/locales/ar-SA.json +1 -1
  633. package/locales/ca-ES.json +1 -1
  634. package/locales/cs-CZ.json +1 -1
  635. package/locales/da-DK.json +1 -1
  636. package/locales/de-DE.json +1 -1
  637. package/locales/el-GR.json +1 -1
  638. package/locales/en.json +132 -0
  639. package/locales/es-ES.json +1 -1
  640. package/locales/fi-FI.json +1 -1
  641. package/locales/fr-FR.json +1 -1
  642. package/locales/he-IL.json +1 -1
  643. package/locales/hu-HU.json +1 -1
  644. package/locales/it-IT.json +1 -1
  645. package/locales/ja-JP.json +1 -1
  646. package/locales/ko-KR.json +1 -1
  647. package/locales/nl-NL.json +1 -1
  648. package/locales/no-NO.json +1 -1
  649. package/locales/pl-PL.json +1 -1
  650. package/locales/pseudo.json +99 -0
  651. package/locales/pt-BR.json +1 -1
  652. package/locales/pt-PT.json +1 -1
  653. package/locales/ro-RO.json +1 -1
  654. package/locales/ru-RU.json +1 -1
  655. package/locales/sr-SP.json +1 -1
  656. package/locales/sv-SE.json +1 -1
  657. package/locales/tr-TR.json +1 -1
  658. package/locales/uk-UA.json +1 -1
  659. package/locales/vi-VN.json +1 -1
  660. package/locales/zh-CN.json +1 -1
  661. package/locales/zh-TW.json +1 -1
  662. package/package.json +63 -8
  663. package/src/AlertDialog/AlertDialog.spec.md +85 -31
  664. package/src/AlertDialog/AlertDialog.tsx +1 -1
  665. package/src/AlertDialog/__tests__/AlertDialog.a11y.chromium.spec.ts +1 -0
  666. package/src/AppShell/AppShell.spec.md +334 -0
  667. package/src/AppShell/AppShell.tsx +170 -2
  668. package/src/AspectRatio/AspectRatio.spec.md +179 -0
  669. package/src/AspectRatio/__tests__/AspectRatioFitLayers.a11y.browser.spec.ts +1 -0
  670. package/src/Avatar/Avatar.spec.md +253 -0
  671. package/src/Avatar/AvatarStatusDot.spec.md +93 -79
  672. package/src/Avatar/AvatarStatusDot.test.tsx +22 -0
  673. package/src/Avatar/AvatarStatusDot.tsx +2 -2
  674. package/src/AvatarGroup/AvatarGroup.spec.md +205 -0
  675. package/src/AvatarGroup/AvatarGroupOverflow.spec.md +123 -120
  676. package/src/Badge/Badge.spec.md +207 -0
  677. package/src/Badge/Badge.test.tsx +13 -0
  678. package/src/Badge/Badge.tsx +38 -2
  679. package/src/Banner/Banner.spec.md +41 -28
  680. package/src/Banner/Banner.test.tsx +118 -16
  681. package/src/Banner/Banner.tsx +94 -7
  682. package/src/Blockquote/Blockquote.spec.md +171 -0
  683. package/src/BottomSheet/BottomSheet.doc.mjs +106 -24
  684. package/src/BottomSheet/BottomSheet.spec.md +271 -40
  685. package/src/BottomSheet/BottomSheet.test.tsx +491 -5
  686. package/src/BottomSheet/BottomSheet.tsx +544 -145
  687. package/src/BottomSheet/BottomSheetHostContext.ts +44 -0
  688. package/src/BottomSheet/BottomSheetPanel.test.tsx +73 -19
  689. package/src/BottomSheet/BottomSheetPanel.tsx +178 -63
  690. package/src/BottomSheet/BottomSheetReplace.test.tsx +1638 -0
  691. package/src/BottomSheet/BottomSheetStacking.announce.test.tsx +246 -0
  692. package/src/BottomSheet/BottomSheetStacking.test.tsx +3184 -0
  693. package/src/BottomSheet/BottomSheetSwitcher.doc.mjs +27 -31
  694. package/src/BottomSheet/BottomSheetSwitcher.spec.md +138 -43
  695. package/src/BottomSheet/BottomSheetSwitcher.tsx +275 -26
  696. package/src/BottomSheet/BottomSheetSwitcherContext.ts +6 -0
  697. package/src/BottomSheet/__tests__/BottomSheetDrag.a11y.chromium.spec.ts +1 -0
  698. package/src/BottomSheet/__tests__/BottomSheetFocusReturn.a11y.browser.spec.ts +1 -0
  699. package/src/BottomSheet/__tests__/BottomSheetKeyboard.a11y.browser.spec.ts +4 -1
  700. package/src/BottomSheet/__tests__/BottomSheetNativeModal.a11y.browser.spec.ts +1 -0
  701. package/src/BottomSheet/__tests__/BottomSheetPinchZoom.a11y.chromium.spec.ts +1 -0
  702. package/src/BottomSheet/__tests__/BottomSheetToastOutlet.a11y.chromium.spec.ts +83 -0
  703. package/src/BottomSheet/bottomSheetEscape.ts +21 -0
  704. package/src/BottomSheet/bottomSheetStack.ts +2054 -0
  705. package/src/BottomSheet/useSheetGestures.ts +68 -12
  706. package/src/Breadcrumbs/BreadcrumbItem.spec.md +104 -60
  707. package/src/Breadcrumbs/BreadcrumbItem.tsx +30 -1
  708. package/src/Breadcrumbs/Breadcrumbs.spec.md +165 -0
  709. package/src/Breadcrumbs/Breadcrumbs.test.tsx +90 -0
  710. package/src/Breadcrumbs/__tests__/Breadcrumbs.a11y.chromium.spec.ts +1 -0
  711. package/src/Button/Button.spec.md +322 -0
  712. package/src/Button/Button.test.tsx +8 -1
  713. package/src/Button/Button.tsx +36 -7
  714. package/src/Button/__tests__/Button.a11y.chromium.spec.ts +1 -0
  715. package/src/ButtonGroup/ButtonGroup.spec.md +220 -0
  716. package/src/Calendar/__tests__/Calendar.a11y.chromium.spec.ts +1 -0
  717. package/src/Card/Card.spec.md +205 -0
  718. package/src/Carousel/__tests__/Carousel.a11y.chromium.spec.ts +1 -0
  719. package/src/Center/Center.spec.md +104 -124
  720. package/src/Chat/ChatComposer.test.tsx +54 -0
  721. package/src/Chat/ChatComposer.tsx +41 -27
  722. package/src/Chat/ChatComposerInput.test.tsx +165 -21
  723. package/src/Chat/ChatComposerInput.tsx +73 -16
  724. package/src/Chat/ChatMessageMetadata.tsx +1 -1
  725. package/src/Chat/ChatPastedTextToken.test.tsx +71 -0
  726. package/src/Chat/ChatPastedTextToken.tsx +8 -7
  727. package/src/Chat/ChatToolCalls.tsx +5 -5
  728. package/src/Chat/__tests__/ChatLayoutScrollButton.a11y.chromium.spec.ts +22 -4
  729. package/src/Chat/__tests__/ChatLayoutScrollButtonSurface.a11y.chromium.spec.ts +1 -0
  730. package/src/Chat/__tests__/ChatMessageList.a11y.chromium.spec.ts +1 -0
  731. package/src/Chat/__tests__/ChatMessageMetadata.a11y.chromium.spec.ts +1 -0
  732. package/src/Chat/__tests__/ChatSendButton.a11y.chromium.spec.ts +1 -0
  733. package/src/Chat/__tests__/ChatSystemMessage.a11y.chromium.spec.ts +1 -0
  734. package/src/Chat/__tests__/ChatTokenizedText.a11y.chromium.spec.ts +1 -0
  735. package/src/Chat/__tests__/useChatStreamScroll.a11y.chromium.spec.ts +1 -0
  736. package/src/CheckboxInput/CheckboxInput.spec.md +97 -66
  737. package/src/CheckboxInput/__tests__/Checkbox.a11y.chromium.spec.ts +1 -0
  738. package/src/CheckboxList/CheckboxList.spec.md +92 -78
  739. package/src/CheckboxList/CheckboxListItem.spec.md +86 -60
  740. package/src/CheckboxList/__tests__/CheckboxList.a11y.chromium.spec.ts +1 -0
  741. package/src/ClickableCard/ClickableCard.doc.mjs +1 -2
  742. package/src/ClickableCard/ClickableCard.spec.md +124 -128
  743. package/src/ClickableCard/ClickableCard.test.tsx +14 -3
  744. package/src/ClickableCard/ClickableCard.tsx +44 -28
  745. package/src/Code/Code.spec.md +30 -32
  746. package/src/CodeBlock/CodeBlock.doc.mjs +21 -4
  747. package/src/CodeBlock/CodeBlock.spec.md +96 -61
  748. package/src/CodeBlock/CodeBlock.test.tsx +97 -1
  749. package/src/CodeBlock/CodeBlock.tsx +132 -22
  750. package/src/CodeBlock/CodeLanguage.test.tsx +173 -0
  751. package/src/CodeBlock/__tests__/CodeBlockCopyClearance.a11y.chromium.spec.ts +290 -0
  752. package/src/CodeBlock/__tests__/CodeBlockLanguages.a11y.chromium.spec.ts +64 -0
  753. package/src/CodeBlock/__tests__/CodeBlockOverflowStop.a11y.chromium.spec.ts +1 -0
  754. package/src/CodeBlock/__tests__/DiffRowPaint.a11y.chromium.spec.ts +1 -0
  755. package/src/CodeBlock/grammar.ts +291 -0
  756. package/src/CodeBlock/index.ts +7 -0
  757. package/src/CodeBlock/languages/dockerfile.ts +43 -0
  758. package/src/CodeBlock/languages/graphql.ts +30 -0
  759. package/src/CodeBlock/languages/java.ts +28 -0
  760. package/src/CodeBlock/languages/lua.ts +21 -0
  761. package/src/CodeBlock/languages/objective-c.ts +26 -0
  762. package/src/CodeBlock/languages/powershell.ts +31 -0
  763. package/src/CodeBlock/languages/ruby.ts +29 -0
  764. package/src/CodeBlock/languages/thrift.ts +32 -0
  765. package/src/CodeBlock/languages/toml.ts +36 -0
  766. package/src/CodeBlock/languages.test.ts +402 -0
  767. package/src/CodeBlock/tokenizer.ts +176 -16
  768. package/src/CodeBlock/tokenizerBudget.test.ts +112 -0
  769. package/src/Collapsible/Collapsible.doc.mjs +6 -0
  770. package/src/Collapsible/Collapsible.spec.md +26 -23
  771. package/src/Collapsible/Collapsible.tsx +121 -2
  772. package/src/Collapsible/__tests__/Collapsible.a11y.chromium.spec.ts +1 -0
  773. package/src/Collapsible/__tests__/CollapsibleGroup.a11y.chromium.spec.ts +1 -0
  774. package/src/Collapsible/__tests__/CollapsibleGroupAccordion.a11y.chromium.spec.ts +1 -0
  775. package/src/CommandPalette/CommandPalette.perf.test.ts +8 -4
  776. package/src/CommandPalette/CommandPalette.tsx +17 -1
  777. package/src/CommandPalette/CommandPaletteEmpty.doc.mjs +6 -3
  778. package/src/CommandPalette/CommandPaletteEmpty.spec.md +190 -0
  779. package/src/CommandPalette/CommandPaletteEmpty.tsx +4 -0
  780. package/src/CommandPalette/CommandPaletteInput.tsx +21 -2
  781. package/src/CommandPalette/__tests__/CommandPalette.a11y.chromium.spec.ts +1 -0
  782. package/src/CommandPalette/__tests__/CommandPaletteEmptyAudit.a11y.chromium.spec.ts +715 -0
  783. package/src/CommandPalette/__tests__/CommandPaletteFooter.a11y.chromium.spec.ts +3 -2
  784. package/src/CommandPalette/__tests__/CommandPaletteInputAudit.a11y.chromium.spec.ts +1 -0
  785. package/src/CommandPalette/__tests__/CommandPaletteItemAudit.a11y.chromium.spec.ts +1 -0
  786. package/src/CommandPalette/busyStartSettle.ts +26 -0
  787. package/src/ComplexSelector/ComplexSelector.doc.mjs +1 -1
  788. package/src/ComplexSelector/ComplexSelector.focusableDisabled.test.tsx +1 -1
  789. package/src/ComplexSelector/ComplexSelector.fr10.test.tsx +9 -9
  790. package/src/ComplexSelector/ComplexSelector.spec.md +161 -107
  791. package/src/ComplexSelector/ComplexSelector.test.tsx +236 -17
  792. package/src/ComplexSelector/ComplexSelector.tsx +69 -4
  793. package/src/ComplexSelector/__tests__/ComplexSelector.a11y.chromium.spec.ts +965 -0
  794. package/src/ContextMenu/ContextMenu.doc.mjs +1 -1
  795. package/src/ContextMenu/ContextMenu.spec.md +38 -30
  796. package/src/ContextMenu/ContextMenu.test.tsx +189 -11
  797. package/src/ContextMenu/ContextMenu.tsx +75 -17
  798. package/src/ContextMenu/__tests__/ContextMenuAudit.a11y.chromium.spec.ts +1 -0
  799. package/src/ContextMenu/__tests__/ContextMenuCursorAnchor.a11y.browser.spec.ts +1 -0
  800. package/src/ContextMenu/__tests__/ContextMenuLongPress.a11y.chromium.spec.ts +117 -0
  801. package/src/DateInput/DateInput.tsx +9 -4
  802. package/src/DateInput/DateInputTouch.test.tsx +10 -1
  803. package/src/DateInput/NativeDateField.tsx +2 -1
  804. package/src/DateInput/TouchDateField.tsx +2 -1
  805. package/src/DateInput/Wheel.tsx +4 -1
  806. package/src/DateInput/__tests__/DateInputAudit.a11y.chromium.spec.ts +1 -0
  807. package/src/DateInput/__tests__/WheelPinchZoom.a11y.chromium.spec.ts +171 -0
  808. package/src/Dialog/Dialog.doc.mjs +201 -47
  809. package/src/Dialog/Dialog.spec.md +20 -4
  810. package/src/Dialog/Dialog.tsx +37 -10
  811. package/src/Dialog/__tests__/Dialog.a11y.browser.spec.ts +1 -0
  812. package/src/Dialog/__tests__/Dialog.a11y.chromium.spec.ts +1 -0
  813. package/src/Dialog/__tests__/Dialog.reduced-motion.a11y.browser.spec.ts +252 -0
  814. package/src/Divider/Divider.spec.md +79 -70
  815. package/src/Drawer/Drawer.tsx +38 -35
  816. package/src/Drawer/__tests__/DrawerAudit.a11y.chromium.spec.ts +1 -0
  817. package/src/Drawer/__tests__/DrawerHeaderAudit.a11y.chromium.spec.ts +1 -0
  818. package/src/DropdownMenu/DropdownMenu.spec.md +14 -6
  819. package/src/DropdownMenu/DropdownMenu.ssr.test.tsx +44 -8
  820. package/src/DropdownMenu/DropdownMenu.test.tsx +107 -5
  821. package/src/DropdownMenu/DropdownMenu.tsx +51 -34
  822. package/src/DropdownMenu/DropdownMenuGroup.doc.mjs +2 -2
  823. package/src/DropdownMenu/DropdownMenuGroup.tsx +12 -6
  824. package/src/DropdownMenu/DropdownMenuItem.tsx +5 -5
  825. package/src/DropdownMenu/DropdownMenuRadioItem.doc.mjs +5 -2
  826. package/src/DropdownMenu/DropdownMenuRadioItem.spec.md +226 -0
  827. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +32 -16
  828. package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +158 -0
  829. package/src/DropdownMenu/DropdownMenuSheetFirstOpen.test.tsx +72 -0
  830. package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +9 -0
  831. package/src/DropdownMenu/DropdownMenuSubMenu.spec.md +225 -0
  832. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +105 -0
  833. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +6 -6
  834. package/src/DropdownMenu/MenuBottomSheet.tsx +42 -7
  835. package/src/DropdownMenu/MenuBottomSheetActionList.tsx +3 -3
  836. package/src/DropdownMenu/__tests__/DropdownMenuDividerAudit.a11y.chromium.spec.ts +1 -0
  837. package/src/DropdownMenu/__tests__/DropdownMenuDrillIn.a11y.chromium.spec.ts +1 -0
  838. package/src/DropdownMenu/__tests__/DropdownMenuFocusReturn.a11y.browser.spec.ts +1 -0
  839. package/src/DropdownMenu/__tests__/DropdownMenuGroupAudit.a11y.chromium.spec.ts +1 -0
  840. package/src/DropdownMenu/__tests__/DropdownMenuItemAudit.a11y.chromium.spec.ts +1 -0
  841. package/src/DropdownMenu/__tests__/DropdownMenuRadioGroupAudit.a11y.chromium.spec.ts +1 -0
  842. package/src/DropdownMenu/__tests__/DropdownMenuRadioItemAudit.a11y.chromium.spec.ts +540 -0
  843. package/src/DropdownMenu/__tests__/DropdownMenuSubMenuAudit.a11y.chromium.spec.ts +671 -0
  844. package/src/DropdownMenu/__tests__/Menu.a11y.chromium.spec.ts +1 -0
  845. package/src/DropdownMenu/__tests__/MenuButton.a11y.chromium.spec.ts +1 -0
  846. package/src/DropdownMenu/__tests__/MenuHeaderFooter.a11y.chromium.spec.ts +1 -0
  847. package/src/DropdownMenu/__tests__/MenuHoverFocus.a11y.chromium.spec.ts +238 -0
  848. package/src/DropdownMenu/__tests__/MenuPinchZoom.a11y.chromium.spec.ts +1 -0
  849. package/src/DropdownMenu/__tests__/MenuPress.a11y.chromium.spec.ts +1 -0
  850. package/src/DropdownMenu/__tests__/SubMenuHeaderFooter.a11y.chromium.spec.ts +1 -0
  851. package/src/DropdownMenu/lazyMenuBottomSheet.ts +28 -2
  852. package/src/DropdownMenu/menuBottomSheet.stylex.ts +33 -0
  853. package/src/DropdownMenu/menuItemHover.ts +13 -1
  854. package/src/DropdownMenu/menuTouchAction.stylex.ts +28 -0
  855. package/src/DropdownMenu/modules/useMenuPress.spec.md +90 -62
  856. package/src/DropdownMenu/useMenuDrillIn.tsx +7 -5
  857. package/src/EmptyState/EmptyState.announce.test.tsx +227 -0
  858. package/src/EmptyState/EmptyState.doc.mjs +1 -1
  859. package/src/EmptyState/EmptyState.spec.md +22 -14
  860. package/src/EmptyState/EmptyState.test.tsx +8 -8
  861. package/src/EmptyState/EmptyState.tsx +7 -5
  862. package/src/Field/Field.spec.md +57 -48
  863. package/src/Field/Field.tsx +1 -1
  864. package/src/Field/FieldLabel.spec.md +70 -59
  865. package/src/Field/FieldLabel.tsx +1 -1
  866. package/src/Field/PanelSearchInput.tsx +23 -13
  867. package/src/Field/__tests__/FieldLabelAudit.a11y.chromium.spec.ts +1 -0
  868. package/src/Field/inputDisabledFocus.ts +28 -0
  869. package/src/Field/inputStyles.stylex.ts +15 -15
  870. package/src/FieldStatus/FieldStatus.test.tsx +12 -0
  871. package/src/FieldStatus/FieldStatus.tsx +12 -3
  872. package/src/FieldStatus/__tests__/StatusMessage.a11y.chromium.spec.ts +1 -0
  873. package/src/FileInput/FileInput.doc.mjs +1 -1
  874. package/src/FileInput/FileInput.test.tsx +102 -0
  875. package/src/FileInput/FileInput.tsx +18 -12
  876. package/src/FormLayout/FormLayout.spec.md +69 -51
  877. package/src/Grid/Grid.spec.md +72 -69
  878. package/src/Grid/GridSpan.spec.md +158 -0
  879. package/src/Heading/Heading.spec.md +198 -0
  880. package/src/HoverCard/HoverCard.spec.md +244 -0
  881. package/src/HoverCard/HoverCard.test.tsx +93 -3
  882. package/src/Icon/Icon.doc.mjs +67 -5
  883. package/src/Icon/Icon.test.tsx +548 -9
  884. package/src/Icon/Icon.tsx +79 -15
  885. package/src/Icon/IconSize.stylex.ts +27 -11
  886. package/src/Icon/globalIconRegistry.test.tsx +395 -3
  887. package/src/Icon/globalIconRegistry.tsx +184 -36
  888. package/src/Icon/index.ts +29 -1
  889. package/src/Icon/useIcon.ts +5 -1
  890. package/src/IconButton/IconButton.spec.md +197 -0
  891. package/src/IconButton/IconButton.test.tsx +5 -2
  892. package/src/InputGroup/InputGroup.spec.md +199 -0
  893. package/src/InputGroup/InputGroup.test.tsx +120 -0
  894. package/src/InputGroup/InputGroup.tsx +59 -52
  895. package/src/InputGroup/InputGroupInternalContext.ts +15 -0
  896. package/src/InputGroup/InputGroupText.spec.md +139 -0
  897. package/src/InputGroup/InputGroupText.tsx +2 -0
  898. package/src/InputGroup/groupStyles.ts +22 -11
  899. package/src/Item/Item.test.tsx +158 -1
  900. package/src/Item/Item.tsx +42 -7
  901. package/src/Item/ItemMarkerColumns.a11y.chromium.spec.ts +211 -0
  902. package/src/Item/ItemMarkerColumnsContext.tsx +20 -0
  903. package/src/Item/ItemSwipeLayer.tsx +9 -0
  904. package/src/Item/__tests__/ItemSwipeActions.a11y.chromium.spec.ts +1 -0
  905. package/src/Item/__tests__/ItemSwipePinchZoom.a11y.chromium.spec.ts +186 -0
  906. package/src/Item/useSwipeAction.ts +71 -5
  907. package/src/Kbd/Kbd.test.tsx +95 -0
  908. package/src/Kbd/Kbd.tsx +30 -23
  909. package/src/Layer/LayerProvider.spec.md +149 -0
  910. package/src/Layer/__tests__/LayerReducedMotion.a11y.chromium.spec.ts +176 -0
  911. package/src/Layer/__tests__/TouchTrigger.a11y.chromium.spec.ts +200 -0
  912. package/src/Layer/layerAnimations.stylex.ts +22 -2
  913. package/src/Layer/layerDismissalInvariants.test.tsx +9 -0
  914. package/src/Layer/layerSlideRules.ts +141 -8
  915. package/src/Layer/layerStack.ts +129 -62
  916. package/src/Layer/modalOutlet.ts +156 -15
  917. package/src/Layer/preserveAnimations.ts +304 -0
  918. package/src/Layer/useLayer.doc.mjs +1 -1
  919. package/src/Layer/useLayer.test.tsx +850 -0
  920. package/src/Layer/useLayer.tsx +644 -58
  921. package/src/Layer/useLayerDismissal.test.tsx +85 -2
  922. package/src/Layer/useLayerDismissal.ts +12 -9
  923. package/src/Layer/useTouchTrigger.ts +95 -41
  924. package/src/Layout/Layout.tsx +18 -0
  925. package/src/Layout/LayoutContent.tsx +5 -14
  926. package/src/Layout/LayoutFooter.tsx +2 -0
  927. package/src/Layout/LayoutHeader.tsx +2 -0
  928. package/src/Layout/__tests__/Layout.a11y.chromium.spec.ts +1 -0
  929. package/src/Layout/layoutEdges.stylex.ts +25 -0
  930. package/src/Lightbox/Lightbox.spec.md +9 -8
  931. package/src/Lightbox/Lightbox.test.tsx +83 -0
  932. package/src/Lightbox/Lightbox.tsx +149 -125
  933. package/src/Lightbox/LightboxKeyboard.a11y.browser.spec.ts +78 -0
  934. package/src/Lightbox/LightboxViewport.a11y.browser.spec.ts +70 -0
  935. package/src/Link/Link.spec.md +229 -0
  936. package/src/Link/LinkProvider.spec.md +167 -0
  937. package/src/Link/__tests__/Link.a11y.chromium.spec.ts +1 -0
  938. package/src/Link/__tests__/Link.navigation.a11y.chromium.spec.ts +1 -0
  939. package/src/List/List.spec.md +113 -34
  940. package/src/List/List.tsx +13 -1
  941. package/src/List/ListContext.tsx +19 -5
  942. package/src/List/ListItem.doc.mjs +3 -3
  943. package/src/List/ListItem.tsx +97 -28
  944. package/src/List/ListMarkers.a11y.chromium.spec.ts +904 -0
  945. package/src/Markdown/Markdown.codeLanguages.test.tsx +137 -0
  946. package/src/Markdown/Markdown.doc.mjs +12 -0
  947. package/src/Markdown/Markdown.fr23.bench.ts +3 -1
  948. package/src/Markdown/Markdown.fr23.perf.test.ts +45 -3
  949. package/src/Markdown/Markdown.fr23.sampling.ts +13 -4
  950. package/src/Markdown/Markdown.spec.md +71 -59
  951. package/src/Markdown/Markdown.test.tsx +50 -0
  952. package/src/Markdown/Markdown.tsx +61 -8
  953. package/src/Markdown/MarkdownTable.a11y.chromium.spec.ts +1 -0
  954. package/src/Markdown/__tests__/MarkdownNesting.a11y.chromium.spec.ts +1 -0
  955. package/src/MobileNav/MobileNav.doc.mjs +2 -2
  956. package/src/MobileNav/MobileNav.spec.md +161 -64
  957. package/src/MobileNav/MobileNav.test.tsx +27 -10
  958. package/src/MobileNav/MobileNav.tsx +51 -38
  959. package/src/MobileNav/MobileNavPinchZoom.a11y.chromium.spec.ts +1 -0
  960. package/src/MobileNav/MobileNavToggle.test.tsx +63 -0
  961. package/src/MobileNav/MobileNavToggle.tsx +13 -5
  962. package/src/MobileNav/__tests__/MobileNavWidth.a11y.chromium.spec.ts +103 -0
  963. package/src/MoreMenu/MoreMenu.doc.mjs +2 -2
  964. package/src/MoreMenu/MoreMenu.spec.md +88 -53
  965. package/src/MultiSelector/CreateRow.a11y.chromium.spec.ts +67 -9
  966. package/src/MultiSelector/MultiSelector.disabledFocus.a11y.chromium.spec.ts +1 -0
  967. package/src/MultiSelector/MultiSelector.test.tsx +122 -10
  968. package/src/MultiSelector/MultiSelector.tsx +24 -4
  969. package/src/MultiSelector/OptionActions.a11y.chromium.spec.ts +1 -0
  970. package/src/MultiSelector/__tests__/MultiSelector.a11y.chromium.spec.ts +1 -0
  971. package/src/NavIcon/NavIcon.spec.md +66 -38
  972. package/src/NavMenu/NavHeadingMenu.spec.md +104 -46
  973. package/src/NavMenu/NavHeadingMenu.test.tsx +276 -2
  974. package/src/NavMenu/NavHeadingMenu.tsx +42 -4
  975. package/src/NavMenu/NavHeadingMenuItem.tsx +60 -6
  976. package/src/NavMenu/NavMenuContext.tsx +11 -0
  977. package/src/NavMenu/__tests__/NavMenusSlideSelection.a11y.chromium.spec.ts +137 -0
  978. package/src/NumberInput/NumberInput.doc.mjs +6 -6
  979. package/src/NumberInput/NumberInput.spec.md +248 -0
  980. package/src/NumberInput/NumberInput.test.tsx +187 -14
  981. package/src/NumberInput/NumberInput.tsx +86 -24
  982. package/src/NumberInput/__tests__/NumberInput.a11y.chromium.spec.ts +1 -0
  983. package/src/Overlay/Overlay.doc.mjs +2 -2
  984. package/src/Overlay/Overlay.test.tsx +72 -4
  985. package/src/Overlay/Overlay.tsx +18 -8
  986. package/src/Pagination/Pagination.test.tsx +2 -2
  987. package/src/Popover/Popover.doc.mjs +38 -2
  988. package/src/Popover/Popover.spec.md +90 -11
  989. package/src/Popover/Popover.test.tsx +340 -2
  990. package/src/Popover/Popover.tsx +401 -35
  991. package/src/Popover/PopoverPresentation.test.tsx +952 -0
  992. package/src/Popover/__tests__/PopoverSecondDocument.a11y.chromium.spec.ts +205 -0
  993. package/src/Popover/index.ts +5 -1
  994. package/src/Popover/lazyPopoverBottomSheet.ts +57 -0
  995. package/src/Popover/usePopover.tsx +11 -5
  996. package/src/PowerSearch/PowerSearch.spec.md +423 -53
  997. package/src/PowerSearch/PowerSearch.test.tsx +77 -1
  998. package/src/PowerSearch/PowerSearch.tsx +7 -5
  999. package/src/ProgressBar/ProgressBar.test.tsx +12 -0
  1000. package/src/ProgressBar/ProgressBar.tsx +18 -0
  1001. package/src/ProgressBar/__tests__/ProgressBar.a11y.chromium.spec.ts +1 -0
  1002. package/src/RadioList/RadioList.spec.md +227 -0
  1003. package/src/RadioList/RadioList.test.tsx +34 -7
  1004. package/src/RadioList/RadioListItem.press.source-build.test.mjs +80 -0
  1005. package/src/RadioList/RadioListItem.spec.md +223 -0
  1006. package/src/RadioList/RadioListItem.tsx +26 -12
  1007. package/src/RadioList/__tests__/RadioGroup.a11y.chromium.spec.ts +1 -0
  1008. package/src/Resizable/__tests__/ResizeHandle.a11y.chromium.spec.ts +1 -0
  1009. package/src/ScrollableArea/ScrollableArea.spec.md +6 -5
  1010. package/src/ScrollableArea/ScrollableArea.test.tsx +5 -0
  1011. package/src/ScrollableArea/ScrollableArea.tsx +4 -0
  1012. package/src/Section/Section.spec.md +102 -44
  1013. package/src/SegmentedControl/SegmentedControl.spec.md +162 -53
  1014. package/src/SegmentedControl/SegmentedControl.test.tsx +46 -0
  1015. package/src/SegmentedControl/SegmentedControl.tsx +7 -3
  1016. package/src/SegmentedControl/SegmentedControlItem.spec.md +206 -0
  1017. package/src/SelectableCard/SelectableCard.doc.mjs +7 -6
  1018. package/src/SelectableCard/SelectableCard.spec.md +230 -0
  1019. package/src/SelectableCard/SelectableCard.test.tsx +11 -1
  1020. package/src/SelectableCard/SelectableCard.tsx +49 -33
  1021. package/src/Selector/Selector.sheetActiveDescendant.test.tsx +95 -0
  1022. package/src/Selector/Selector.spec.md +12 -4
  1023. package/src/Selector/Selector.test.tsx +114 -8
  1024. package/src/Selector/Selector.tsx +30 -6
  1025. package/src/Selector/__tests__/ComboboxField.a11y.chromium.spec.ts +458 -0
  1026. package/src/Selector/__tests__/EmptyStateAnnouncement.a11y.chromium.spec.ts +1 -0
  1027. package/src/Selector/__tests__/Listbox.a11y.chromium.spec.ts +1 -0
  1028. package/src/Selector/__tests__/Selector.a11y.chromium.spec.ts +1 -0
  1029. package/src/Selector/__tests__/Selector.combobox.a11y.chromium.spec.ts +1 -0
  1030. package/src/Selector/hooks.ts +234 -10
  1031. package/src/Selector/useCombobox.doc.mjs +156 -9
  1032. package/src/Selector/useCombobox.public.test.tsx +89 -0
  1033. package/src/Selector/useCombobox.test.tsx +444 -0
  1034. package/src/SideNav/SideNav.spec.md +50 -30
  1035. package/src/SideNav/SideNav.test.tsx +425 -25
  1036. package/src/SideNav/SideNav.tsx +85 -1
  1037. package/src/SideNav/SideNavCollapseButton.spec.md +161 -0
  1038. package/src/SideNav/SideNavHeading.spec.md +226 -0
  1039. package/src/SideNav/SideNavHeading.tsx +102 -6
  1040. package/src/SideNav/SideNavItem.spec.md +246 -0
  1041. package/src/SideNav/SideNavItem.tsx +40 -9
  1042. package/src/SideNav/SideNavRailMotion.test.tsx +620 -0
  1043. package/src/SideNav/SideNavSection.spec.md +153 -0
  1044. package/src/SideNav/__tests__/SideNavRailMotion.interaction.browser.spec.ts +417 -0
  1045. package/src/SideNav/railMotion.ts +315 -0
  1046. package/src/Skeleton/Skeleton.spec.md +99 -42
  1047. package/src/Skeleton/Skeleton.test.tsx +108 -1
  1048. package/src/Skeleton/Skeleton.tsx +30 -2
  1049. package/src/Slider/Slider.fr10.test.tsx +34 -0
  1050. package/src/Slider/Slider.test.tsx +172 -0
  1051. package/src/Slider/Slider.tsx +70 -14
  1052. package/src/Slider/__tests__/Slider.a11y.chromium.spec.ts +1 -0
  1053. package/src/Spinner/Spinner.spec.md +231 -0
  1054. package/src/Stack/Stack.spec.md +104 -56
  1055. package/src/StatusDot/StatusDot.spec.md +139 -51
  1056. package/src/StatusDot/StatusDot.test.tsx +13 -0
  1057. package/src/StatusDot/StatusDot.tsx +27 -0
  1058. package/src/Stepper/Step.spec.md +206 -0
  1059. package/src/Stepper/Step.tsx +19 -3
  1060. package/src/Stepper/Stepper.test.tsx +50 -0
  1061. package/src/Switch/Switch.focusRing.source-build.test.mjs +81 -0
  1062. package/src/Switch/Switch.spec.md +150 -66
  1063. package/src/Switch/Switch.tsx +11 -9
  1064. package/src/Switch/__tests__/Switch.a11y.chromium.spec.ts +1 -0
  1065. package/src/Switch/switch.markers.stylex.ts +7 -2
  1066. package/src/TabList/Tab.spec.md +201 -0
  1067. package/src/TabList/Tab.tsx +7 -1
  1068. package/src/TabList/TabList.doc.mjs +3 -3
  1069. package/src/TabList/TabList.test.tsx +27 -0
  1070. package/src/TabList/TabMenu.spec.md +198 -0
  1071. package/src/TabList/TabMenu.tsx +24 -1
  1072. package/src/TabList/__tests__/TabListOverflow.interaction.browser.spec.ts +99 -0
  1073. package/src/TabList/__tests__/Tabs.a11y.chromium.spec.ts +1 -0
  1074. package/src/Table/Table.spec.md +54 -30
  1075. package/src/Table/TableCell.tsx +9 -0
  1076. package/src/Table/TableHeaderCell.tsx +2 -0
  1077. package/src/Table/TableRow.tsx +3 -0
  1078. package/src/Table/__tests__/Table.a11y.chromium.spec.ts +129 -0
  1079. package/src/Table/__tests__/Table.a11y.contracts.ts +35 -0
  1080. package/src/Table/__tests__/Table.a11y.renders.tsx +112 -0
  1081. package/src/Table/__tests__/Table.a11y.states.ts +140 -0
  1082. package/src/Table/__tests__/Table.a11y.test.tsx +198 -0
  1083. package/src/Table/__tests__/TableMinWidth.a11y.chromium.spec.ts +1 -0
  1084. package/src/Table/__tests__/TableRowGlide.a11y.browser.spec.ts +382 -0
  1085. package/src/Table/__tests__/TableScroll.a11y.chromium.spec.ts +1 -0
  1086. package/src/Table/__tests__/TableStickyDividers.a11y.browser.spec.ts +560 -0
  1087. package/src/Table/glidingDivider.ts +336 -0
  1088. package/src/Table/plugins/columnResize/useTableColumnResize.tsx +23 -8
  1089. package/src/Table/plugins/rowExpansion/useTableRowExpansion.glide.test.tsx +280 -0
  1090. package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +91 -9
  1091. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +471 -10
  1092. package/src/Table/plugins/rowStatus/useTableRowStatus.spec.md +4 -4
  1093. package/src/Table/plugins/sortable/__tests__/useTableSortable.a11y.test.tsx +174 -0
  1094. package/src/Table/plugins/sortable/__tests__/useTableSortable.a11y.ts +86 -0
  1095. package/src/Table/plugins/sortable/useTableSortable.test.tsx +0 -12
  1096. package/src/Table/plugins/stickyColumns/useTableStickyColumns.test.tsx +51 -1
  1097. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +312 -12
  1098. package/src/Table/rowDivider.ts +154 -0
  1099. package/src/Table/useTableRowExpansion.doc.mjs +8 -0
  1100. package/src/Text/Text.spec.md +114 -127
  1101. package/src/TextArea/TextArea.doc.mjs +6 -6
  1102. package/src/TextArea/TextArea.spec.md +164 -64
  1103. package/src/TextArea/TextArea.test.tsx +65 -6
  1104. package/src/TextArea/TextArea.tsx +27 -15
  1105. package/src/TextInput/TextInput.doc.mjs +8 -8
  1106. package/src/TextInput/TextInput.spec.md +260 -0
  1107. package/src/TextInput/TextInput.test.tsx +126 -10
  1108. package/src/TextInput/TextInput.tsx +57 -23
  1109. package/src/TextInput/__tests__/TextInput.a11y.chromium.spec.ts +1 -0
  1110. package/src/Thumbnail/Thumbnail.doc.mjs +1 -2
  1111. package/src/Thumbnail/Thumbnail.spec.md +244 -0
  1112. package/src/Thumbnail/Thumbnail.test.tsx +120 -7
  1113. package/src/Thumbnail/Thumbnail.tsx +77 -31
  1114. package/src/TimeInput/TimeInput.spec.md +273 -0
  1115. package/src/TimeInput/TimeInput.tsx +12 -4
  1116. package/src/TimeInput/TouchTimeField.tsx +2 -1
  1117. package/src/Timestamp/Timestamp.spec.md +252 -0
  1118. package/src/Toast/Toast.spec.md +300 -0
  1119. package/src/Toast/ToastViewport.modalHost.test.tsx +630 -5
  1120. package/src/Toast/ToastViewport.test.tsx +137 -0
  1121. package/src/Toast/ToastViewport.tsx +63 -6
  1122. package/src/ToggleButton/ToggleButton.spec.md +256 -0
  1123. package/src/ToggleButton/ToggleButtonGroup.spec.md +195 -0
  1124. package/src/ToggleButton/__tests__/ToggleButton.a11y.chromium.spec.ts +1 -0
  1125. package/src/Token/Token.spec.md +271 -0
  1126. package/src/Token/__tests__/TokenRemoveTarget.a11y.chromium.spec.ts +1 -0
  1127. package/src/Tokenizer/Tokenizer.props-type.test.tsx +126 -0
  1128. package/src/Tokenizer/Tokenizer.spec.md +313 -72
  1129. package/src/Tokenizer/Tokenizer.ssr.test.tsx +196 -0
  1130. package/src/Tokenizer/Tokenizer.test.tsx +44 -8
  1131. package/src/Tokenizer/Tokenizer.tsx +586 -41
  1132. package/src/Tokenizer/TokenizerBottomSheet.test.tsx +2719 -0
  1133. package/src/Tokenizer/TokenizerBottomSheet.tsx +957 -0
  1134. package/src/Tokenizer/__tests__/TokenizerEndLane.a11y.chromium.spec.ts +61 -27
  1135. package/src/Toolbar/Toolbar.spec.md +103 -49
  1136. package/src/Toolbar/__tests__/Toolbar.a11y.chromium.spec.ts +1 -0
  1137. package/src/Tooltip/Tooltip.spec.md +161 -36
  1138. package/src/Tooltip/Tooltip.test.tsx +171 -3
  1139. package/src/Tooltip/__tests__/Tooltip.a11y.chromium.spec.ts +1 -0
  1140. package/src/Tooltip/__tests__/Tooltip.a11y.states.ts +2 -2
  1141. package/src/Tooltip/__tests__/TooltipFocusReturn.a11y.chromium.spec.ts +1 -0
  1142. package/src/Tooltip/__tests__/TooltipHoverBridge.a11y.chromium.spec.ts +1 -0
  1143. package/src/Tooltip/__tests__/TooltipTallContent.a11y.browser.spec.ts +673 -0
  1144. package/src/Tooltip/__tests__/TooltipTallContentTracking.a11y.browser.spec.ts +1162 -0
  1145. package/src/Tooltip/useTooltip.tsx +7 -2
  1146. package/src/TopNav/TopNav.spec.md +190 -0
  1147. package/src/TopNav/TopNav.test.tsx +89 -0
  1148. package/src/TopNav/TopNavHeading.spec.md +211 -0
  1149. package/src/TopNav/TopNavHeading.tsx +35 -2
  1150. package/src/TopNav/TopNavItem.spec.md +189 -0
  1151. package/src/TopNav/TopNavMegaMenu.reduced-motion.source-build.test.mjs +83 -0
  1152. package/src/TopNav/TopNavMegaMenu.spec.md +190 -0
  1153. package/src/TopNav/TopNavMegaMenu.tsx +21 -4
  1154. package/src/TopNav/TopNavMegaMenuFeaturedCard.spec.md +150 -0
  1155. package/src/TopNav/TopNavMegaMenuItem.spec.md +155 -0
  1156. package/src/TopNav/TopNavMenu.spec.md +202 -0
  1157. package/src/TopNav/TopNavMenu.test.tsx +65 -1
  1158. package/src/TopNav/TopNavMenu.tsx +30 -1
  1159. package/src/TopNav/__tests__/TopNavMobileLongHeading.a11y.chromium.spec.ts +1 -0
  1160. package/src/TreeList/TreeList.doc.mjs +13 -0
  1161. package/src/TreeList/TreeList.spec.md +54 -35
  1162. package/src/TreeList/TreeList.tsx +234 -2
  1163. package/src/TreeList/TreeListBranches.tsx +8 -6
  1164. package/src/TreeList/TreeListItem.tsx +12 -6
  1165. package/src/TreeList/__tests__/TreeList.a11y.chromium.spec.ts +19 -6
  1166. package/src/TreeList/__tests__/TreeListGuideAlignment.interaction.browser.spec.ts +127 -0
  1167. package/src/TreeList/__tests__/TreeListRowNames.a11y.chromium.spec.ts +1 -0
  1168. package/src/Typeahead/BaseTypeahead.emptyState.a11y.chromium.spec.ts +138 -0
  1169. package/src/Typeahead/BaseTypeahead.test.tsx +201 -4
  1170. package/src/Typeahead/BaseTypeahead.tsx +26 -10
  1171. package/src/Typeahead/Typeahead.test.tsx +114 -1
  1172. package/src/Typeahead/Typeahead.tsx +34 -16
  1173. package/src/VisuallyHidden/VisuallyHidden.spec.md +170 -0
  1174. package/src/__tests__/BusyOwnerAnnouncement.test.tsx +66 -5
  1175. package/src/__tests__/CardPress.a11y.chromium.spec.ts +353 -0
  1176. package/src/__tests__/DisabledTriggerFocus.a11y.chromium.spec.ts +2 -1
  1177. package/src/__tests__/PressModality.a11y.chromium.spec.ts +392 -0
  1178. package/src/__tests__/PressedState.a11y.chromium.spec.ts +1 -0
  1179. package/src/__tests__/pressState.ts +43 -1
  1180. package/src/__tests__/unthemedLength.ts +34 -0
  1181. package/src/gestures/GestureArena.ts +966 -0
  1182. package/src/gestures/GestureRecognizer.ts +626 -0
  1183. package/src/gestures/LongPressGestureRecognizer.ts +186 -0
  1184. package/src/gestures/PanGestureRecognizer.ts +410 -0
  1185. package/src/gestures/TapGestureRecognizer.ts +192 -0
  1186. package/src/gestures/VelocityTracker.ts +194 -0
  1187. package/src/gestures/__tests__/LongPressGestureRecognizer.test.ts +141 -0
  1188. package/src/gestures/__tests__/PanGestureRecognizer.test.ts +327 -0
  1189. package/src/gestures/__tests__/TapGestureRecognizer.test.ts +154 -0
  1190. package/src/gestures/__tests__/VelocityTracker.streams.test.ts +243 -0
  1191. package/src/gestures/__tests__/VelocityTracker.test.ts +261 -0
  1192. package/src/gestures/__tests__/arena.test.ts +824 -0
  1193. package/src/gestures/__tests__/arenaContinuous.test.ts +207 -0
  1194. package/src/gestures/__tests__/arenaTapLongPress.test.ts +211 -0
  1195. package/src/gestures/__tests__/fixtures/pointer-streams/README.md +82 -0
  1196. package/src/gestures/__tests__/fixtures/pointer-streams/android-chromium-fling.json +130 -0
  1197. package/src/gestures/__tests__/fixtures/pointer-streams/android-chromium-slow.json +860 -0
  1198. package/src/gestures/__tests__/fixtures/pointer-streams/android-chromium-stop-release.json +357 -0
  1199. package/src/gestures/__tests__/fixtures/pointer-streams/android-firefox-fling.json +66 -0
  1200. package/src/gestures/__tests__/fixtures/pointer-streams/android-firefox-slow.json +268 -0
  1201. package/src/gestures/__tests__/fixtures/pointer-streams/android-firefox-stop-release.json +128 -0
  1202. package/src/gestures/__tests__/fixtures/pointer-streams/capture.html +123 -0
  1203. package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-mouse-fling.json +64 -0
  1204. package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-mouse-slow.json +268 -0
  1205. package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-mouse-stop-release.json +124 -0
  1206. package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-pen-fling.json +64 -0
  1207. package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-pen-slow.json +268 -0
  1208. package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-pen-stop-release.json +124 -0
  1209. package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-touch-fling.json +84 -0
  1210. package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-touch-slow.json +381 -0
  1211. package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-touch-stop-release.json +171 -0
  1212. package/src/gestures/__tests__/fixtures/pointer-streams/ios-safari-fling.json +45 -0
  1213. package/src/gestures/__tests__/fixtures/pointer-streams/ios-safari-slow.json +101 -0
  1214. package/src/gestures/__tests__/fixtures/pointer-streams/ios-safari-stop-release.json +130 -0
  1215. package/src/gestures/__tests__/harness.ts +204 -0
  1216. package/src/gestures/geometry.ts +55 -0
  1217. package/src/gestures/types.ts +161 -0
  1218. package/src/hooks/AnnounceRenderedText.tsx +27 -0
  1219. package/src/hooks/ModalAnnounceProvider.tsx +155 -0
  1220. package/src/hooks/__tests__/MenuPressShadowRoot.a11y.chromium.spec.ts +98 -4
  1221. package/src/hooks/__tests__/menuLinkClicks.ts +71 -0
  1222. package/src/hooks/actionGroupTracker.exports.test.ts +28 -0
  1223. package/src/hooks/actionGroupTracker.test.ts +510 -0
  1224. package/src/hooks/actionGroupTracker.ts +449 -0
  1225. package/src/hooks/index.ts +6 -0
  1226. package/src/hooks/menuPressOnItems.ts +40 -0
  1227. package/src/hooks/modalAnnounce.ts +439 -0
  1228. package/src/hooks/scrollGeometry.ts +71 -4
  1229. package/src/hooks/useAdaptivePresentation.ts +46 -9
  1230. package/src/hooks/useAnimatedLayout.doc.mjs +101 -0
  1231. package/src/hooks/useAnimatedLayout.ts +61 -0
  1232. package/src/hooks/useAnnounce.doc.mjs +4 -4
  1233. package/src/hooks/useAnnounce.modal.test.tsx +1291 -0
  1234. package/src/hooks/useAnnounce.test.tsx +64 -4
  1235. package/src/hooks/useAnnounce.ts +452 -28
  1236. package/src/hooks/useAnnounceRenderedText.adopters.test.tsx +226 -0
  1237. package/src/hooks/useAnnounceRenderedText.ts +81 -11
  1238. package/src/hooks/useBusyAnnouncement.adopters.test.tsx +69 -0
  1239. package/src/hooks/useBusyAnnouncement.test.tsx +112 -0
  1240. package/src/hooks/useBusyAnnouncement.ts +64 -54
  1241. package/src/hooks/useFocusTrap.doc.mjs +3 -3
  1242. package/src/hooks/useFocusTrap.test.tsx +135 -2
  1243. package/src/hooks/useFocusTrap.ts +59 -27
  1244. package/src/hooks/useMenuHover.ts +6 -2
  1245. package/src/hooks/useMenuPress.doc.mjs +2 -2
  1246. package/src/hooks/useMenuPress.test.tsx +5 -2
  1247. package/src/hooks/useMenuPress.ts +72 -37
  1248. package/src/hooks/usePressFeedback.doc.mjs +4 -4
  1249. package/src/hooks/usePressFeedback.ts +5 -2
  1250. package/src/hooks/useScrollableArea.test.tsx +344 -3
  1251. package/src/hooks/useScrollableArea.ts +120 -12
  1252. package/src/i18n/generated-locales/en.generated.ts +35 -0
  1253. package/src/i18n/generated-locales/pseudo.generated.ts +37 -0
  1254. package/src/internal/tokenizer-presentation.test.ts +29 -0
  1255. package/src/internal/tokenizer-presentation.ts +25 -0
  1256. package/src/internal/touch.test.ts +44 -0
  1257. package/src/internal/touch.ts +41 -0
  1258. package/src/motion/LayoutChangeSnapshot.tsx +50 -0
  1259. package/src/motion/MEASUREMENTS.md +271 -0
  1260. package/src/motion/README.md +218 -0
  1261. package/src/motion/__tests__/animatedLayout.interaction.browser.spec.ts +1613 -0
  1262. package/src/motion/__tests__/animatedLayoutAdopters.interaction.browser.spec.ts +217 -0
  1263. package/src/motion/__tests__/animatedLayoutBundle.ts +17 -0
  1264. package/src/motion/animatedLayout.boundary.test.ts +155 -0
  1265. package/src/motion/animatedLayout.swap.test.ts +827 -0
  1266. package/src/motion/animatedLayout.test.ts +1154 -0
  1267. package/src/motion/animatedLayout.ts +1801 -0
  1268. package/src/motion/animatedLayoutAdopters.test.tsx +500 -0
  1269. package/src/motion/animator.test.ts +2653 -0
  1270. package/src/motion/animator.ts +2794 -0
  1271. package/src/motion/bezier.test.ts +52 -0
  1272. package/src/motion/bezier.ts +64 -0
  1273. package/src/motion/coast.test.ts +99 -0
  1274. package/src/motion/coast.ts +150 -0
  1275. package/src/motion/decay.test.ts +120 -0
  1276. package/src/motion/decay.ts +126 -0
  1277. package/src/motion/projection.test.ts +107 -0
  1278. package/src/motion/projection.ts +116 -0
  1279. package/src/motion/reducedMotion.stylex.ts +41 -0
  1280. package/src/motion/reducedMotion.test.ts +129 -0
  1281. package/src/motion/reducedMotion.ts +94 -0
  1282. package/src/motion/reducedMotionPlan.test.ts +182 -0
  1283. package/src/motion/reducedMotionPlan.ts +263 -0
  1284. package/src/motion/resolveSnapPoint.test.ts +189 -0
  1285. package/src/motion/resolveSnapPoint.ts +169 -0
  1286. package/src/motion/roleValue.ts +105 -0
  1287. package/src/motion/roles.test.ts +256 -0
  1288. package/src/motion/roles.ts +262 -0
  1289. package/src/motion/rubberBand.test.ts +88 -0
  1290. package/src/motion/rubberBand.ts +115 -0
  1291. package/src/motion/selectPage.test.ts +31 -0
  1292. package/src/motion/selectPage.ts +55 -0
  1293. package/src/motion/spring.test.ts +650 -0
  1294. package/src/motion/spring.ts +551 -0
  1295. package/src/motion/transientCopy.ts +374 -0
  1296. package/src/motion/uikit/gestures.test.ts +89 -0
  1297. package/src/motion/uikit/gestures.ts +359 -0
  1298. package/src/motion/uikit/index.ts +80 -0
  1299. package/src/motion/uikit/navigation.ts +83 -0
  1300. package/src/motion/uikit/scroll.ts +141 -0
  1301. package/src/motion/uikit/springRows.test.ts +71 -0
  1302. package/src/motion/uikit/springs.ts +514 -0
  1303. package/src/motion/uikit/timing.ts +210 -0
  1304. package/src/motion/uikit/uikit.test.ts +364 -0
  1305. package/src/motion/uikit/values.test.ts +110 -0
  1306. package/src/reset.a11y.chromium.spec.ts +1 -0
  1307. package/src/reset.until-found.a11y.browser.spec.ts +1 -0
  1308. package/src/serverSafeComponents.test.ts +10 -0
  1309. package/src/tailwind-theme.css +51 -1
  1310. package/src/tailwind-theme.test.ts +51 -0
  1311. package/src/theme/Theme.test.tsx +28 -0
  1312. package/src/theme/__tests__/SpacingRootFontSize.a11y.chromium.spec.ts +1 -0
  1313. package/src/theme/declarationBoundary.ts +282 -1
  1314. package/src/theme/defineTheme.test.ts +529 -12
  1315. package/src/theme/defineTheme.ts +231 -19
  1316. package/src/theme/derivedVarRegistry.test.ts +34 -5
  1317. package/src/theme/derivedVarRegistry.ts +4 -0
  1318. package/src/theme/expandMotionScale.test.ts +17 -0
  1319. package/src/theme/extensibleAxes.test.ts +74 -29
  1320. package/src/theme/generateThemeRules.ts +772 -35
  1321. package/src/theme/index.ts +3 -0
  1322. package/src/theme/onMediaTokens.test.ts +186 -0
  1323. package/src/theme/statusColor.ts +189 -0
  1324. package/src/theme/statusRoleDerivation.ts +289 -0
  1325. package/src/theme/syntax/SyntaxTheme.tsx +1 -1
  1326. package/src/theme/syntax/defineSyntaxTheme.ts +1 -1
  1327. package/src/theme/syntax/presets.ts +1 -1
  1328. package/src/theme/syntax/tokens.ts +1 -1
  1329. package/src/theme/themeAdaptations.test.ts +412 -0
  1330. package/src/theme/themeAdaptations.ts +43 -1
  1331. package/src/theme/tokens.stylex.ts +36 -2
  1332. package/src/theme/tokens.test.ts +111 -1
  1333. package/src/theme/tokens.ts +23 -1
  1334. package/src/theme/useTheme.ts +10 -4
  1335. package/src/utils/customPropertyArmLayering.test.ts +131 -0
  1336. package/src/utils/edgeAutoscroll.test.ts +192 -0
  1337. package/src/utils/edgeAutoscroll.ts +111 -0
  1338. package/src/utils/hitArea.test.ts +628 -0
  1339. package/src/utils/hitArea.ts +770 -0
  1340. package/src/utils/interactionOverlay.stylex.ts +4 -1
  1341. package/src/utils/pressFeedback.test.ts +310 -2
  1342. package/src/utils/pressFeedback.ts +306 -54
  1343. package/src/utils/pressGesture.test.ts +50 -0
  1344. package/src/utils/pressGesture.ts +40 -2
  1345. package/src/utils/touchPresentation.test.ts +323 -0
  1346. package/src/utils/touchPresentation.ts +153 -0
@@ -0,0 +1,2054 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file bottomSheetStack.ts
7
+ * @input Uses the DOM (dialog elements, document order) and focusForLastInput
8
+ * @output Exports the private bottom-sheet stack registry: registration of
9
+ * sheet hosts (modal sheets stack; non-modal sheets are a group of their
10
+ * own, hosted as manual popovers), open-order ranking with tree-order
11
+ * ties, native top-layer reconciliation, one view per host (top, covered,
12
+ * recede depth, scrim ownership, blocking), the replace handoff between a
13
+ * sheet closing and a sheet opening in the same update, and the native
14
+ * show/hide and focus helpers the hosts share
15
+ * @position Internal to BottomSheet; consumed by the standalone host in
16
+ * BottomSheet.tsx and by BottomSheetSwitcher. Not exported from the package
17
+ * root, and no public API reaches it.
18
+ *
19
+ * SYNC: When modified, update:
20
+ * - /packages/core/src/BottomSheet/BottomSheet.tsx
21
+ * - /packages/core/src/BottomSheet/BottomSheetSwitcher.tsx
22
+ * - /packages/core/src/BottomSheet/BottomSheetStacking.test.tsx
23
+ * - /packages/core/src/BottomSheet/BottomSheetReplace.test.tsx
24
+ * - /packages/core/src/BottomSheet/BottomSheet.doc.mjs
25
+ * - /apps/storybook/stories/BottomSheetReplace.stories.tsx
26
+ *
27
+ * ## Why a registry and not a component
28
+ *
29
+ * Every modal sheet keeps its own native `<dialog>` and its own open state. A
30
+ * sheet opened while another sheet is open is a stacked sheet: the browser's
31
+ * top layer already paints the later `showModal()` above the earlier one, and
32
+ * the later modal dialog already blocks the earlier one. What the browser does
33
+ * NOT know is that the two dialogs are sheets of one stack, so this registry
34
+ * supplies the rest: which sheet is on top, how far back each covered sheet
35
+ * recedes, whose `::backdrop` is the one visible scrim, and when the native
36
+ * order would come out wrong (several sheets opening in one commit) it puts
37
+ * the top layer right before the frame paints. Nothing here is a public
38
+ * surface; the hosts call it from their commit-phase effects only.
39
+ *
40
+ * ## Order is open order, ties are tree order
41
+ *
42
+ * Each open cycle of a sheet gets a rank: the batch it opened in, then a
43
+ * running sequence. A batch is one React commit: registrations that arrive
44
+ * between two seals belong to the same commit, because the hosts seal in
45
+ * passive effects and React runs every pending passive effect before the next
46
+ * commit's layout effects (and flushes them synchronously after a sync
47
+ * commit). Later batch is higher. Within one batch there is no open order, so
48
+ * document order of the dialog elements decides: a sheet before the sheets
49
+ * rendered in its content, siblings in the order they are written. That is the
50
+ * order the first painted frame of a deep link must show, and effect order
51
+ * (child first) gets it backwards; the rank is read at compare time, after
52
+ * every registration of the commit has arrived, so it does not.
53
+ *
54
+ * ## The top layer is reconciled, not trusted
55
+ *
56
+ * The registry remembers the order it called `showModal()` in. After every
57
+ * change it computes the order the ranks want; where the two diverge it closes
58
+ * the dialogs from the first divergence up and shows them again in rank order.
59
+ * That happens inside the commit, before paint, so a deep link whose inner
60
+ * sheet registered first is repaired without a frame in between. A sheet that
61
+ * closes and reopens gets a new rank and is re-shown on top the same way;
62
+ * only the dialogs that have to move up are re-shown, the rest keep their
63
+ * place, their backdrop and any motion in flight.
64
+ *
65
+ * ## A replace is a move the person makes from one sheet to the next
66
+ *
67
+ * One sheet closing and another opening in the same commit, where the closing
68
+ * sheet was the top open sheet of its stack (no other open sheet above it,
69
+ * the opening sheet aside) and the interaction came from inside it (the
70
+ * control last pressed — or, with no fresh press, the focused element — was
71
+ * in its dialog), is a replace: the person is moving from one step to the
72
+ * next, not stacking one on the other. The registry then runs the handoff a BottomSheetSwitcher runs
73
+ * between its steps, on the two standalone dialogs: the entering sheet rises
74
+ * above the retained one; a taller retained sheet moves down to meet it; the
75
+ * retained sheet fades only after both motions complete, then its dialog
76
+ * closes and the entering sheet takes over the scrim in the same frame. The
77
+ * retained sheet is inert at once, keeps no place in the dismissal order, and
78
+ * lends its opener to the sheet replacing it, so closing the flow later
79
+ * returns focus to where the flow began. A covered sheet closing (not the
80
+ * top), a sheet closing in a different update from the open, or a close and
81
+ * an open driven from a control outside the closing sheet (two owners acting
82
+ * in one update) is never a replace, so a push over a stack and a pop out of
83
+ * one keep their motion and their own openers. Non-modal sheets
84
+ * (`hasScrim={false}`) replace each other too: they are hosted as manual
85
+ * popovers, so the top layer orders them, but they are a group of their own
86
+ * that never stacks, recedes, or owns a scrim.
87
+ *
88
+ * ## One state per page, per document
89
+ *
90
+ * The state lives on `globalThis` so that two copies of this module on one
91
+ * page that speak the same stack protocol version share one stack (see
92
+ * StackState); everything the stack reads and writes across commits — the
93
+ * entries, each document's shown order, which documents have the press
94
+ * listeners, the deferred non-modal sheets and their watchers, the element to
95
+ * keep focused across a re-show — is in that shared state and none of it is
96
+ * per copy. The one module-level value is the engine probe's answer, a fact
97
+ * about the browser that every copy measures alike. A copy on another
98
+ * protocol version keeps a stack of its own. Within a state, each document is
99
+ * its own stack: a sheet portaled into another document has that document's
100
+ * top layer, focus and order.
101
+ */
102
+
103
+ import {notifyTopLayerEntry} from '../Layer/modalOutlet';
104
+ import {focusForLastInput} from '../utils/focusReturn';
105
+
106
+ export interface BottomSheetStackView {
107
+ /** Another modal sheet is presented alongside this one. */
108
+ readonly isStacked: boolean;
109
+ /** This sheet is the open sheet that is on top. */
110
+ readonly isTop: boolean;
111
+ /** This sheet is open with at least one open sheet above it. */
112
+ readonly isCovered: boolean;
113
+ /** Open sheets above this one; drives how far the sheet recedes. */
114
+ readonly depth: number;
115
+ /** This sheet's `::backdrop` is the one visible scrim of the stack. */
116
+ readonly ownsScrim: boolean;
117
+ /**
118
+ * This sheet took the scrim over from a sheet below it that is still
119
+ * sliding out, so its backdrop must appear at once rather than fade in.
120
+ */
121
+ readonly isScrimHandoff: boolean;
122
+ /**
123
+ * This sheet is covered and contains no presented sheet, so its whole
124
+ * dialog can be marked inert and hidden from assistive technology.
125
+ */
126
+ readonly isBlocked: boolean;
127
+ /**
128
+ * This sheet is closing and an open sheet above it owns the scrim now, so
129
+ * its own backdrop must leave at once rather than fade: the dim is the
130
+ * other sheet's from this frame on, and two backdrops would double it.
131
+ */
132
+ readonly isScrimTakenOver: boolean;
133
+ /**
134
+ * This closed sheet is being replaced by the sheet opened in the same
135
+ * update: it stays in place (`covered`), moves down to the entering sheet's
136
+ * top edge (`aligning`), or fades (`fading`), instead of sliding out.
137
+ */
138
+ readonly replacedMotion: BottomSheetReplacedMotion | null;
139
+ /** How far down a replaced sheet moves to meet the entering sheet, in px. */
140
+ readonly alignmentOffset: number;
141
+ /** This open sheet is replacing the sheet that closed in the same update. */
142
+ readonly isReplacing: boolean;
143
+ }
144
+
145
+ export type BottomSheetReplacedMotion = 'covered' | 'aligning' | 'fading';
146
+
147
+ /** The motions a host's panel reports to the registry during a replace. */
148
+ export type BottomSheetReplaceMotion =
149
+ 'entering' | 'aligning' | 'fading' | 'exiting';
150
+
151
+ export const BOTTOM_SHEET_STACK_DEFAULT_VIEW: BottomSheetStackView = {
152
+ isStacked: false,
153
+ isTop: false,
154
+ isCovered: false,
155
+ depth: 0,
156
+ ownsScrim: false,
157
+ isScrimHandoff: false,
158
+ isBlocked: false,
159
+ isScrimTakenOver: false,
160
+ replacedMotion: null,
161
+ alignmentOffset: 0,
162
+ isReplacing: false,
163
+ };
164
+
165
+ /**
166
+ * Why the registry moves focus into a sheet: it was shown on top (`open`), a
167
+ * close above it revealed it (`reveal`), or it is replacing the sheet the
168
+ * person was in (`replace`: focus follows the person from one step to the
169
+ * next, whatever the native host did with it).
170
+ */
171
+ export type BottomSheetFocusReason = 'open' | 'reveal' | 'replace';
172
+
173
+ /** The sheets of one document's modal stack that close in the same update. */
174
+ interface ClosingGroup {
175
+ /** Bottom to top. */
176
+ members: Entry[];
177
+ /** Members whose dialogs have not left the top layer yet. */
178
+ pending: Set<Entry>;
179
+ /** The bottom-most member's return target, read when the group is sealed. */
180
+ returnTarget: HTMLElement | null;
181
+ /** Focus has been returned for this group. */
182
+ reported?: boolean;
183
+ }
184
+
185
+ export interface BottomSheetStackRegistration {
186
+ /** Stable identity of the host component instance. */
187
+ key: object;
188
+ /** The host's native dialog. */
189
+ getElement: () => HTMLDialogElement | null;
190
+ /**
191
+ * The element whose place in the tree orders this level against the other
192
+ * sheets of its commit, when it is not the dialog itself: a switcher flow
193
+ * is realized by whichever step dialog is active, so its flow wrapper — the
194
+ * one element that contains every step — stands for it, and a handoff
195
+ * cannot reorder the flow against a sheet opened in the same commit.
196
+ */
197
+ getTreeAnchor?: () => Element | null;
198
+ /** Present the dialog modally (`showModal()`), capturing the opener first. */
199
+ show: () => void;
200
+ /** Take the dialog out of the top layer (`close()`) for a re-show. */
201
+ hide: () => void;
202
+ /** Move focus into the sheet: shown on top, or revealed by a close above. */
203
+ focus: (reason: BottomSheetFocusReason) => void;
204
+ /**
205
+ * Where focus returns when this sheet closes the stack: its explicit
206
+ * final-focus target, else the element that opened it. Read by the
207
+ * registry when several sheets close in one update.
208
+ */
209
+ getReturnTarget?: () => HTMLElement | null;
210
+ /** Receive this host's view whenever it changes. */
211
+ onView: (view: BottomSheetStackView) => void;
212
+ /**
213
+ * What a host must supply to take part in a replace. A host without it (a
214
+ * switcher flow, which replaces its own steps) is never paired.
215
+ */
216
+ replaceable?: BottomSheetReplaceable;
217
+ }
218
+
219
+ export interface BottomSheetReplaceable {
220
+ /** The host's visual panel, measured for the replace alignment. */
221
+ getPanel: () => HTMLElement | null;
222
+ /** The element focus returns to when the sheet closes the flow. */
223
+ getOpener: () => HTMLElement | null;
224
+ /** Adopt the replaced sheet's opener, so the flow closes back to it. */
225
+ setOpener: (opener: HTMLElement | null) => void;
226
+ /** The replace is over: this replaced sheet is hidden and its dialog closed. */
227
+ finish: () => void;
228
+ }
229
+
230
+ interface Rank {
231
+ batch: number;
232
+ seq: number;
233
+ }
234
+
235
+ interface ReplaceState {
236
+ /** The sheet that opened in the same update and now stands in for this one. */
237
+ replacer: Entry;
238
+ motion: BottomSheetReplacedMotion;
239
+ alignmentOffset: number;
240
+ isAlignmentComplete: boolean;
241
+ isEnteringComplete: boolean;
242
+ }
243
+
244
+ interface Entry extends BottomSheetStackRegistration {
245
+ rank: Rank;
246
+ isOpen: boolean;
247
+ /** The document whose top layer this sheet's dialog is in. */
248
+ doc: Document;
249
+ /**
250
+ * Modal sheets stack with each other; non-modal sheets (`hasScrim={false}`)
251
+ * form their own group per document: they never stack, recede or own a
252
+ * scrim, but they replace each other and keep their top-layer order.
253
+ */
254
+ isModal: boolean;
255
+ view: BottomSheetStackView;
256
+ /** Set on a closed sheet while another sheet replaces it. */
257
+ replace: ReplaceState | null;
258
+ /** Set on an open sheet while it replaces the sheet that closed with it. */
259
+ replacing: Entry | null;
260
+ /**
261
+ * Reopened while it was being replaced: its panel is already in place, so
262
+ * when it replaces in turn its entrance is complete the moment it starts.
263
+ */
264
+ isEnteringInPlace: boolean;
265
+ }
266
+
267
+ const ALIGNMENT_THRESHOLD_PX = 1;
268
+
269
+ /**
270
+ * The registry's state. One per JavaScript realm, shared by every copy of this
271
+ * module in it that speaks the same stack protocol version: two copies of
272
+ * the package on one page (two bundles, a dev server serving the same file
273
+ * under two URLs, a micro-frontend) must see one stack, or each would show
274
+ * its own sheets over the other's with two scrims and no order. The state
275
+ * lives on `globalThis` under a symbol that names the protocol version
276
+ * (STACK_PROTOCOL_VERSION), so a copy on another version finds no state of
277
+ * its own and keeps a stack of its own; the shape it carries is the guard
278
+ * against a key collision.
279
+ */
280
+ interface StackState {
281
+ shape: number;
282
+ entries: Entry[];
283
+ // The order the presented entries were shown in, per group (one document's
284
+ // modal sheets, one document's non-modal sheets): each document has its
285
+ // own top layer, and the two groups never reorder each other.
286
+ shownOrder: WeakMap<Document, {modal: Entry[]; nonModal: Entry[]}>;
287
+ // Documents that have the press listeners, each with the function that
288
+ // removes them: one set per document, installed with the document's first
289
+ // registered sheet and removed when its last one leaves (the listeners
290
+ // feed this shared state, so a second copy must not add another set).
291
+ listenedDocuments: WeakMap<Document, () => void>;
292
+ // The open/close flips of the current batch (one commit); a replace pairs
293
+ // one of each. Cleared with the seal.
294
+ batchOpened: Entry[];
295
+ batchClosed: Entry[];
296
+ // The control the person acted from, for the batch's first flip: the
297
+ // target of the last pointer or key press in the document (recorded in the
298
+ // capture phase, so it is known whether or not the press moved focus — a
299
+ // non-modal sheet takes no focus, and some browsers do not focus a clicked
300
+ // button), else where focus was, read before any dialog of this commit is
301
+ // shown. A replace is recognised by it.
302
+ batchActor: Element | null;
303
+ // The target is held weakly: a press on an element that has since been
304
+ // removed and dropped must not keep it alive until the next press.
305
+ lastPress: WeakMap<Document, {target: WeakRef<Element>; at: number}>;
306
+ // Retained sheets whose replacer closed in this batch; dropped once the
307
+ // batch's pairing is known, unless the batch reopened them.
308
+ pendingDrops: Entry[];
309
+ // A replacer that still owes the move of focus into itself (done once its
310
+ // dialog is shown).
311
+ pendingReplaceFocus: Entry | null;
312
+ // The pair this batch made, and the opener the replacer had before it
313
+ // adopted the replaced sheet's: a later flip of the same commit (a third
314
+ // sheet closing or opening) makes the tally no longer one close and one
315
+ // open, and the pair is undone — the commit is then several sheets
316
+ // changing, which keep their own push and pop motion.
317
+ batchPair: {
318
+ replaced: Entry;
319
+ replacer: Entry;
320
+ replacerOpener: HTMLElement | null;
321
+ } | null;
322
+ // Modal sheets closing together in one update ("Close all"): focus returns
323
+ // once, from the bottom-most of them, after the last of them has left the
324
+ // top layer. Sealed from `batchClosed` when the batch ends.
325
+ closingTogether: Map<Entry, ClosingGroup>;
326
+ // Rank persists across a StrictMode replay (unregister and register in one
327
+ // synchronous pass) so the replay cannot promote a sheet. A rank marked
328
+ // closed is spent: the next open takes a new one.
329
+ rankByKey: WeakMap<
330
+ object,
331
+ Rank & {isClosed: boolean; detachedBatch: number | null}
332
+ >;
333
+ currentBatch: number;
334
+ nextSeq: number;
335
+ isBatchDirty: boolean;
336
+ isSealScheduled: boolean;
337
+ // The element a step present blurred while the person was in a sheet above
338
+ // the flow; the next top-layer reconcile lands focus on it again. Per
339
+ // document, within one commit.
340
+ focusToKeep: WeakMap<Document, HTMLElement>;
341
+ // Non-modal sheets presented by `show()` because a modal outside them was
342
+ // open, waiting to enter the top layer, with the watchers that look again
343
+ // (see deferTopLayerEntry).
344
+ deferredTopLayer: WeakMap<Document, DeferredTopLayer>;
345
+ }
346
+
347
+ interface DeferredTopLayer {
348
+ deferred: Map<HTMLDialogElement, HTMLElement | null>;
349
+ blockers: WeakSet<HTMLDialogElement>;
350
+ removals: MutationObserver | null;
351
+ /** Removes the document `close` listener; set while anything waits. */
352
+ stopListeningForClose: (() => void) | null;
353
+ }
354
+
355
+ /**
356
+ * The stack protocol version: the shape and meaning of Entry, the
357
+ * registration, the batch/seal protocol and the shared listeners. Copies of
358
+ * the package on one page share one stack per document when they speak the
359
+ * same protocol (`component:BottomSheet` PR1); the version is part of the
360
+ * document-global key, so a copy on another protocol finds no state of its
361
+ * own version and keeps a stack of its own — two independent stacks, each
362
+ * ordering only the sheets its copy renders, never a shared state read with
363
+ * the wrong shape. Bump it whenever any of those change.
364
+ */
365
+ const STACK_PROTOCOL_VERSION = 8;
366
+ const STACK_STATE_KEY = Symbol.for(
367
+ `astryx.bottomSheetStack.v${STACK_PROTOCOL_VERSION}`,
368
+ );
369
+ const STACK_STATE_SHAPE = STACK_PROTOCOL_VERSION;
370
+
371
+ function createStackState(): StackState {
372
+ return {
373
+ shape: STACK_STATE_SHAPE,
374
+ entries: [],
375
+ shownOrder: new WeakMap(),
376
+ listenedDocuments: new WeakMap(),
377
+ batchOpened: [],
378
+ batchClosed: [],
379
+ batchActor: null,
380
+ batchPair: null,
381
+ lastPress: new WeakMap(),
382
+ pendingDrops: [],
383
+ pendingReplaceFocus: null,
384
+ closingTogether: new Map(),
385
+ rankByKey: new WeakMap(),
386
+ currentBatch: 0,
387
+ nextSeq: 0,
388
+ isBatchDirty: false,
389
+ isSealScheduled: false,
390
+ focusToKeep: new WeakMap(),
391
+ deferredTopLayer: new WeakMap(),
392
+ };
393
+ }
394
+
395
+ function acquireStackState(): StackState {
396
+ const holder = globalThis as {[STACK_STATE_KEY]?: StackState};
397
+ const shared = holder[STACK_STATE_KEY];
398
+ if (shared != null) {
399
+ // The key names the version, so a state found under it is this
400
+ // protocol's; the shape check is the guard against a key collision.
401
+ return shared.shape === STACK_STATE_SHAPE ? shared : createStackState();
402
+ }
403
+ const created = createStackState();
404
+ holder[STACK_STATE_KEY] = created;
405
+ return created;
406
+ }
407
+
408
+ const state = acquireStackState();
409
+
410
+ function takeRank(): Rank {
411
+ state.isBatchDirty = true;
412
+ scheduleSeal();
413
+ return {batch: state.currentBatch, seq: state.nextSeq++};
414
+ }
415
+
416
+ function scheduleSeal(): void {
417
+ // Backstop for a commit whose hosts run no passive effect afterwards (a
418
+ // subtree React just hid). A later task is always a later batch.
419
+ if (state.isSealScheduled || typeof queueMicrotask !== 'function') {
420
+ return;
421
+ }
422
+ state.isSealScheduled = true;
423
+ queueMicrotask(() => {
424
+ state.isSealScheduled = false;
425
+ sealBottomSheetBatch();
426
+ });
427
+ }
428
+
429
+ /**
430
+ * End the current batch. Hosts call it from a passive effect, which React runs
431
+ * after every layout effect of the same commit and before the next commit;
432
+ * registrations on either side of it are therefore different open orders.
433
+ */
434
+ export function sealBottomSheetBatch(): void {
435
+ flushPendingDrops();
436
+ sealClosingGroups();
437
+ if (state.isBatchDirty) {
438
+ state.currentBatch += 1;
439
+ state.isBatchDirty = false;
440
+ }
441
+ state.batchOpened = [];
442
+ state.batchClosed = [];
443
+ state.batchActor = null;
444
+ state.batchPair = null;
445
+ }
446
+
447
+ /**
448
+ * Two or more modal sheets of one stack closing in the same update with no
449
+ * sheet of that stack left open and nothing opening: "Close all". Each one
450
+ * would return focus on its own, at depth 0, to an opener that is either
451
+ * inside a dialog that is closing with it or on a page that is still inert
452
+ * behind the other modals — so none of them can. The group returns focus
453
+ * once instead, from its bottom-most sheet, after the last of its dialogs
454
+ * has left the top layer. A single sheet closing, a non-modal sheet, and a
455
+ * batch that also opens a sheet are not groups: their own close handles
456
+ * focus (the replace and the pop have their own rules).
457
+ */
458
+ function sealClosingGroups(): void {
459
+ if (state.batchOpened.length > 0) {
460
+ return;
461
+ }
462
+ const closingModal = state.batchClosed.filter(
463
+ entry => entry.isModal && entry.replace == null && entry.replacing == null,
464
+ );
465
+ if (closingModal.length < 2) {
466
+ return;
467
+ }
468
+ const byDoc = new Map<Document, Entry[]>();
469
+ for (const entry of closingModal) {
470
+ const list = byDoc.get(entry.doc) ?? [];
471
+ list.push(entry);
472
+ byDoc.set(entry.doc, list);
473
+ }
474
+ for (const [doc, closing] of byDoc) {
475
+ if (closing.length < 2) {
476
+ continue;
477
+ }
478
+ const stack = sortedEntries(doc, true);
479
+ if (stack.some(entry => entry.isOpen)) {
480
+ // Sheets remain open beneath: the pops return into the revealed sheet
481
+ // through the ordinary close path.
482
+ continue;
483
+ }
484
+ const members = stack.filter(entry => closing.includes(entry));
485
+ const bottom = members[0];
486
+ const group: ClosingGroup = {
487
+ members,
488
+ pending: new Set(members),
489
+ returnTarget: bottom.getReturnTarget?.() ?? null,
490
+ };
491
+ for (const entry of members) {
492
+ state.closingTogether.set(entry, group);
493
+ }
494
+ }
495
+ }
496
+
497
+ /**
498
+ * Whether `key` closes as part of a "Close all" group. Its host then leaves
499
+ * the top layer without returning focus itself; the registry returns it
500
+ * once the whole group has left.
501
+ */
502
+ export function isClosingTogether(key: object): boolean {
503
+ const entry = state.entries.find(candidate => candidate.key === key);
504
+ return entry != null && state.closingTogether.has(entry);
505
+ }
506
+
507
+ function completeClosingGroup(group: ClosingGroup): void {
508
+ if (group.pending.size > 0 || group.reported) {
509
+ return;
510
+ }
511
+ group.reported = true;
512
+ const target = group.returnTarget;
513
+ if (target != null && target.isConnected) {
514
+ focusForLastInput(target);
515
+ }
516
+ }
517
+
518
+ /**
519
+ * A member of a "Close all" group has left the top layer. When it is the
520
+ * last one, focus returns to the group's target: the bottom-most sheet's
521
+ * final-focus target or opener, now that no modal dialog stands in the way.
522
+ */
523
+ export function reportClosedTogether(key: object): void {
524
+ const entry = state.entries.find(candidate => candidate.key === key);
525
+ const group = entry == null ? undefined : state.closingTogether.get(entry);
526
+ if (entry == null || group == null) {
527
+ return;
528
+ }
529
+ leaveClosingGroup(entry, group);
530
+ }
531
+
532
+ function leaveClosingGroup(entry: Entry, group: ClosingGroup): void {
533
+ state.closingTogether.delete(entry);
534
+ group.pending.delete(entry);
535
+ completeClosingGroup(group);
536
+ }
537
+
538
+ /**
539
+ * Remember the last press in a document: a pointer down, a click (pointer,
540
+ * touch, keyboard activation or code: it is what runs the handler that flips
541
+ * the sheets) or a key down. One capture-phase listener per event per
542
+ * document, installed with the first sheet registered in it; the target is
543
+ * kept weakly.
544
+ */
545
+ function listenForPresses(doc: Document): void {
546
+ if (state.listenedDocuments.has(doc)) {
547
+ return;
548
+ }
549
+ const record = (event: Event) => {
550
+ if (event.target instanceof Element) {
551
+ state.lastPress.set(doc, {
552
+ target: new WeakRef(event.target),
553
+ at: Date.now(),
554
+ });
555
+ }
556
+ };
557
+ doc.addEventListener('pointerdown', record, true);
558
+ doc.addEventListener('click', record, true);
559
+ doc.addEventListener('keydown', record, true);
560
+ state.listenedDocuments.set(doc, () => {
561
+ doc.removeEventListener('pointerdown', record, true);
562
+ doc.removeEventListener('click', record, true);
563
+ doc.removeEventListener('keydown', record, true);
564
+ state.lastPress.delete(doc);
565
+ });
566
+ }
567
+
568
+ /**
569
+ * The document's last registered sheet left: nothing feeds the press record
570
+ * any more, so the listeners go (`architecture:react-component-runtime`
571
+ * INV5: a subscription lives as long as what reads it). The next sheet to
572
+ * register in the document installs them again.
573
+ */
574
+ function stopListeningForPresses(doc: Document): void {
575
+ if (state.entries.some(entry => entry.doc === doc)) {
576
+ return;
577
+ }
578
+ const remove = state.listenedDocuments.get(doc);
579
+ if (remove != null) {
580
+ state.listenedDocuments.delete(doc);
581
+ remove();
582
+ }
583
+ }
584
+
585
+ /**
586
+ * A press is the actor of a flip only while it is fresh: the handler a press
587
+ * runs flips the sheets within the same task, milliseconds later. A flip
588
+ * that arrives later (a step change after a save resolves) is not that
589
+ * press's doing, and reads focus instead. A press is also spent once the
590
+ * sheet it landed in has been replaced or has closed — its target sits in
591
+ * an inert or no longer presented dialog — or once a replace has consumed
592
+ * it: a step advanced by code shortly after a Submit press (a "Processing"
593
+ * interstitial) is then judged by where focus is, inside the step, and
594
+ * hands off as DEP-0015 promises.
595
+ */
596
+ const PRESS_ACTOR_WINDOW_MS = 1000;
597
+
598
+ function actorFor(doc: Document, flipping: Entry): Element | null {
599
+ const press = state.lastPress.get(doc);
600
+ const target = press?.target.deref();
601
+ if (
602
+ press != null &&
603
+ target != null &&
604
+ target.isConnected &&
605
+ Date.now() - press.at <= PRESS_ACTOR_WINDOW_MS &&
606
+ !isPressSpent(target, flipping)
607
+ ) {
608
+ return target;
609
+ }
610
+ return doc.activeElement;
611
+ }
612
+
613
+ /**
614
+ * A press is spent when the sheet it landed in was already closed or
615
+ * replaced before this flip — not the sheet this very flip is closing, which
616
+ * is the ordinary replace made from inside it.
617
+ */
618
+ function isPressSpent(target: Element, flipping: Entry): boolean {
619
+ const owning = state.entries.find(entry => {
620
+ const element = entry.getElement();
621
+ return (
622
+ entry.doc === flipping.doc && element != null && element.contains(target)
623
+ );
624
+ });
625
+ if (owning == null || owning === flipping) {
626
+ return false;
627
+ }
628
+ return !owning.isOpen || owning.replace != null;
629
+ }
630
+
631
+ /** Record a flip of the current batch, and who acted if it is the first. */
632
+ function recordFlip(entry: Entry, flip: 'opened' | 'closed'): void {
633
+ if (state.batchOpened.length === 0 && state.batchClosed.length === 0) {
634
+ state.batchActor = actorFor(entry.doc, entry);
635
+ }
636
+ (flip === 'opened' ? state.batchOpened : state.batchClosed).push(entry);
637
+ }
638
+
639
+ function compareRank(a: Entry, b: Entry): number {
640
+ if (a.rank.batch !== b.rank.batch) {
641
+ return a.rank.batch - b.rank.batch;
642
+ }
643
+ // One commit: tree order. A dialog that precedes another in document order
644
+ // (including one that contains the other) is below it.
645
+ const aEl = a.getTreeAnchor?.() ?? a.getElement();
646
+ const bEl = b.getTreeAnchor?.() ?? b.getElement();
647
+ if (aEl != null && bEl != null && aEl !== bEl) {
648
+ const position = aEl.compareDocumentPosition(bEl);
649
+ if (position & Node.DOCUMENT_POSITION_FOLLOWING) {
650
+ return -1;
651
+ }
652
+ if (position & Node.DOCUMENT_POSITION_PRECEDING) {
653
+ return 1;
654
+ }
655
+ }
656
+ return a.rank.seq - b.rank.seq;
657
+ }
658
+
659
+ /** The sheets of one group (document + modality), bottom to top. */
660
+ function sortedEntries(doc: Document, isModal: boolean): Entry[] {
661
+ return state.entries
662
+ .filter(entry => entry.doc === doc && entry.isModal === isModal)
663
+ .sort(compareRank);
664
+ }
665
+
666
+ /** The sheets `entry` shares a group with, bottom to top. */
667
+ function groupOf(entry: Entry): Entry[] {
668
+ return sortedEntries(entry.doc, entry.isModal);
669
+ }
670
+
671
+ /** The shown order of one group, read from or written to the shared state. */
672
+ function getShownOrder(doc: Document, isModal: boolean): Entry[] {
673
+ const orders = state.shownOrder.get(doc);
674
+ if (orders == null) {
675
+ return [];
676
+ }
677
+ return isModal ? orders.modal : orders.nonModal;
678
+ }
679
+ function setShownOrder(doc: Document, isModal: boolean, order: Entry[]): void {
680
+ const orders = state.shownOrder.get(doc) ?? {modal: [], nonModal: []};
681
+ if (isModal) {
682
+ orders.modal = order;
683
+ } else {
684
+ orders.nonModal = order;
685
+ }
686
+ state.shownOrder.set(doc, orders);
687
+ }
688
+
689
+ function isSameView(a: BottomSheetStackView, b: BottomSheetStackView): boolean {
690
+ return (
691
+ a.isStacked === b.isStacked &&
692
+ a.isTop === b.isTop &&
693
+ a.isCovered === b.isCovered &&
694
+ a.depth === b.depth &&
695
+ a.ownsScrim === b.ownsScrim &&
696
+ a.isScrimHandoff === b.isScrimHandoff &&
697
+ a.isBlocked === b.isBlocked &&
698
+ a.isScrimTakenOver === b.isScrimTakenOver &&
699
+ a.replacedMotion === b.replacedMotion &&
700
+ a.alignmentOffset === b.alignmentOffset &&
701
+ a.isReplacing === b.isReplacing
702
+ );
703
+ }
704
+
705
+ function computeViews(order: Entry[], isModal: boolean): void {
706
+ const changed: Entry[] = [];
707
+ if (!isModal) {
708
+ // Non-modal sheets never stack: no recede, no scrim, no top-layer order
709
+ // against modal sheets. Their view carries only the replace a pair of
710
+ // them may be running.
711
+ for (const entry of order) {
712
+ const view: BottomSheetStackView = {
713
+ ...BOTTOM_SHEET_STACK_DEFAULT_VIEW,
714
+ replacedMotion: entry.replace?.motion ?? null,
715
+ alignmentOffset: entry.replace?.alignmentOffset ?? 0,
716
+ isReplacing: entry.replacing != null,
717
+ };
718
+ if (!isSameView(entry.view, view)) {
719
+ entry.view = view;
720
+ changed.push(entry);
721
+ }
722
+ }
723
+ for (const entry of changed) {
724
+ entry.onView(entry.view);
725
+ }
726
+ return;
727
+ }
728
+ const openEntries = order.filter(entry => entry.isOpen);
729
+ const top = openEntries[openEntries.length - 1] ?? null;
730
+ // A replaced sheet keeps the scrim while it is retained; the sheet replacing
731
+ // it takes the scrim over, instantly, when the replaced sheet leaves.
732
+ const owner =
733
+ order.find(entry => entry.isOpen || entry.replace != null) ?? null;
734
+ order.forEach((entry, index) => {
735
+ let depth = 0;
736
+ for (let above = index + 1; above < order.length; above += 1) {
737
+ // The sheet replacing this one stands in its place, not above it.
738
+ if (order[above].isOpen && order[above] !== entry.replace?.replacer) {
739
+ depth += 1;
740
+ }
741
+ }
742
+ const isCovered = entry.isOpen && depth > 0;
743
+ const element = entry.getElement();
744
+ const containsPresented =
745
+ element != null &&
746
+ order.some(other => {
747
+ const otherElement = other.getElement();
748
+ return (
749
+ other !== entry &&
750
+ otherElement != null &&
751
+ element.contains(otherElement)
752
+ );
753
+ });
754
+ const ownsScrim = entry === owner;
755
+ const isScrimHandoff =
756
+ ownsScrim &&
757
+ entry.isOpen &&
758
+ order.slice(0, index).some(below => !below.isOpen);
759
+ const view: BottomSheetStackView = {
760
+ isStacked: order.length > 1,
761
+ isTop: entry === top,
762
+ isCovered,
763
+ depth,
764
+ ownsScrim,
765
+ isScrimHandoff,
766
+ isBlocked: isCovered && !containsPresented,
767
+ isScrimTakenOver: !entry.isOpen && owner != null && owner !== entry,
768
+ replacedMotion: entry.replace?.motion ?? null,
769
+ alignmentOffset: entry.replace?.alignmentOffset ?? 0,
770
+ isReplacing: entry.replacing != null,
771
+ };
772
+ if (!isSameView(entry.view, view)) {
773
+ entry.view = view;
774
+ changed.push(entry);
775
+ }
776
+ });
777
+ for (const entry of changed) {
778
+ entry.onView(entry.view);
779
+ }
780
+ }
781
+
782
+ /**
783
+ * Present a switcher step's dialog modally with no focus to return to.
784
+ * showModal() records the element focused at that moment and close() moves
785
+ * focus back to it, in Chromium and WebKit even when focus is in another
786
+ * dialog by then. For a step that element is the control that advanced the
787
+ * flow (Continue, Back) or the flow's opener, and the dialog closes a fade
788
+ * later, while the user is in the next step: the return would pull focus
789
+ * off the active panel with no user action. Blurring first leaves nothing
790
+ * recorded, so the close moves nothing; the entering step then focuses its
791
+ * own panel, and the switcher returns focus to the opener itself when the
792
+ * flow ends. The blur happens in the same task as the present, so no frame
793
+ * paints without focus.
794
+ */
795
+ export function presentStepModally(dialog: HTMLDialogElement): void {
796
+ const doc = dialog.ownerDocument;
797
+ const focused = doc.activeElement;
798
+ if (focused instanceof HTMLElement && focused !== doc.body) {
799
+ // Focus in another open dialog that does not contain this step — a sheet
800
+ // stacked over the flow, with the person typing in it while code moves
801
+ // the flow on — is theirs to keep: the registry puts that sheet back on
802
+ // top right after this and lands focus on this element again.
803
+ const focusedDialog = focused.closest('dialog');
804
+ if (
805
+ focusedDialog != null &&
806
+ focusedDialog !== dialog &&
807
+ !focusedDialog.contains(dialog) &&
808
+ !dialog.contains(focusedDialog) &&
809
+ isSheetHostPresented(focusedDialog)
810
+ ) {
811
+ state.focusToKeep.set(doc, focused);
812
+ }
813
+ focused.blur();
814
+ }
815
+ dialog.showModal();
816
+ }
817
+
818
+ /**
819
+ * Present a switcher dialog whose backdrop must start, and stay, clear: the
820
+ * opacity is set with the scrim transition pinned to 0s, the dialog is
821
+ * presented, and the pin is lifted only after a style flush has applied the
822
+ * clear backdrop, so no frame eases from a previous backdrop value.
823
+ */
824
+ export function presentWithClearScrim(dialog: HTMLDialogElement): void {
825
+ dialog.style.setProperty('--_sheet-scrim-duration', '0s');
826
+ dialog.style.setProperty('--_sheet-scrim-opacity', '0');
827
+ presentStepModally(dialog);
828
+ if (typeof getComputedStyle === 'function') {
829
+ void getComputedStyle(dialog, '::backdrop').opacity;
830
+ }
831
+ dialog.style.removeProperty('--_sheet-scrim-duration');
832
+ }
833
+
834
+ /** The pending restore of a dialog's scrim transition; one per host. */
835
+ export interface BottomSheetScrimWrite {
836
+ frame: number | null;
837
+ }
838
+
839
+ /**
840
+ * Write a dialog's scrim opacity. A change while the dialog is up is a change
841
+ * of scrim owner, and lands with no transition at all: a `0.01s` duration
842
+ * still paints one frame at the old value, which reads as a dip or, with the
843
+ * old owner's backdrop still fading, as a doubled dim. The pin
844
+ * (`--_sheet-scrim-duration: 0s`, inline) stays for two animation frames
845
+ * (two nested `requestAnimationFrame`s: the first frame paints the new value,
846
+ * the second confirms it is on screen before the stylesheet's duration
847
+ * returns). Hosts cancel the pending restore with `cancelScrimWrite` when
848
+ * they unmount.
849
+ */
850
+ export function writeScrimOpacity(
851
+ dialog: HTMLDialogElement | null,
852
+ opacity: '0' | '1',
853
+ pending: BottomSheetScrimWrite,
854
+ ): void {
855
+ if (dialog == null) {
856
+ return;
857
+ }
858
+ if (
859
+ !dialog.open ||
860
+ dialog.style.getPropertyValue('--_sheet-scrim-opacity') === opacity
861
+ ) {
862
+ dialog.style.setProperty('--_sheet-scrim-opacity', opacity);
863
+ return;
864
+ }
865
+ dialog.style.setProperty('--_sheet-scrim-duration', '0s');
866
+ dialog.style.setProperty('--_sheet-scrim-opacity', opacity);
867
+ cancelScrimWrite(pending);
868
+ pending.frame = requestAnimationFrame(() => {
869
+ pending.frame = requestAnimationFrame(() => {
870
+ pending.frame = null;
871
+ dialog.style.removeProperty('--_sheet-scrim-duration');
872
+ });
873
+ });
874
+ }
875
+
876
+ export function cancelScrimWrite(pending: BottomSheetScrimWrite): void {
877
+ if (pending.frame != null) {
878
+ cancelAnimationFrame(pending.frame);
879
+ pending.frame = null;
880
+ }
881
+ }
882
+
883
+ /**
884
+ * Whether a sheet's dialog is presented by the browser: as a modal dialog
885
+ * (`open`), as a manual popover (a non-modal sheet in the top layer), or by
886
+ * `show()` (a non-modal sheet below the Popover API support floor).
887
+ */
888
+ export function isSheetHostPresented(
889
+ dialog: HTMLDialogElement | null,
890
+ ): boolean {
891
+ if (dialog == null) {
892
+ return false;
893
+ }
894
+ if (dialog.open) {
895
+ return true;
896
+ }
897
+ try {
898
+ return dialog.matches(':popover-open');
899
+ } catch {
900
+ // jsdom and pre-Popover browsers do not recognise :popover-open.
901
+ return false;
902
+ }
903
+ }
904
+
905
+ /**
906
+ * Whether a modal dialog that does not contain `element` is open in its
907
+ * document. Such a modal makes everything outside it inert, so a non-modal
908
+ * sheet outside it must not paint above it.
909
+ */
910
+ export function hasOpenModalOutside(element: Element): boolean {
911
+ return openModalsOutside(element).length > 0;
912
+ }
913
+
914
+ /** The open modal dialogs that do not contain `element`; see above. */
915
+ function openModalsOutside(element: Element): HTMLDialogElement[] {
916
+ const blockers: HTMLDialogElement[] = [];
917
+ for (const dialog of Array.from(
918
+ element.ownerDocument.querySelectorAll<HTMLDialogElement>('dialog[open]'),
919
+ )) {
920
+ if (dialog === element || dialog.contains(element)) {
921
+ continue;
922
+ }
923
+ // A modal on its way out (a closing sheet keeps its dialog modal through
924
+ // the exit animation, inert and hidden) blocks nothing any more: it is
925
+ // gone for this decision.
926
+ if (
927
+ dialog.hasAttribute('inert') ||
928
+ dialog.getAttribute('aria-hidden') === 'true'
929
+ ) {
930
+ continue;
931
+ }
932
+ if (isModalDialog(dialog)) {
933
+ blockers.push(dialog);
934
+ }
935
+ }
936
+ return blockers;
937
+ }
938
+
939
+ /**
940
+ * Non-modal sheets presented by `show()` because a modal outside them was
941
+ * open, waiting to enter the top layer once it has gone. Per document, with
942
+ * one `close` listener per document: any dialog closing is a reason to look
943
+ * again, and so is every sheet-stack update (a closing modal sheet turns
944
+ * inert before its dialog closes). An open modal removed from the document
945
+ * fires no `close` — a `{isEditing && <Dialog isOpen>}` that unmounts while
946
+ * open — so while anything waits, a mutation observer watches removals too
947
+ * and looks again when a removed subtree held one of the dialogs that caused
948
+ * a deferral. Those blockers are recorded at defer time: `:modal` is the
949
+ * mark that matters, and it leaves with the dialog's top-layer membership,
950
+ * so it cannot be read off a removed node (nor can `aria-modal`, which a
951
+ * `showModal()` host such as MobileNav or Lightbox does not set).
952
+ */
953
+
954
+ function deferTopLayerEntry(
955
+ dialog: HTMLDialogElement,
956
+ panel: HTMLElement | null,
957
+ blockers: ReadonlyArray<HTMLDialogElement>,
958
+ ): void {
959
+ const doc = dialog.ownerDocument;
960
+ let entry = state.deferredTopLayer.get(doc);
961
+ if (entry == null) {
962
+ entry = {
963
+ deferred: new Map(),
964
+ blockers: new WeakSet(),
965
+ removals: null,
966
+ stopListeningForClose: null,
967
+ };
968
+ state.deferredTopLayer.set(doc, entry);
969
+ }
970
+ if (entry.stopListeningForClose == null) {
971
+ // Installed with the first deferral and removed with the last promotion
972
+ // (`architecture:react-component-runtime` INV5), like the observer below.
973
+ const onClose = () => {
974
+ promoteDeferredNonModal(doc);
975
+ };
976
+ doc.addEventListener('close', onClose, true);
977
+ entry.stopListeningForClose = () => {
978
+ doc.removeEventListener('close', onClose, true);
979
+ };
980
+ }
981
+ entry.deferred.set(dialog, panel);
982
+ for (const blocker of blockers) {
983
+ entry.blockers.add(blocker);
984
+ }
985
+ if (entry.removals == null && typeof MutationObserver === 'function') {
986
+ const {blockers: known} = entry;
987
+ const observer = new MutationObserver(records => {
988
+ if (records.some(record => removedABlocker(record, known))) {
989
+ promoteDeferredNonModal(doc);
990
+ }
991
+ });
992
+ observer.observe(doc, {childList: true, subtree: true});
993
+ entry.removals = observer;
994
+ }
995
+ }
996
+
997
+ function removedABlocker(
998
+ record: MutationRecord,
999
+ blockers: WeakSet<HTMLDialogElement>,
1000
+ ): boolean {
1001
+ for (const node of Array.from(record.removedNodes)) {
1002
+ if (!(node instanceof Element)) {
1003
+ continue;
1004
+ }
1005
+ const dialogs =
1006
+ node instanceof HTMLDialogElement
1007
+ ? [node]
1008
+ : Array.from(node.querySelectorAll<HTMLDialogElement>('dialog'));
1009
+ if (dialogs.some(dialog => blockers.has(dialog))) {
1010
+ return true;
1011
+ }
1012
+ }
1013
+ return false;
1014
+ }
1015
+
1016
+ /**
1017
+ * Move every waiting non-modal sheet whose outside modals have all gone into
1018
+ * the top layer: it leaves `show()` and is presented again as a manual
1019
+ * popover, announcing its entry so global hosts re-enter above it. Focus
1020
+ * stays where it was.
1021
+ */
1022
+ export function promoteDeferredNonModal(doc: Document): void {
1023
+ const entry = state.deferredTopLayer.get(doc);
1024
+ if (entry == null || entry.deferred.size === 0) {
1025
+ return;
1026
+ }
1027
+ const {deferred} = entry;
1028
+ for (const [dialog, panel] of Array.from(deferred)) {
1029
+ if (!dialog.isConnected || !dialog.open) {
1030
+ deferred.delete(dialog);
1031
+ continue;
1032
+ }
1033
+ const blockers = openModalsOutside(dialog);
1034
+ if (blockers.length > 0) {
1035
+ // Still waiting, maybe on a modal that was not there at defer time (one
1036
+ // Dialog replaced by another in a single update): it is a blocker now,
1037
+ // and its removal must be a reason to look again too.
1038
+ for (const blocker of blockers) {
1039
+ entry.blockers.add(blocker);
1040
+ }
1041
+ continue;
1042
+ }
1043
+ deferred.delete(dialog);
1044
+ const activeElement = doc.activeElement;
1045
+ dialog.close();
1046
+ showSheetHostNonModal(dialog, panel);
1047
+ if (
1048
+ doc.activeElement !== activeElement &&
1049
+ activeElement instanceof HTMLElement &&
1050
+ activeElement.isConnected
1051
+ ) {
1052
+ activeElement.focus({preventScroll: true});
1053
+ }
1054
+ }
1055
+ if (deferred.size === 0) {
1056
+ releaseDeferralWatchers(entry);
1057
+ }
1058
+ }
1059
+
1060
+ function releaseDeferralWatchers(entry: DeferredTopLayer): void {
1061
+ entry.removals?.disconnect();
1062
+ entry.removals = null;
1063
+ entry.stopListeningForClose?.();
1064
+ entry.stopListeningForClose = null;
1065
+ }
1066
+
1067
+ function isModalDialog(dialog: HTMLDialogElement): boolean {
1068
+ // `:modal` is the browser's own answer (every browser with the Popover
1069
+ // API has it). jsdom answers false to it for every dialog, so the modal
1070
+ // hosts' own `aria-modal="true"` (Dialog, a scrim BottomSheet) decides
1071
+ // there.
1072
+ try {
1073
+ if (dialog.matches(':modal')) {
1074
+ return true;
1075
+ }
1076
+ } catch {
1077
+ // An engine without :modal; fall through to the attribute.
1078
+ }
1079
+ return dialog.getAttribute('aria-modal') === 'true';
1080
+ }
1081
+
1082
+ /**
1083
+ * Present a non-modal sheet: in the top layer as a manual popover where the
1084
+ * Popover API exists (Tier 2 and up), so later sheets order above earlier
1085
+ * ones and no page-level z-index is needed; by `show()` below that floor.
1086
+ * A manual popover has no light dismiss, no backdrop and no focus or scroll
1087
+ * side effects, so the non-modal contract is otherwise unchanged.
1088
+ *
1089
+ * A non-modal sheet shown while a modal dialog that does not contain it is
1090
+ * open (a modal sheet, a Dialog) is inert under that modal, so it is not put
1091
+ * in the top layer — there it would paint above the modal while a press on
1092
+ * it lands on the modal beneath — and is presented by `show()` instead, in
1093
+ * page stacking order beneath the modal, with no page-level z-index; once
1094
+ * the last such modal has gone it is presented again in the top layer
1095
+ * (`promoteDeferredNonModal`). A non-modal sheet rendered inside the modal's
1096
+ * content is not inert and enters the top layer at once.
1097
+ */
1098
+ export function showSheetHostNonModal(
1099
+ dialog: HTMLDialogElement,
1100
+ panel: HTMLElement | null,
1101
+ ): void {
1102
+ if (typeof dialog.showPopover !== 'function') {
1103
+ dialog.show();
1104
+ return;
1105
+ }
1106
+ const blockers = openModalsOutside(dialog);
1107
+ if (blockers.length > 0) {
1108
+ dialog.show();
1109
+ deferTopLayerEntry(dialog, panel, blockers);
1110
+ return;
1111
+ }
1112
+ // Both native paths run the engine's focusing steps, and engines differ.
1113
+ // Chromium's `show()` lands on the first focusable area in tree order,
1114
+ // the panel (`tabindex="-1"`, no focus ring), while its `showPopover()`
1115
+ // skips such containers and lands on the first control; Firefox lands on
1116
+ // the first control on both paths. The sheet must focus as it did with
1117
+ // `show()` in the engine at hand, and no control may be focused and
1118
+ // blurred on the way (a field validating on blur would show its error on
1119
+ // open). So the popover's focusing steps are pointed at the panel first:
1120
+ // `autofocus` on the panel for the duration of `showPopover()` makes it
1121
+ // the steps' autofocus delegate in every engine, and the panel is where a
1122
+ // container-focusing engine's `show()` lands. Where the engine's `show()`
1123
+ // skips the container and lands on the first control, focus moves from
1124
+ // the panel to that control once — a focus on the control, no blur.
1125
+ const doc = dialog.ownerDocument;
1126
+ const hadAutofocus = panel?.hasAttribute('autofocus') ?? false;
1127
+ if (panel != null && !hadAutofocus) {
1128
+ panel.setAttribute('autofocus', '');
1129
+ }
1130
+ try {
1131
+ dialog.showPopover();
1132
+ } finally {
1133
+ if (panel != null && !hadAutofocus) {
1134
+ panel.removeAttribute('autofocus');
1135
+ }
1136
+ }
1137
+ // The sheet is now the newest top-layer entry: global hosts shown before
1138
+ // it (the toast viewport) re-enter above it, as they do above a modal.
1139
+ notifyTopLayerEntry();
1140
+ if (
1141
+ panel != null &&
1142
+ doc.activeElement === panel &&
1143
+ !nativeShowFocusesContainer(dialog)
1144
+ ) {
1145
+ firstSequentiallyFocusable(panel)?.focus({preventScroll: true});
1146
+ }
1147
+ }
1148
+
1149
+ /**
1150
+ * The first element inside `root`, in tree order, that sequential focus
1151
+ * navigation reaches: focusable, with a tab index of zero or more, not
1152
+ * disabled, not inert, and rendered. This is where an engine whose
1153
+ * `show()` skips programmatically focusable containers lands.
1154
+ */
1155
+ function firstSequentiallyFocusable(root: HTMLElement): HTMLElement | null {
1156
+ const candidates = root.querySelectorAll<HTMLElement>(
1157
+ 'a[href], area[href], button, input, select, textarea, iframe, summary, [contenteditable]:not([contenteditable="false"]), [tabindex]',
1158
+ );
1159
+ for (const candidate of Array.from(candidates)) {
1160
+ if (candidate === root || candidate.tabIndex < 0) {
1161
+ continue;
1162
+ }
1163
+ if (
1164
+ (candidate as HTMLButtonElement).disabled === true ||
1165
+ candidate.closest('[inert]') != null ||
1166
+ candidate.getAttribute('type') === 'hidden' ||
1167
+ candidate.hidden ||
1168
+ (typeof candidate.checkVisibility === 'function' &&
1169
+ !candidate.checkVisibility())
1170
+ ) {
1171
+ continue;
1172
+ }
1173
+ return candidate;
1174
+ }
1175
+ return null;
1176
+ }
1177
+
1178
+ let showFocusesContainer: boolean | null = null;
1179
+
1180
+ /**
1181
+ * Whether this engine's `dialog.show()` focusing steps land on a
1182
+ * programmatically focusable container (`tabindex="-1"`) that comes before
1183
+ * the first control — Chromium does, Firefox skips it. Measured once, on a
1184
+ * throwaway non-modal dialog that is shown, read and removed inside one
1185
+ * task (no paint); focus is put back where it was. The probe lives inside
1186
+ * `host`, the sheet's own dialog, which is in the top layer and interactive
1187
+ * at this point (a lone sheet, or one inside the open modal's content): a
1188
+ * probe appended to the body could sit under an open modal's inertness,
1189
+ * where `show()` moves no focus, and cache the wrong answer for the page.
1190
+ */
1191
+ function nativeShowFocusesContainer(host: HTMLDialogElement): boolean {
1192
+ if (showFocusesContainer != null) {
1193
+ return showFocusesContainer;
1194
+ }
1195
+ const doc = host.ownerDocument;
1196
+ const activeBefore = doc.activeElement;
1197
+ const probe = doc.createElement('dialog');
1198
+ probe.setAttribute('aria-hidden', 'true');
1199
+ probe.style.cssText =
1200
+ 'position:fixed;inset:auto;opacity:0;pointer-events:none';
1201
+ const container = doc.createElement('div');
1202
+ container.tabIndex = -1;
1203
+ const control = doc.createElement('button');
1204
+ control.type = 'button';
1205
+ container.appendChild(control);
1206
+ probe.appendChild(container);
1207
+ host.appendChild(probe);
1208
+ try {
1209
+ probe.show();
1210
+ showFocusesContainer = doc.activeElement === container;
1211
+ probe.close();
1212
+ } catch {
1213
+ showFocusesContainer = true;
1214
+ } finally {
1215
+ probe.remove();
1216
+ if (
1217
+ doc.activeElement !== activeBefore &&
1218
+ activeBefore instanceof HTMLElement &&
1219
+ activeBefore.isConnected
1220
+ ) {
1221
+ activeBefore.focus({preventScroll: true});
1222
+ }
1223
+ }
1224
+ return showFocusesContainer;
1225
+ }
1226
+
1227
+ /** Leave the native host, whichever one presents the sheet. */
1228
+ export function hideSheetHost(dialog: HTMLDialogElement): void {
1229
+ const entry = state.deferredTopLayer.get(dialog.ownerDocument);
1230
+ if (entry != null && entry.deferred.delete(dialog)) {
1231
+ if (entry.deferred.size === 0) {
1232
+ releaseDeferralWatchers(entry);
1233
+ }
1234
+ }
1235
+ if (
1236
+ dialog.hasAttribute('popover') &&
1237
+ typeof dialog.hidePopover === 'function'
1238
+ ) {
1239
+ try {
1240
+ dialog.hidePopover();
1241
+ } catch {
1242
+ // Not showing as a popover (the show() fallback); nothing to hide here.
1243
+ }
1244
+ }
1245
+ if (dialog.open) {
1246
+ dialog.close();
1247
+ }
1248
+ }
1249
+
1250
+ /**
1251
+ * Close a dialog without letting the browser move focus. `close()` returns
1252
+ * focus to the element that was focused when `showModal()` ran; with another
1253
+ * sheet still open on top, that would pull focus out of the sheet the person
1254
+ * is using (a re-show that repairs the top-layer order, a covered sheet
1255
+ * closing from code, a replaced sheet leaving). Focus stays where it is; the
1256
+ * caller decides where it goes next, if anywhere.
1257
+ */
1258
+ export function closeDialogKeepingFocus(
1259
+ dialog: HTMLDialogElement | null,
1260
+ ): void {
1261
+ if (dialog == null || !isSheetHostPresented(dialog)) {
1262
+ return;
1263
+ }
1264
+ const doc = dialog.ownerDocument;
1265
+ const activeElement = doc.activeElement;
1266
+ hideSheetHost(dialog);
1267
+ if (
1268
+ doc.activeElement !== activeElement &&
1269
+ activeElement instanceof HTMLElement &&
1270
+ activeElement.isConnected
1271
+ ) {
1272
+ activeElement.focus({preventScroll: true});
1273
+ }
1274
+ }
1275
+
1276
+ /**
1277
+ * Pair the one close and the one open of this batch as a replace. A replace
1278
+ * is a move the person makes from one sheet to the next, and that is what
1279
+ * the conditions check:
1280
+ *
1281
+ * - exactly one sheet closed and exactly one opened in this update;
1282
+ * - both are standalone sheets of one group — one document, both modal or
1283
+ * both non-modal (a switcher flow replaces its own steps and is never
1284
+ * paired);
1285
+ * - the closing sheet was the top sheet of its stack once the opening sheet
1286
+ * is set aside — a covered sheet closing while a sheet opens is a pop
1287
+ * beneath a push;
1288
+ * - neither dialog contains the other — a sheet in another's content closes
1289
+ * with it, it does not replace it;
1290
+ * - the interaction came from inside the closing sheet: the control the
1291
+ * person last pressed (or, with no recent press, the element focused when
1292
+ * this update's first flip arrived, before any dialog of the update was
1293
+ * shown) is in its dialog, or nowhere (a control that left with the step).
1294
+ * A close and an open driven from a control outside the closing sheet are
1295
+ * two unrelated owners acting in one update, so the sheets keep their own
1296
+ * openers and their own push and pop motion.
1297
+ *
1298
+ * The opening sheet then adopts the closing sheet's opener: its own opener
1299
+ * is inside the sheet that is leaving, and the flow began where the closing
1300
+ * sheet's did.
1301
+ */
1302
+ function detectReplace(): void {
1303
+ if (state.batchOpened.length !== 1 || state.batchClosed.length !== 1) {
1304
+ // A pair made earlier in this commit, before a third flip arrived, is
1305
+ // undone: the commit's final tally decides, and several sheets changing
1306
+ // in one update keep their own push and pop motion.
1307
+ undoBatchPair();
1308
+ return;
1309
+ }
1310
+ const [replacer] = state.batchOpened;
1311
+ const [replaced] = state.batchClosed;
1312
+ if (state.batchPair != null && state.batchPair.replaced === replaced) {
1313
+ return;
1314
+ }
1315
+ if (
1316
+ replaced === replacer ||
1317
+ replaced.replaceable == null ||
1318
+ replacer.replaceable == null ||
1319
+ replaced.doc !== replacer.doc ||
1320
+ replaced.isModal !== replacer.isModal ||
1321
+ replaced.replace?.replacer === replacer ||
1322
+ !replacer.isOpen ||
1323
+ replaced.isOpen
1324
+ ) {
1325
+ return;
1326
+ }
1327
+ const replacedElement = replaced.getElement();
1328
+ const replacerElement = replacer.getElement();
1329
+ if (
1330
+ replacedElement == null ||
1331
+ replacerElement == null ||
1332
+ replacedElement.contains(replacerElement) ||
1333
+ replacerElement.contains(replacedElement)
1334
+ ) {
1335
+ return;
1336
+ }
1337
+ const wasTop = !groupOf(replaced).some(
1338
+ other =>
1339
+ other !== replacer &&
1340
+ other !== replaced &&
1341
+ other.isOpen &&
1342
+ compareRank(other, replaced) > 0,
1343
+ );
1344
+ if (!wasTop) {
1345
+ return;
1346
+ }
1347
+ const actor = state.batchActor;
1348
+ const actedFromReplaced =
1349
+ actor == null ||
1350
+ actor === replaced.doc.body ||
1351
+ replacedElement.contains(actor);
1352
+ if (!actedFromReplaced) {
1353
+ return;
1354
+ }
1355
+ // A third sheet the closing sheet was itself replacing is dropped at once,
1356
+ // the way a switcher drops a step that is left mid-handoff. The sheet it
1357
+ // was replacing may instead be the one coming back now (a reversal): then
1358
+ // the roles swap and nothing is dropped.
1359
+ if (replaced.replacing != null && replaced.replacing !== replacer) {
1360
+ finishReplace(replaced.replacing);
1361
+ }
1362
+ if (replaced.replace != null) {
1363
+ replaced.replace.replacer.replacing = null;
1364
+ }
1365
+ if (replacer.replace != null) {
1366
+ replacer.replace = null;
1367
+ }
1368
+ replaced.replace = {
1369
+ replacer,
1370
+ motion: 'covered',
1371
+ alignmentOffset: 0,
1372
+ isAlignmentComplete: false,
1373
+ isEnteringComplete: false,
1374
+ };
1375
+ replacer.replacing = replaced;
1376
+ state.batchPair = {
1377
+ replaced,
1378
+ replacer,
1379
+ replacerOpener: replacer.replaceable.getOpener(),
1380
+ };
1381
+ // The press that made this replace is consumed by it.
1382
+ state.lastPress.delete(replacer.doc);
1383
+ replacer.replaceable.setOpener(replaced.replaceable.getOpener());
1384
+ state.pendingReplaceFocus = replacer;
1385
+ }
1386
+
1387
+ /**
1388
+ * Undo the pair this batch made: the replaced sheet is an ordinary closing
1389
+ * sheet again, the replacer an ordinary opening one with its own opener, and
1390
+ * no focus is owed. Called when a later flip of the same commit changes the
1391
+ * tally, before the commit paints.
1392
+ */
1393
+ function undoBatchPair(): void {
1394
+ const pair = state.batchPair;
1395
+ if (pair == null) {
1396
+ return;
1397
+ }
1398
+ state.batchPair = null;
1399
+ const {replaced, replacer, replacerOpener} = pair;
1400
+ if (replaced.replace?.replacer === replacer) {
1401
+ replaced.replace = null;
1402
+ }
1403
+ if (replacer.replacing === replaced) {
1404
+ replacer.replacing = null;
1405
+ }
1406
+ replacer.replaceable?.setOpener(replacerOpener);
1407
+ if (state.pendingReplaceFocus === replacer) {
1408
+ state.pendingReplaceFocus = null;
1409
+ }
1410
+ }
1411
+
1412
+ /**
1413
+ * The person moves from the replaced step to the entering one, so focus
1414
+ * does too, and it lands on the step's `data-autofocus` descendant when it
1415
+ * has one. The dialog is shown by now, so the native focusing steps have
1416
+ * run: a modal replacer's `showModal()` put focus on the entering panel, a
1417
+ * non-modal replacer's `showPopover()` may have left it where it was (Safari;
1418
+ * the replaced step is inert from this frame). Either way the placement runs
1419
+ * after them — focus sitting on the panel, or anywhere that is not the
1420
+ * `data-autofocus` descendant, is the native steps' doing, not the
1421
+ * person's, so it does not count as placed. Only focus the person already
1422
+ * moved to a control inside the entering step is left alone.
1423
+ */
1424
+ function focusPendingReplacer(): void {
1425
+ const replacer = state.pendingReplaceFocus;
1426
+ if (replacer == null) {
1427
+ return;
1428
+ }
1429
+ const element = replacer.getElement();
1430
+ if (element == null || !isSheetHostPresented(element)) {
1431
+ return;
1432
+ }
1433
+ state.pendingReplaceFocus = null;
1434
+ replacer.focus('replace');
1435
+ }
1436
+
1437
+ /**
1438
+ * End a replace: the replaced sheet is hidden and its dialog closed; the
1439
+ * views computed next hand the scrim to the sheet that replaced it, which
1440
+ * takes it in the same frame. Focus stays where it is.
1441
+ */
1442
+ function finishReplace(replaced: Entry): void {
1443
+ const replace = replaced.replace;
1444
+ if (replace == null) {
1445
+ return;
1446
+ }
1447
+ const {replacer} = replace;
1448
+ replaced.replace = null;
1449
+ if (replacer.replacing === replaced) {
1450
+ replacer.replacing = null;
1451
+ }
1452
+ replaced.hide();
1453
+ replaced.replaceable?.finish();
1454
+ }
1455
+
1456
+ /**
1457
+ * The viewport top a panel rests at: its box without the translation it is
1458
+ * still travelling under (an entering panel rises from below the viewport).
1459
+ * Read from the panel itself, never from the element around it: a standalone
1460
+ * sheet's panel sits directly in its dialog, which spans the viewport, so a
1461
+ * parent's top is not where the panel rests.
1462
+ */
1463
+ function restingTopOfPanel(panel: HTMLElement): number {
1464
+ const top = panel.getBoundingClientRect().top;
1465
+ const view = panel.ownerDocument.defaultView;
1466
+ if (view == null || typeof view.DOMMatrixReadOnly !== 'function') {
1467
+ return top;
1468
+ }
1469
+ const {transform} = view.getComputedStyle(panel);
1470
+ if (transform === '' || transform === 'none') {
1471
+ return top;
1472
+ }
1473
+ // A sheet panel only ever translates on the block axis (entrance, drag,
1474
+ // alignment); its computed matrix's `m42` is that translation.
1475
+ return top - new view.DOMMatrixReadOnly(transform).m42;
1476
+ }
1477
+
1478
+ function alignmentOffsetForPanels(
1479
+ enteringPanel: HTMLElement | null,
1480
+ retainedPanel: HTMLElement | null,
1481
+ ): number {
1482
+ if (enteringPanel == null || retainedPanel == null) {
1483
+ return 0;
1484
+ }
1485
+ // The retained panel is at rest; the entering panel is measured where its
1486
+ // entrance will leave it.
1487
+ return Math.max(
1488
+ 0,
1489
+ restingTopOfPanel(enteringPanel) -
1490
+ retainedPanel.getBoundingClientRect().top,
1491
+ );
1492
+ }
1493
+
1494
+ /**
1495
+ * A host's panel reports the start and end of its motions here. During a
1496
+ * replace they drive the handoff: when the entering sheet starts to rise, a
1497
+ * taller retained sheet starts moving down to its top edge; the retained
1498
+ * sheet fades once both have finished; when the fade ends the replace is over.
1499
+ */
1500
+ export function reportBottomSheetMotion(
1501
+ key: object,
1502
+ event: 'start' | 'complete',
1503
+ motion: BottomSheetReplaceMotion,
1504
+ ): void {
1505
+ const entry = state.entries.find(candidate => candidate.key === key);
1506
+ if (entry == null) {
1507
+ return;
1508
+ }
1509
+ if (motion === 'entering') {
1510
+ const replaced = entry.replacing;
1511
+ const replace = replaced?.replace ?? null;
1512
+ if (replaced == null || replace == null || replace.replacer !== entry) {
1513
+ return;
1514
+ }
1515
+ if (event === 'start') {
1516
+ if (replace.motion !== 'covered') {
1517
+ return;
1518
+ }
1519
+ const alignmentOffset = alignmentOffsetForPanels(
1520
+ entry.replaceable?.getPanel() ?? null,
1521
+ replaced.replaceable?.getPanel() ?? null,
1522
+ );
1523
+ if (alignmentOffset > ALIGNMENT_THRESHOLD_PX) {
1524
+ replace.motion = 'aligning';
1525
+ replace.alignmentOffset = alignmentOffset;
1526
+ replace.isAlignmentComplete = false;
1527
+ }
1528
+ // A sheet that came back while fading is already where it belongs:
1529
+ // its entrance is over as soon as it starts, like a switcher step's.
1530
+ if (entry.isEnteringInPlace) {
1531
+ entry.isEnteringInPlace = false;
1532
+ replace.isEnteringComplete = true;
1533
+ if (replace.motion !== 'aligning') {
1534
+ replace.motion = 'fading';
1535
+ }
1536
+ } else if (replace.motion === 'covered') {
1537
+ return;
1538
+ }
1539
+ } else {
1540
+ replace.isEnteringComplete = true;
1541
+ if (replace.motion === 'aligning' && !replace.isAlignmentComplete) {
1542
+ return;
1543
+ }
1544
+ replace.motion = 'fading';
1545
+ }
1546
+ update(entry.doc, entry.isModal);
1547
+ return;
1548
+ }
1549
+ const replace = entry.replace;
1550
+ if (replace == null || event !== 'complete') {
1551
+ return;
1552
+ }
1553
+ if (motion === 'aligning' && replace.motion === 'aligning') {
1554
+ if (replace.isEnteringComplete) {
1555
+ replace.motion = 'fading';
1556
+ } else {
1557
+ replace.isAlignmentComplete = true;
1558
+ }
1559
+ update(entry.doc, entry.isModal);
1560
+ } else if (motion === 'fading' && replace.motion === 'fading') {
1561
+ finishReplace(entry);
1562
+ update(entry.doc, entry.isModal);
1563
+ }
1564
+ }
1565
+
1566
+ /**
1567
+ * Make a document's top layer match the ranked order. The top layer is
1568
+ * append-only, so a dialog can only move up, by closing and showing it again:
1569
+ * the longest prefix of the wanted order that the shown order already
1570
+ * contains, in order, is kept, and every dialog after it is re-shown in
1571
+ * order (closing them from the top first). A deep link whose inner sheet
1572
+ * registered first therefore re-shows inner and outer; a sheet that must
1573
+ * rise above the sheets shown after it re-shows only itself, so a retained
1574
+ * sheet beneath it keeps its backdrop and any motion in flight. Runs inside
1575
+ * the commit, so a wrong intermediate order never paints. Focus moves into
1576
+ * the top open sheet when anything was shown — unless the person was already
1577
+ * in a sheet that is only re-shown to keep its place (a switcher flow it
1578
+ * covers changed step from code, say): the element they were in, a field
1579
+ * being typed in, is the dialog's focus delegate for that `showModal()` and
1580
+ * is focused again right after it, so the keystrokes that follow still land
1581
+ * there. The top layer is append-only, so the re-show has to close the dialog
1582
+ * first and the field sees one blur and one focus; nothing shorter exists.
1583
+ */
1584
+ function reconcileTopLayer(
1585
+ doc: Document,
1586
+ isModal: boolean,
1587
+ order: Entry[],
1588
+ ): void {
1589
+ const shownOrder = getShownOrder(doc, isModal);
1590
+ const presentable = order.filter(entry => {
1591
+ const element = entry.getElement();
1592
+ return element != null && element.isConnected;
1593
+ });
1594
+ let kept = 0;
1595
+ let cursor = 0;
1596
+ while (kept < presentable.length) {
1597
+ const next = shownOrder.indexOf(presentable[kept], cursor);
1598
+ if (next === -1) {
1599
+ break;
1600
+ }
1601
+ cursor = next + 1;
1602
+ kept += 1;
1603
+ }
1604
+ const keptEntries = new Set(presentable.slice(0, kept));
1605
+ const reshown = presentable.slice(kept);
1606
+ const keptActive = activeElementToKeep(doc, reshown);
1607
+ let didShow = false;
1608
+ for (let index = shownOrder.length - 1; index >= 0; index -= 1) {
1609
+ if (!keptEntries.has(shownOrder[index])) {
1610
+ shownOrder[index].hide();
1611
+ }
1612
+ }
1613
+ for (const entry of reshown) {
1614
+ const delegate =
1615
+ keptActive != null && entry.getElement()?.contains(keptActive)
1616
+ ? keptActive
1617
+ : null;
1618
+ // The native focusing steps follow an `autofocus` delegate, so the
1619
+ // re-shown dialog lands on the element the person was in instead of its
1620
+ // first focusable area; the attribute is the dialog's for this call only.
1621
+ const hadAutofocus = delegate?.hasAttribute('autofocus') ?? false;
1622
+ if (delegate != null && !hadAutofocus) {
1623
+ delegate.setAttribute('autofocus', '');
1624
+ }
1625
+ entry.show();
1626
+ if (delegate != null && !hadAutofocus) {
1627
+ delegate.removeAttribute('autofocus');
1628
+ }
1629
+ didShow = true;
1630
+ }
1631
+ setShownOrder(doc, isModal, presentable);
1632
+ if (!didShow) {
1633
+ return;
1634
+ }
1635
+ // A dialog shown again (closed and re-shown to keep its place) went back
1636
+ // into the top layer above everything shown before, a global host's
1637
+ // popover hosted inside it included: that popover still reads as showing
1638
+ // but paints beneath the dialog now. Hosts re-enter the top layer in
1639
+ // place, as they do above a non-modal surface that just entered, so toasts
1640
+ // raised in the re-shown sheet still paint above it. A first show needs
1641
+ // none of this: the outlet it supplies moves the hosts.
1642
+ if (reshown.some(entry => shownOrder.includes(entry))) {
1643
+ notifyTopLayerEntry();
1644
+ }
1645
+ if (keptActive != null && keptActive.isConnected) {
1646
+ if (doc.activeElement !== keptActive) {
1647
+ keptActive.focus({preventScroll: true});
1648
+ }
1649
+ return;
1650
+ }
1651
+ const openEntries = presentable.filter(entry => entry.isOpen);
1652
+ openEntries[openEntries.length - 1]?.focus('open');
1653
+ }
1654
+
1655
+ /**
1656
+ * The element to keep focused across a re-show: the document's active
1657
+ * element when it is inside an open sheet that is about to be re-shown.
1658
+ */
1659
+ function activeElementToKeep(
1660
+ doc: Document,
1661
+ reshown: ReadonlyArray<Entry>,
1662
+ ): HTMLElement | null {
1663
+ const remembered = state.focusToKeep.get(doc);
1664
+ state.focusToKeep.delete(doc);
1665
+ const current = doc.activeElement;
1666
+ const active =
1667
+ remembered != null && remembered.isConnected
1668
+ ? remembered
1669
+ : current instanceof HTMLElement && current !== doc.body
1670
+ ? current
1671
+ : null;
1672
+ if (active == null) {
1673
+ return null;
1674
+ }
1675
+ for (const entry of reshown) {
1676
+ const element = entry.getElement();
1677
+ if (entry.isOpen && element != null && element.contains(active)) {
1678
+ return active;
1679
+ }
1680
+ }
1681
+ return null;
1682
+ }
1683
+
1684
+ function update(doc: Document, isModal: boolean): void {
1685
+ detectReplace();
1686
+ // A drop can land as soon as the batch has both of its flips: the pairing
1687
+ // is decided then, and anything left `replace`d is a retained sheet whose
1688
+ // replacer left the flow.
1689
+ if (state.batchOpened.length > 0 && state.batchClosed.length > 0) {
1690
+ flushPendingDrops();
1691
+ }
1692
+ const order = sortedEntries(doc, isModal);
1693
+ computeViews(order, isModal);
1694
+ reconcileTopLayer(doc, isModal, order);
1695
+ state.focusToKeep.delete(doc);
1696
+ focusPendingReplacer();
1697
+ promoteDeferredNonModal(doc);
1698
+ }
1699
+
1700
+ /**
1701
+ * Join the stack for as long as the sheet is presented. Call from a layout
1702
+ * effect; the returned function leaves the stack (also from its cleanup).
1703
+ * `isOpen` is the controlled open state; a presented sheet whose `isOpen` is
1704
+ * false is sliding out and keeps its place without counting as a layer.
1705
+ */
1706
+ export function registerBottomSheet(
1707
+ registration: BottomSheetStackRegistration,
1708
+ isOpen: boolean,
1709
+ isModal: boolean = true,
1710
+ ): () => void {
1711
+ const {key} = registration;
1712
+ const remembered = state.rankByKey.get(key);
1713
+ let rank: Rank;
1714
+ if (
1715
+ remembered != null &&
1716
+ !remembered.isClosed &&
1717
+ // A StrictMode replay unregisters and registers again in one synchronous
1718
+ // pass, before any seal; the rank is kept so the replay cannot reorder.
1719
+ // A sheet React hid (Suspense, Activity) and later revealed comes back in
1720
+ // a later batch and re-presents on top, like a fresh open.
1721
+ (remembered.detachedBatch == null ||
1722
+ remembered.detachedBatch === state.currentBatch)
1723
+ ) {
1724
+ rank = {batch: remembered.batch, seq: remembered.seq};
1725
+ remembered.detachedBatch = null;
1726
+ } else {
1727
+ rank = takeRank();
1728
+ state.rankByKey.set(key, {
1729
+ ...rank,
1730
+ isClosed: !isOpen,
1731
+ detachedBatch: null,
1732
+ });
1733
+ }
1734
+ const doc = registration.getElement()?.ownerDocument ?? document;
1735
+ listenForPresses(doc);
1736
+ const entry: Entry = {
1737
+ ...registration,
1738
+ rank,
1739
+ isOpen,
1740
+ doc,
1741
+ isModal,
1742
+ view: BOTTOM_SHEET_STACK_DEFAULT_VIEW,
1743
+ replace: null,
1744
+ replacing: null,
1745
+ isEnteringInPlace: false,
1746
+ };
1747
+ state.entries.push(entry);
1748
+ if (isOpen && rank.batch === state.currentBatch && state.isBatchDirty) {
1749
+ recordFlip(entry, 'opened');
1750
+ }
1751
+ update(entry.doc, entry.isModal);
1752
+
1753
+ return () => {
1754
+ const index = state.entries.indexOf(entry);
1755
+ if (index === -1) {
1756
+ return;
1757
+ }
1758
+ state.entries.splice(index, 1);
1759
+ stopListeningForPresses(entry.doc);
1760
+ setShownOrder(
1761
+ entry.doc,
1762
+ entry.isModal,
1763
+ getShownOrder(entry.doc, entry.isModal).filter(shown => shown !== entry),
1764
+ );
1765
+ state.batchOpened = state.batchOpened.filter(other => other !== entry);
1766
+ state.batchClosed = state.batchClosed.filter(other => other !== entry);
1767
+ state.pendingDrops = state.pendingDrops.filter(other => other !== entry);
1768
+ if (state.pendingReplaceFocus === entry) {
1769
+ state.pendingReplaceFocus = null;
1770
+ }
1771
+ if (
1772
+ state.batchPair?.replaced === entry ||
1773
+ state.batchPair?.replacer === entry
1774
+ ) {
1775
+ state.batchPair = null;
1776
+ }
1777
+ // A member of a "Close all" group leaving the registry has left for
1778
+ // good: a host that unmounts mid-exit never sends its motion report, so
1779
+ // leaving is its completion. Reported after `hide()` below, once its
1780
+ // dialog is out of the top layer, so the return focus has nothing modal
1781
+ // in its way; a host that still reports afterwards finds nothing to do.
1782
+ const closingGroup = state.closingTogether.get(entry);
1783
+ if (entry.replace != null) {
1784
+ entry.replace.replacer.replacing = null;
1785
+ entry.replace = null;
1786
+ }
1787
+ if (entry.replacing != null) {
1788
+ // The sheet it was replacing is left as an ordinary closing sheet.
1789
+ entry.replacing.replace = null;
1790
+ entry.replacing = null;
1791
+ }
1792
+ // A sheet that leaves while its dialog is still open was hidden by React
1793
+ // (Suspense, Activity) or is unmounting: a modal dialog with no box would
1794
+ // keep blocking the page, so it leaves the top layer here.
1795
+ entry.hide();
1796
+ if (closingGroup != null) {
1797
+ leaveClosingGroup(entry, closingGroup);
1798
+ }
1799
+ const current = state.rankByKey.get(key);
1800
+ if (current != null) {
1801
+ current.detachedBatch = state.currentBatch;
1802
+ state.isBatchDirty = true;
1803
+ scheduleSeal();
1804
+ }
1805
+ entry.view = BOTTOM_SHEET_STACK_DEFAULT_VIEW;
1806
+ entry.onView(entry.view);
1807
+ update(entry.doc, entry.isModal);
1808
+ };
1809
+ }
1810
+
1811
+ /**
1812
+ * The dialog that realizes a level changed: a switcher flow handed off to a
1813
+ * step with its own dialog, which its host presented on top of the top layer
1814
+ * in this same commit. The level keeps its rank; the registry records the new
1815
+ * dialog as the most recently shown and puts the sheets that belong above it
1816
+ * back on top before paint. A level on its own, or already on top, is left
1817
+ * alone.
1818
+ */
1819
+ export function notifyBottomSheetHostChanged(key: object): void {
1820
+ const entry = state.entries.find(candidate => candidate.key === key);
1821
+ if (entry == null || !entry.isModal) {
1822
+ return;
1823
+ }
1824
+ const element = entry.getElement();
1825
+ if (element == null || !isSheetHostPresented(element)) {
1826
+ return;
1827
+ }
1828
+ const shown = getShownOrder(entry.doc, true).filter(
1829
+ shownEntry => shownEntry !== entry,
1830
+ );
1831
+ shown.push(entry);
1832
+ setShownOrder(entry.doc, true, shown);
1833
+ update(entry.doc, true);
1834
+ }
1835
+
1836
+ /**
1837
+ * Report the controlled open state of a registered sheet. Closing keeps the
1838
+ * sheet's place while it slides out; reopening takes a new rank, so the sheet
1839
+ * returns on top.
1840
+ */
1841
+ export function setBottomSheetOpen(key: object, isOpen: boolean): void {
1842
+ const entry = state.entries.find(candidate => candidate.key === key);
1843
+ if (entry == null || entry.isOpen === isOpen) {
1844
+ return;
1845
+ }
1846
+ entry.isOpen = isOpen;
1847
+ const remembered = state.rankByKey.get(key);
1848
+ if (isOpen) {
1849
+ if (state.closingTogether.has(entry)) {
1850
+ const group = state.closingTogether.get(entry);
1851
+ state.closingTogether.delete(entry);
1852
+ group?.pending.delete(entry);
1853
+ }
1854
+ entry.rank = takeRank();
1855
+ state.rankByKey.set(key, {
1856
+ ...entry.rank,
1857
+ isClosed: false,
1858
+ detachedBatch: null,
1859
+ });
1860
+ recordFlip(entry, 'opened');
1861
+ // Reopened while being replaced: it is a sheet again, not a fading one.
1862
+ if (entry.replace != null) {
1863
+ entry.replace.replacer.replacing = null;
1864
+ entry.replace = null;
1865
+ entry.isEnteringInPlace = true;
1866
+ }
1867
+ } else {
1868
+ if (remembered != null) {
1869
+ remembered.isClosed = true;
1870
+ }
1871
+ state.isBatchDirty = true;
1872
+ scheduleSeal();
1873
+ recordFlip(entry, 'closed');
1874
+ entry.isEnteringInPlace = false;
1875
+ // A replacing sheet that closes drops the sheet it was replacing, the way
1876
+ // a switcher hides a retained step when the flow is left — unless that
1877
+ // sheet is the one coming back in this same update (Continue pressed
1878
+ // during a Back handoff), which `detectReplace` pairs as the reverse
1879
+ // replace. The other flips of this commit may not have arrived yet, so
1880
+ // the drop waits for the seal; a paired sheet is no longer `replace`d by
1881
+ // then and is left alone.
1882
+ if (entry.replacing != null) {
1883
+ state.pendingDrops.push(entry.replacing);
1884
+ }
1885
+ }
1886
+ update(entry.doc, entry.isModal);
1887
+ }
1888
+
1889
+ /**
1890
+ * Drop the retained sheets whose replacer closed in this batch and that no
1891
+ * replace of this batch took back. Runs when the batch is sealed and, before
1892
+ * that, whenever a pairing has been decided, so the drop lands in the same
1893
+ * commit as the close that caused it.
1894
+ */
1895
+ function flushPendingDrops(): void {
1896
+ if (state.pendingDrops.length === 0) {
1897
+ return;
1898
+ }
1899
+ const drops = state.pendingDrops;
1900
+ state.pendingDrops = [];
1901
+ for (const replaced of drops) {
1902
+ const replacer = replaced.replace?.replacer;
1903
+ if (replacer != null && !replacer.isOpen) {
1904
+ finishReplace(replaced);
1905
+ }
1906
+ }
1907
+ }
1908
+
1909
+ /**
1910
+ * The open sheet directly beneath `key`: its dialog, and a way to move focus
1911
+ * into it. Null when nothing open is beneath. A closing top sheet asks this
1912
+ * to return focus into the sheet it reveals.
1913
+ */
1914
+ export function getBottomSheetBeneath(
1915
+ key: object,
1916
+ ): {element: HTMLDialogElement; focus: () => void} | null {
1917
+ const own = state.entries.find(entry => entry.key === key);
1918
+ if (own == null) {
1919
+ return null;
1920
+ }
1921
+ const order = groupOf(own);
1922
+ for (let below = order.indexOf(own) - 1; below >= 0; below -= 1) {
1923
+ const entry = order[below];
1924
+ const element = entry.getElement();
1925
+ if (entry.isOpen && element != null) {
1926
+ return {element, focus: () => entry.focus('reveal')};
1927
+ }
1928
+ }
1929
+ return null;
1930
+ }
1931
+
1932
+ // preventScroll on both: presenting a sheet must not scroll the page to reveal
1933
+ // what it just focused. For an autofocused field that reveal is the mobile
1934
+ // keyboard's, and it moves the document under a fixed sheet; useMobileKeyboard
1935
+ // brings the field into view within the sheet instead.
1936
+ /**
1937
+ * Move focus into a sheet panel. Focus already inside the sheet stays put:
1938
+ * on `open` the native host has normally run its own focusing steps, which
1939
+ * land on the panel (`tabindex="-1"`), so a `data-autofocus` descendant is
1940
+ * reached only where the host moved nothing (a stubbed host, or a browser
1941
+ * whose focusing steps skipped the sheet) — the released behavior. On
1942
+ * `replace` the entering step takes focus whatever its modality and whatever
1943
+ * the host did, a `data-autofocus` descendant first; on `reveal` the panel
1944
+ * itself takes focus, with a ring only after keyboard input.
1945
+ */
1946
+ export function focusSheetPanel(
1947
+ panel: HTMLElement | null,
1948
+ reason: BottomSheetFocusReason,
1949
+ isModal: boolean,
1950
+ ): void {
1951
+ if (panel == null) {
1952
+ return;
1953
+ }
1954
+ // A covered sheet takes no focus: its dialog is inert (the stack marks it
1955
+ // so, and a modal above it blocks it in the browser anyway), so a step that
1956
+ // enters beneath a sheet on top — a covered switcher flow changing step from
1957
+ // code — leaves the person where they are, in the sheet on top.
1958
+ const host = panel.closest('dialog');
1959
+ if (
1960
+ host != null &&
1961
+ (host.hasAttribute('inert') || host.getAttribute('aria-hidden') === 'true')
1962
+ ) {
1963
+ return;
1964
+ }
1965
+ // Focus already inside this sheet's own content stays put. Focus inside a
1966
+ // sheet rendered within this content (a closing nested sheet) does not
1967
+ // count: that sheet's dialog is leaving, and this one is being revealed.
1968
+ // On a replace entry the native focusing steps have just run and may have
1969
+ // put focus on the panel itself; that is not a placement, so only focus on
1970
+ // a control inside the panel (the person's, or the field this placement
1971
+ // chose) stays put.
1972
+ const activeElement = panel.ownerDocument.activeElement;
1973
+ const isInsidePanel =
1974
+ activeElement != null &&
1975
+ panel.contains(activeElement) &&
1976
+ activeElement.closest('dialog') === panel.closest('dialog');
1977
+ if (isInsidePanel && (reason !== 'replace' || activeElement !== panel)) {
1978
+ return;
1979
+ }
1980
+ if (reason === 'reveal') {
1981
+ focusForLastInput(panel);
1982
+ return;
1983
+ }
1984
+ const autofocus = panel.querySelector<HTMLElement>('[data-autofocus]');
1985
+ if (autofocus != null) {
1986
+ autofocus.focus({preventScroll: true});
1987
+ } else if (!isInsidePanel && (isModal || reason === 'replace')) {
1988
+ // A lone non-modal sheet takes no focus on open; the step replacing the
1989
+ // one the person was in does, so the keyboard stays in the flow. Focus
1990
+ // the native steps already put on the panel needs no second focus().
1991
+ panel.focus({preventScroll: true});
1992
+ }
1993
+ }
1994
+
1995
+ /** Test-only: the presented sheets' dialogs, bottom to top, with their views. */
1996
+ export function getBottomSheetStackForTests(
1997
+ doc: Document = document,
1998
+ isModal: boolean = true,
1999
+ ): ReadonlyArray<{
2000
+ element: HTMLDialogElement | null;
2001
+ isOpen: boolean;
2002
+ view: BottomSheetStackView;
2003
+ }> {
2004
+ return sortedEntries(doc, isModal).map(entry => ({
2005
+ element: entry.getElement(),
2006
+ isOpen: entry.isOpen,
2007
+ view: entry.view,
2008
+ }));
2009
+ }
2010
+
2011
+ /** Test-only: forget every sheet and start the batch counter over. */
2012
+ export function resetBottomSheetStackForTests(): void {
2013
+ showFocusesContainer = null;
2014
+ // The press listeners go with the entries they served.
2015
+ for (const entry of state.entries) {
2016
+ const remove = state.listenedDocuments.get(entry.doc);
2017
+ if (remove != null) {
2018
+ state.listenedDocuments.delete(entry.doc);
2019
+ remove();
2020
+ }
2021
+ }
2022
+ state.entries.length = 0;
2023
+ state.shownOrder = new WeakMap();
2024
+ state.batchOpened = [];
2025
+ state.batchClosed = [];
2026
+ state.batchActor = null;
2027
+ state.pendingDrops = [];
2028
+ state.pendingReplaceFocus = null;
2029
+ state.closingTogether = new Map();
2030
+ state.currentBatch = 0;
2031
+ state.nextSeq = 0;
2032
+ state.isBatchDirty = false;
2033
+ state.isSealScheduled = false;
2034
+ state.focusToKeep = new WeakMap();
2035
+ // Deferral watchers on the test document go with the deferrals they
2036
+ // served (a WeakMap cannot be walked; the test document is the one place
2037
+ // a test can have deferred into).
2038
+ const deferral = state.deferredTopLayer.get(document);
2039
+ if (deferral != null) {
2040
+ releaseDeferralWatchers(deferral);
2041
+ }
2042
+ state.deferredTopLayer = new WeakMap();
2043
+ }
2044
+
2045
+ /** Test-only: the shared state's key, shape and protocol version, for the two-copies tests. */
2046
+ export const BOTTOM_SHEET_STACK_STATE_FOR_TESTS = {
2047
+ key: STACK_STATE_KEY,
2048
+ shape: STACK_STATE_SHAPE,
2049
+ protocolVersion: STACK_PROTOCOL_VERSION,
2050
+ keyFor: (version: number) =>
2051
+ Symbol.for(`astryx.bottomSheetStack.v${version}`),
2052
+ /** Whether the document has the press listeners installed. */
2053
+ isListeningForPresses: (doc: Document) => state.listenedDocuments.has(doc),
2054
+ };