@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.
- package/CHANGELOG.md +211 -10
- package/README.md +15 -12
- package/dist/AlertDialog/AlertDialog.js +1 -1
- package/dist/AppShell/AppShell.d.ts +0 -22
- package/dist/AppShell/AppShell.d.ts.map +1 -1
- package/dist/AppShell/AppShell.js +155 -1
- package/dist/Avatar/AvatarStatusDot.js +2 -2
- package/dist/Badge/Badge.d.ts.map +1 -1
- package/dist/Badge/Badge.js +18 -2
- package/dist/Banner/Banner.d.ts +1 -0
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +64 -9
- package/dist/BottomSheet/BottomSheet.d.ts +53 -5
- package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheet.js +435 -198
- package/dist/BottomSheet/BottomSheetHostContext.d.ts +8 -0
- package/dist/BottomSheet/BottomSheetHostContext.d.ts.map +1 -0
- package/dist/BottomSheet/BottomSheetHostContext.js +35 -0
- package/dist/BottomSheet/BottomSheetPanel.d.ts +9 -1
- package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetPanel.js +77 -23
- package/dist/BottomSheet/BottomSheetSwitcher.d.ts +53 -14
- package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetSwitcher.js +229 -27
- package/dist/BottomSheet/BottomSheetSwitcherContext.d.ts +6 -0
- package/dist/BottomSheet/BottomSheetSwitcherContext.d.ts.map +1 -1
- package/dist/BottomSheet/bottomSheetEscape.d.ts +3 -0
- package/dist/BottomSheet/bottomSheetEscape.d.ts.map +1 -0
- package/dist/BottomSheet/bottomSheetEscape.js +20 -0
- package/dist/BottomSheet/bottomSheetStack.d.ts +262 -0
- package/dist/BottomSheet/bottomSheetStack.d.ts.map +1 -0
- package/dist/BottomSheet/bottomSheetStack.js +1675 -0
- package/dist/BottomSheet/useSheetGestures.d.ts +19 -3
- package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
- package/dist/BottomSheet/useSheetGestures.js +43 -14
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +36 -3
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +18 -7
- package/dist/Chat/ChatComposer.d.ts.map +1 -1
- package/dist/Chat/ChatComposer.js +25 -32
- package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
- package/dist/Chat/ChatComposerInput.js +55 -16
- package/dist/Chat/ChatMessageMetadata.js +2 -2
- package/dist/Chat/ChatPastedTextToken.d.ts.map +1 -1
- package/dist/Chat/ChatPastedTextToken.js +7 -6
- package/dist/Chat/ChatToolCalls.js +4 -4
- package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
- package/dist/ClickableCard/ClickableCard.js +10 -6
- package/dist/CodeBlock/CodeBlock.d.ts +25 -2
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +58 -19
- package/dist/CodeBlock/grammar.d.ts +134 -0
- package/dist/CodeBlock/grammar.d.ts.map +1 -0
- package/dist/CodeBlock/grammar.js +219 -0
- package/dist/CodeBlock/index.d.ts +2 -0
- package/dist/CodeBlock/index.d.ts.map +1 -1
- package/dist/CodeBlock/index.js +1 -0
- package/dist/CodeBlock/languages/dockerfile.d.ts +3 -0
- package/dist/CodeBlock/languages/dockerfile.d.ts.map +1 -0
- package/dist/CodeBlock/languages/dockerfile.js +45 -0
- package/dist/CodeBlock/languages/graphql.d.ts +3 -0
- package/dist/CodeBlock/languages/graphql.d.ts.map +1 -0
- package/dist/CodeBlock/languages/graphql.js +27 -0
- package/dist/CodeBlock/languages/java.d.ts +3 -0
- package/dist/CodeBlock/languages/java.d.ts.map +1 -0
- package/dist/CodeBlock/languages/java.js +24 -0
- package/dist/CodeBlock/languages/lua.d.ts +3 -0
- package/dist/CodeBlock/languages/lua.d.ts.map +1 -0
- package/dist/CodeBlock/languages/lua.js +21 -0
- package/dist/CodeBlock/languages/objective-c.d.ts +3 -0
- package/dist/CodeBlock/languages/objective-c.d.ts.map +1 -0
- package/dist/CodeBlock/languages/objective-c.js +27 -0
- package/dist/CodeBlock/languages/powershell.d.ts +3 -0
- package/dist/CodeBlock/languages/powershell.d.ts.map +1 -0
- package/dist/CodeBlock/languages/powershell.js +30 -0
- package/dist/CodeBlock/languages/ruby.d.ts +3 -0
- package/dist/CodeBlock/languages/ruby.d.ts.map +1 -0
- package/dist/CodeBlock/languages/ruby.js +24 -0
- package/dist/CodeBlock/languages/thrift.d.ts +3 -0
- package/dist/CodeBlock/languages/thrift.d.ts.map +1 -0
- package/dist/CodeBlock/languages/thrift.js +18 -0
- package/dist/CodeBlock/languages/toml.d.ts +3 -0
- package/dist/CodeBlock/languages/toml.d.ts.map +1 -0
- package/dist/CodeBlock/languages/toml.js +53 -0
- package/dist/CodeBlock/tokenizer.d.ts +8 -4
- package/dist/CodeBlock/tokenizer.d.ts.map +1 -1
- package/dist/CodeBlock/tokenizer.js +158 -8
- package/dist/Collapsible/Collapsible.d.ts +8 -1
- package/dist/Collapsible/Collapsible.d.ts.map +1 -1
- package/dist/Collapsible/Collapsible.js +84 -2
- package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPalette.js +15 -1
- package/dist/CommandPalette/CommandPaletteEmpty.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteEmpty.js +1 -0
- package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteInput.js +14 -2
- package/dist/CommandPalette/busyStartSettle.d.ts +4 -0
- package/dist/CommandPalette/busyStartSettle.d.ts.map +1 -0
- package/dist/CommandPalette/busyStartSettle.js +23 -0
- package/dist/ComplexSelector/ComplexSelector.d.ts +20 -2
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +42 -7
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +48 -13
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +12 -5
- package/dist/DateInput/NativeDateField.d.ts.map +1 -1
- package/dist/DateInput/NativeDateField.js +2 -1
- package/dist/DateInput/TouchDateField.d.ts.map +1 -1
- package/dist/DateInput/TouchDateField.js +2 -1
- package/dist/DateInput/Wheel.d.ts.map +1 -1
- package/dist/DateInput/Wheel.js +1 -1
- package/dist/Dialog/Dialog.d.ts +4 -0
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +20 -8
- package/dist/Drawer/Drawer.d.ts.map +1 -1
- package/dist/Drawer/Drawer.js +18 -13
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +34 -30
- package/dist/DropdownMenu/DropdownMenuGroup.d.ts +7 -4
- package/dist/DropdownMenu/DropdownMenuGroup.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuGroup.js +10 -4
- package/dist/DropdownMenu/DropdownMenuItem.js +3 -3
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +10 -5
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.js +13 -5
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +6 -6
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +0 -3
- package/dist/DropdownMenu/MenuBottomSheet.d.ts +11 -4
- package/dist/DropdownMenu/MenuBottomSheet.d.ts.map +1 -1
- package/dist/DropdownMenu/MenuBottomSheet.js +35 -9
- package/dist/DropdownMenu/MenuBottomSheetActionList.js +3 -3
- package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts +2 -0
- package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts.map +1 -1
- package/dist/DropdownMenu/lazyMenuBottomSheet.js +25 -3
- package/dist/DropdownMenu/menuBottomSheet.stylex.d.ts +23 -0
- package/dist/DropdownMenu/menuBottomSheet.stylex.d.ts.map +1 -0
- package/dist/DropdownMenu/menuBottomSheet.stylex.js +29 -0
- package/dist/DropdownMenu/menuItemHover.d.ts +3 -0
- package/dist/DropdownMenu/menuItemHover.d.ts.map +1 -1
- package/dist/DropdownMenu/menuItemHover.js +14 -1
- package/dist/DropdownMenu/menuTouchAction.stylex.d.ts +25 -0
- package/dist/DropdownMenu/menuTouchAction.stylex.d.ts.map +1 -0
- package/dist/DropdownMenu/menuTouchAction.stylex.js +29 -0
- package/dist/DropdownMenu/useMenuDrillIn.d.ts.map +1 -1
- package/dist/DropdownMenu/useMenuDrillIn.js +7 -5
- package/dist/EmptyState/EmptyState.d.ts +4 -2
- package/dist/EmptyState/EmptyState.d.ts.map +1 -1
- package/dist/EmptyState/EmptyState.js +6 -4
- package/dist/Field/Field.js +1 -1
- package/dist/Field/FieldLabel.js +1 -1
- package/dist/Field/PanelSearchInput.d.ts +9 -1
- package/dist/Field/PanelSearchInput.d.ts.map +1 -1
- package/dist/Field/PanelSearchInput.js +31 -22
- package/dist/Field/inputDisabledFocus.d.ts +14 -0
- package/dist/Field/inputDisabledFocus.d.ts.map +1 -0
- package/dist/Field/inputDisabledFocus.js +19 -0
- package/dist/Field/inputStyles.stylex.d.ts +9 -9
- package/dist/Field/inputStyles.stylex.js +9 -9
- package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
- package/dist/FieldStatus/FieldStatus.js +7 -3
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +22 -12
- package/dist/Icon/Icon.d.ts +37 -5
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Icon/Icon.js +65 -11
- package/dist/Icon/IconSize.stylex.d.ts +16 -11
- package/dist/Icon/IconSize.stylex.d.ts.map +1 -1
- package/dist/Icon/IconSize.stylex.js +27 -11
- package/dist/Icon/globalIconRegistry.d.ts +71 -4
- package/dist/Icon/globalIconRegistry.d.ts.map +1 -1
- package/dist/Icon/globalIconRegistry.js +163 -23
- package/dist/Icon/index.d.ts +26 -2
- package/dist/Icon/index.d.ts.map +1 -1
- package/dist/Icon/index.js +24 -1
- package/dist/Icon/useIcon.d.ts +5 -1
- package/dist/Icon/useIcon.d.ts.map +1 -1
- package/dist/Icon/useIcon.js +5 -1
- package/dist/InputGroup/InputGroup.d.ts +1 -1
- package/dist/InputGroup/InputGroup.d.ts.map +1 -1
- package/dist/InputGroup/InputGroup.js +46 -36
- package/dist/InputGroup/InputGroupInternalContext.d.ts +4 -0
- package/dist/InputGroup/InputGroupInternalContext.d.ts.map +1 -0
- package/dist/InputGroup/InputGroupInternalContext.js +15 -0
- package/dist/InputGroup/InputGroupText.d.ts.map +1 -1
- package/dist/InputGroup/InputGroupText.js +2 -0
- package/dist/InputGroup/groupStyles.d.ts +9 -0
- package/dist/InputGroup/groupStyles.d.ts.map +1 -1
- package/dist/InputGroup/groupStyles.js +28 -14
- package/dist/Item/Item.d.ts +5 -1
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +23 -7
- package/dist/Item/ItemMarkerColumns.a11y.chromium.spec.d.ts +2 -0
- package/dist/Item/ItemMarkerColumns.a11y.chromium.spec.d.ts.map +1 -0
- package/dist/Item/ItemMarkerColumns.a11y.chromium.spec.js +132 -0
- package/dist/Item/ItemMarkerColumnsContext.d.ts +14 -0
- package/dist/Item/ItemMarkerColumnsContext.d.ts.map +1 -0
- package/dist/Item/ItemMarkerColumnsContext.js +18 -0
- package/dist/Item/ItemSwipeLayer.d.ts.map +1 -1
- package/dist/Item/ItemSwipeLayer.js +3 -0
- package/dist/Item/useSwipeAction.d.ts.map +1 -1
- package/dist/Item/useSwipeAction.js +60 -5
- package/dist/Kbd/Kbd.d.ts +2 -2
- package/dist/Kbd/Kbd.d.ts.map +1 -1
- package/dist/Kbd/Kbd.js +18 -11
- package/dist/Layer/layerAnimations.stylex.d.ts +9 -5
- package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
- package/dist/Layer/layerAnimations.stylex.js +23 -10
- package/dist/Layer/layerSlideRules.d.ts +62 -2
- package/dist/Layer/layerSlideRules.d.ts.map +1 -1
- package/dist/Layer/layerSlideRules.js +124 -3
- package/dist/Layer/layerStack.d.ts +12 -9
- package/dist/Layer/layerStack.d.ts.map +1 -1
- package/dist/Layer/layerStack.js +116 -53
- package/dist/Layer/modalOutlet.d.ts +44 -6
- package/dist/Layer/modalOutlet.d.ts.map +1 -1
- package/dist/Layer/modalOutlet.js +150 -14
- package/dist/Layer/preserveAnimations.d.ts +11 -0
- package/dist/Layer/preserveAnimations.d.ts.map +1 -0
- package/dist/Layer/preserveAnimations.js +245 -0
- package/dist/Layer/useLayer.d.ts +19 -2
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +531 -44
- package/dist/Layer/useLayerDismissal.d.ts +10 -7
- package/dist/Layer/useLayerDismissal.d.ts.map +1 -1
- package/dist/Layer/useLayerDismissal.js +8 -8
- package/dist/Layer/useTouchTrigger.d.ts +14 -1
- package/dist/Layer/useTouchTrigger.d.ts.map +1 -1
- package/dist/Layer/useTouchTrigger.js +72 -17
- package/dist/Layout/Layout.d.ts.map +1 -1
- package/dist/Layout/Layout.js +4 -0
- package/dist/Layout/LayoutContent.d.ts.map +1 -1
- package/dist/Layout/LayoutContent.js +2 -2
- package/dist/Layout/LayoutFooter.d.ts.map +1 -1
- package/dist/Layout/LayoutFooter.js +2 -1
- package/dist/Layout/LayoutHeader.d.ts.map +1 -1
- package/dist/Layout/LayoutHeader.js +2 -1
- package/dist/Layout/layoutEdges.stylex.d.ts +20 -0
- package/dist/Layout/layoutEdges.stylex.d.ts.map +1 -0
- package/dist/Layout/layoutEdges.stylex.js +28 -0
- package/dist/Lightbox/Lightbox.d.ts +5 -2
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +111 -89
- package/dist/Lightbox/LightboxKeyboard.a11y.browser.spec.d.ts +2 -0
- package/dist/Lightbox/LightboxKeyboard.a11y.browser.spec.d.ts.map +1 -0
- package/dist/Lightbox/LightboxKeyboard.a11y.browser.spec.js +78 -0
- package/dist/Lightbox/LightboxViewport.a11y.browser.spec.d.ts +2 -0
- package/dist/Lightbox/LightboxViewport.a11y.browser.spec.d.ts.map +1 -0
- package/dist/Lightbox/LightboxViewport.a11y.browser.spec.js +65 -0
- package/dist/List/List.d.ts +2 -1
- package/dist/List/List.d.ts.map +1 -1
- package/dist/List/List.js +9 -2
- package/dist/List/ListContext.d.ts +16 -4
- package/dist/List/ListContext.d.ts.map +1 -1
- package/dist/List/ListContext.js +10 -5
- package/dist/List/ListItem.d.ts +7 -1
- package/dist/List/ListItem.d.ts.map +1 -1
- package/dist/List/ListItem.js +52 -8
- package/dist/List/ListMarkers.a11y.chromium.spec.d.ts +2 -0
- package/dist/List/ListMarkers.a11y.chromium.spec.d.ts.map +1 -0
- package/dist/List/ListMarkers.a11y.chromium.spec.js +677 -0
- package/dist/Markdown/Markdown.d.ts +11 -1
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.fr23.bench.js +3 -1
- package/dist/Markdown/Markdown.fr23.sampling.d.ts +16 -0
- package/dist/Markdown/Markdown.fr23.sampling.d.ts.map +1 -1
- package/dist/Markdown/Markdown.fr23.sampling.js +13 -4
- package/dist/Markdown/Markdown.js +41 -14
- package/dist/Markdown/MarkdownTable.a11y.chromium.spec.js +1 -0
- package/dist/MobileNav/MobileNav.d.ts +2 -1
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +46 -37
- package/dist/MobileNav/MobileNavPinchZoom.a11y.chromium.spec.js +1 -0
- package/dist/MobileNav/MobileNavToggle.d.ts +7 -3
- package/dist/MobileNav/MobileNavToggle.d.ts.map +1 -1
- package/dist/MobileNav/MobileNavToggle.js +11 -3
- package/dist/MultiSelector/CreateRow.a11y.chromium.spec.js +53 -6
- package/dist/MultiSelector/MultiSelector.d.ts +1 -1
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.disabledFocus.a11y.chromium.spec.js +1 -0
- package/dist/MultiSelector/MultiSelector.js +21 -5
- package/dist/MultiSelector/OptionActions.a11y.chromium.spec.js +1 -0
- package/dist/NavMenu/NavHeadingMenu.d.ts +1 -1
- package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
- package/dist/NavMenu/NavHeadingMenu.js +29 -5
- package/dist/NavMenu/NavHeadingMenuItem.d.ts.map +1 -1
- package/dist/NavMenu/NavHeadingMenuItem.js +51 -7
- package/dist/NavMenu/NavMenuContext.d.ts +9 -0
- package/dist/NavMenu/NavMenuContext.d.ts.map +1 -1
- package/dist/NavMenu/NavMenuContext.js +9 -0
- package/dist/NumberInput/NumberInput.d.ts +4 -4
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +61 -24
- package/dist/Overlay/Overlay.d.ts +3 -3
- package/dist/Overlay/Overlay.d.ts.map +1 -1
- package/dist/Overlay/Overlay.js +12 -5
- package/dist/Popover/Popover.d.ts +41 -2
- package/dist/Popover/Popover.d.ts.map +1 -1
- package/dist/Popover/Popover.js +276 -44
- package/dist/Popover/index.d.ts +1 -1
- package/dist/Popover/index.d.ts.map +1 -1
- package/dist/Popover/lazyPopoverBottomSheet.d.ts +23 -0
- package/dist/Popover/lazyPopoverBottomSheet.d.ts.map +1 -0
- package/dist/Popover/lazyPopoverBottomSheet.js +40 -0
- package/dist/Popover/usePopover.d.ts.map +1 -1
- package/dist/Popover/usePopover.js +11 -5
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +7 -5
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +8 -0
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +10 -2
- package/dist/ScrollableArea/ScrollableArea.d.ts.map +1 -1
- package/dist/ScrollableArea/ScrollableArea.js +1 -1
- package/dist/SegmentedControl/SegmentedControl.d.ts +1 -1
- package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControl.js +6 -2
- package/dist/SelectableCard/SelectableCard.d.ts +5 -5
- package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
- package/dist/SelectableCard/SelectableCard.js +15 -11
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +27 -8
- package/dist/Selector/hooks.d.ts +52 -6
- package/dist/Selector/hooks.d.ts.map +1 -1
- package/dist/Selector/hooks.js +145 -2
- package/dist/SideNav/SideNav.d.ts.map +1 -1
- package/dist/SideNav/SideNav.js +58 -2
- package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.js +79 -3
- package/dist/SideNav/SideNavItem.d.ts +5 -1
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +36 -13
- package/dist/SideNav/railMotion.d.ts +54 -0
- package/dist/SideNav/railMotion.d.ts.map +1 -0
- package/dist/SideNav/railMotion.js +253 -0
- package/dist/Skeleton/Skeleton.d.ts.map +1 -1
- package/dist/Skeleton/Skeleton.js +12 -3
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +52 -15
- package/dist/StatusDot/StatusDot.d.ts.map +1 -1
- package/dist/StatusDot/StatusDot.js +12 -0
- package/dist/Stepper/Step.d.ts.map +1 -1
- package/dist/Stepper/Step.js +10 -6
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +5 -5
- package/dist/Switch/switch.markers.stylex.d.ts +7 -2
- package/dist/Switch/switch.markers.stylex.d.ts.map +1 -1
- package/dist/Switch/switch.markers.stylex.js +8 -3
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +5 -1
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +25 -3
- package/dist/Table/TableCell.d.ts.map +1 -1
- package/dist/Table/TableCell.js +5 -1
- package/dist/Table/TableHeaderCell.d.ts.map +1 -1
- package/dist/Table/TableHeaderCell.js +1 -0
- package/dist/Table/TableRow.d.ts.map +1 -1
- package/dist/Table/TableRow.js +3 -0
- package/dist/Table/glidingDivider.d.ts +96 -0
- package/dist/Table/glidingDivider.d.ts.map +1 -0
- package/dist/Table/glidingDivider.js +275 -0
- package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
- package/dist/Table/plugins/columnResize/useTableColumnResize.js +11 -2
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts +8 -0
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +374 -13
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +244 -6
- package/dist/Table/rowDivider.d.ts +34 -0
- package/dist/Table/rowDivider.d.ts.map +1 -0
- package/dist/Table/rowDivider.js +118 -0
- package/dist/TextArea/TextArea.d.ts +6 -4
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +15 -12
- package/dist/TextInput/TextInput.d.ts +7 -5
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +43 -22
- package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
- package/dist/Thumbnail/Thumbnail.js +45 -11
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +12 -4
- package/dist/TimeInput/TouchTimeField.d.ts.map +1 -1
- package/dist/TimeInput/TouchTimeField.js +2 -1
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +62 -6
- package/dist/Tokenizer/Tokenizer.d.ts +71 -4
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +430 -45
- package/dist/Tokenizer/TokenizerBottomSheet.d.ts +98 -0
- package/dist/Tokenizer/TokenizerBottomSheet.d.ts.map +1 -0
- package/dist/Tokenizer/TokenizerBottomSheet.js +721 -0
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +9 -3
- package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
- package/dist/TopNav/TopNavHeading.js +26 -0
- package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenu.js +4 -4
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +32 -4
- package/dist/TreeList/TreeList.d.ts +8 -23
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +175 -3
- package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
- package/dist/TreeList/TreeListBranches.js +7 -5
- package/dist/TreeList/TreeListItem.d.ts +7 -1
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +5 -3
- package/dist/Typeahead/BaseTypeahead.d.ts +1 -1
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.emptyState.a11y.chromium.spec.d.ts +2 -0
- package/dist/Typeahead/BaseTypeahead.emptyState.a11y.chromium.spec.d.ts.map +1 -0
- package/dist/Typeahead/BaseTypeahead.emptyState.a11y.chromium.spec.js +118 -0
- package/dist/Typeahead/BaseTypeahead.js +27 -11
- package/dist/Typeahead/Typeahead.d.ts +1 -1
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +31 -14
- package/dist/astryx.css +164 -41
- package/dist/gestures/GestureArena.d.ts +175 -0
- package/dist/gestures/GestureArena.d.ts.map +1 -0
- package/dist/gestures/GestureArena.js +816 -0
- package/dist/gestures/GestureRecognizer.d.ts +239 -0
- package/dist/gestures/GestureRecognizer.d.ts.map +1 -0
- package/dist/gestures/GestureRecognizer.js +487 -0
- package/dist/gestures/LongPressGestureRecognizer.d.ts +32 -0
- package/dist/gestures/LongPressGestureRecognizer.d.ts.map +1 -0
- package/dist/gestures/LongPressGestureRecognizer.js +135 -0
- package/dist/gestures/PanGestureRecognizer.d.ts +117 -0
- package/dist/gestures/PanGestureRecognizer.d.ts.map +1 -0
- package/dist/gestures/PanGestureRecognizer.js +349 -0
- package/dist/gestures/TapGestureRecognizer.d.ts +39 -0
- package/dist/gestures/TapGestureRecognizer.d.ts.map +1 -0
- package/dist/gestures/TapGestureRecognizer.js +151 -0
- package/dist/gestures/VelocityTracker.d.ts +51 -0
- package/dist/gestures/VelocityTracker.d.ts.map +1 -0
- package/dist/gestures/VelocityTracker.js +186 -0
- package/dist/gestures/geometry.d.ts +17 -0
- package/dist/gestures/geometry.d.ts.map +1 -0
- package/dist/gestures/geometry.js +55 -0
- package/dist/gestures/types.d.ts +139 -0
- package/dist/gestures/types.d.ts.map +1 -0
- package/dist/gestures/types.js +67 -0
- package/dist/hooks/AnnounceRenderedText.d.ts +17 -0
- package/dist/hooks/AnnounceRenderedText.d.ts.map +1 -0
- package/dist/hooks/AnnounceRenderedText.js +32 -0
- package/dist/hooks/ModalAnnounceProvider.d.ts +41 -0
- package/dist/hooks/ModalAnnounceProvider.d.ts.map +1 -0
- package/dist/hooks/ModalAnnounceProvider.js +133 -0
- package/dist/hooks/actionGroupTracker.d.ts +98 -0
- package/dist/hooks/actionGroupTracker.d.ts.map +1 -0
- package/dist/hooks/actionGroupTracker.js +338 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/menuPressOnItems.d.ts +19 -0
- package/dist/hooks/menuPressOnItems.d.ts.map +1 -0
- package/dist/hooks/menuPressOnItems.js +32 -0
- package/dist/hooks/modalAnnounce.d.ts +18 -0
- package/dist/hooks/modalAnnounce.d.ts.map +1 -0
- package/dist/hooks/modalAnnounce.js +382 -0
- package/dist/hooks/scrollGeometry.d.ts +28 -0
- package/dist/hooks/scrollGeometry.d.ts.map +1 -1
- package/dist/hooks/scrollGeometry.js +36 -2
- package/dist/hooks/useAdaptivePresentation.d.ts +9 -1
- package/dist/hooks/useAdaptivePresentation.d.ts.map +1 -1
- package/dist/hooks/useAdaptivePresentation.js +33 -8
- package/dist/hooks/useAnimatedLayout.d.ts +42 -0
- package/dist/hooks/useAnimatedLayout.d.ts.map +1 -0
- package/dist/hooks/useAnimatedLayout.js +46 -0
- package/dist/hooks/useAnnounce.d.ts +132 -1
- package/dist/hooks/useAnnounce.d.ts.map +1 -1
- package/dist/hooks/useAnnounce.js +356 -27
- package/dist/hooks/useAnnounceRenderedText.d.ts +19 -2
- package/dist/hooks/useAnnounceRenderedText.d.ts.map +1 -1
- package/dist/hooks/useAnnounceRenderedText.js +52 -11
- package/dist/hooks/useBusyAnnouncement.d.ts +9 -5
- package/dist/hooks/useBusyAnnouncement.d.ts.map +1 -1
- package/dist/hooks/useBusyAnnouncement.js +58 -46
- package/dist/hooks/useFocusTrap.d.ts +1 -1
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +57 -26
- package/dist/hooks/useMenuHover.d.ts.map +1 -1
- package/dist/hooks/useMenuHover.js +6 -2
- package/dist/hooks/useMenuPress.d.ts +4 -2
- package/dist/hooks/useMenuPress.d.ts.map +1 -1
- package/dist/hooks/useMenuPress.js +58 -33
- package/dist/hooks/usePressFeedback.d.ts +5 -2
- package/dist/hooks/usePressFeedback.d.ts.map +1 -1
- package/dist/hooks/usePressFeedback.js +5 -2
- package/dist/hooks/useScrollableArea.d.ts +5 -0
- package/dist/hooks/useScrollableArea.d.ts.map +1 -1
- package/dist/hooks/useScrollableArea.js +104 -11
- package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/en.generated.js +33 -0
- package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/pseudo.generated.js +33 -0
- package/dist/internal/tokenizer-presentation.d.ts +21 -0
- package/dist/internal/tokenizer-presentation.d.ts.map +1 -0
- package/dist/internal/tokenizer-presentation.js +21 -0
- package/dist/internal/touch.d.ts +26 -0
- package/dist/internal/touch.d.ts.map +1 -0
- package/dist/internal/touch.js +28 -0
- package/dist/motion/LayoutChangeSnapshot.d.ts +33 -0
- package/dist/motion/LayoutChangeSnapshot.d.ts.map +1 -0
- package/dist/motion/LayoutChangeSnapshot.js +37 -0
- package/dist/motion/animatedLayout.d.ts +190 -0
- package/dist/motion/animatedLayout.d.ts.map +1 -0
- package/dist/motion/animatedLayout.js +1502 -0
- package/dist/motion/animator.d.ts +240 -0
- package/dist/motion/animator.d.ts.map +1 -0
- package/dist/motion/animator.js +2203 -0
- package/dist/motion/bezier.d.ts +18 -0
- package/dist/motion/bezier.d.ts.map +1 -0
- package/dist/motion/bezier.js +60 -0
- package/dist/motion/coast.d.ts +61 -0
- package/dist/motion/coast.d.ts.map +1 -0
- package/dist/motion/coast.js +107 -0
- package/dist/motion/decay.d.ts +41 -0
- package/dist/motion/decay.d.ts.map +1 -0
- package/dist/motion/decay.js +90 -0
- package/dist/motion/projection.d.ts +36 -0
- package/dist/motion/projection.d.ts.map +1 -0
- package/dist/motion/projection.js +92 -0
- package/dist/motion/reducedMotion.d.ts +25 -0
- package/dist/motion/reducedMotion.d.ts.map +1 -0
- package/dist/motion/reducedMotion.js +85 -0
- package/dist/motion/reducedMotion.stylex.d.ts +19 -0
- package/dist/motion/reducedMotion.stylex.d.ts.map +1 -0
- package/dist/motion/reducedMotion.stylex.js +37 -0
- package/dist/motion/reducedMotionPlan.d.ts +89 -0
- package/dist/motion/reducedMotionPlan.d.ts.map +1 -0
- package/dist/motion/reducedMotionPlan.js +194 -0
- package/dist/motion/resolveSnapPoint.d.ts +52 -0
- package/dist/motion/resolveSnapPoint.d.ts.map +1 -0
- package/dist/motion/resolveSnapPoint.js +135 -0
- package/dist/motion/roleValue.d.ts +33 -0
- package/dist/motion/roleValue.d.ts.map +1 -0
- package/dist/motion/roleValue.js +84 -0
- package/dist/motion/roles.d.ts +79 -0
- package/dist/motion/roles.d.ts.map +1 -0
- package/dist/motion/roles.js +199 -0
- package/dist/motion/rubberBand.d.ts +20 -0
- package/dist/motion/rubberBand.d.ts.map +1 -0
- package/dist/motion/rubberBand.js +91 -0
- package/dist/motion/selectPage.d.ts +26 -0
- package/dist/motion/selectPage.d.ts.map +1 -0
- package/dist/motion/selectPage.js +55 -0
- package/dist/motion/spring.d.ts +193 -0
- package/dist/motion/spring.d.ts.map +1 -0
- package/dist/motion/spring.js +442 -0
- package/dist/motion/transientCopy.d.ts +33 -0
- package/dist/motion/transientCopy.d.ts.map +1 -0
- package/dist/motion/transientCopy.js +314 -0
- package/dist/motion/uikit/gestures.d.ts +642 -0
- package/dist/motion/uikit/gestures.d.ts.map +1 -0
- package/dist/motion/uikit/gestures.js +428 -0
- package/dist/motion/uikit/index.d.ts +24 -0
- package/dist/motion/uikit/index.d.ts.map +1 -0
- package/dist/motion/uikit/index.js +26 -0
- package/dist/motion/uikit/navigation.d.ts +54 -0
- package/dist/motion/uikit/navigation.d.ts.map +1 -0
- package/dist/motion/uikit/navigation.js +83 -0
- package/dist/motion/uikit/scroll.d.ts +116 -0
- package/dist/motion/uikit/scroll.d.ts.map +1 -0
- package/dist/motion/uikit/scroll.js +146 -0
- package/dist/motion/uikit/springs.d.ts +545 -0
- package/dist/motion/uikit/springs.d.ts.map +1 -0
- package/dist/motion/uikit/springs.js +548 -0
- package/dist/motion/uikit/timing.d.ts +202 -0
- package/dist/motion/uikit/timing.d.ts.map +1 -0
- package/dist/motion/uikit/timing.js +201 -0
- package/dist/reset.a11y.chromium.spec.js +1 -0
- package/dist/reset.until-found.a11y.browser.spec.js +1 -0
- package/dist/theme/declarationBoundary.d.ts +13 -0
- package/dist/theme/declarationBoundary.d.ts.map +1 -1
- package/dist/theme/declarationBoundary.js +264 -1
- package/dist/theme/defineTheme.d.ts +111 -11
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/defineTheme.js +97 -7
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +9 -0
- package/dist/theme/generateThemeRules.d.ts +6 -2
- package/dist/theme/generateThemeRules.d.ts.map +1 -1
- package/dist/theme/generateThemeRules.js +468 -24
- package/dist/theme/index.d.ts +2 -2
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +1 -1
- package/dist/theme/statusColor.d.ts +48 -0
- package/dist/theme/statusColor.d.ts.map +1 -0
- package/dist/theme/statusColor.js +203 -0
- package/dist/theme/statusRoleDerivation.d.ts +11 -0
- package/dist/theme/statusRoleDerivation.d.ts.map +1 -0
- package/dist/theme/statusRoleDerivation.js +236 -0
- package/dist/theme/syntax/SyntaxTheme.d.ts +1 -1
- package/dist/theme/syntax/SyntaxTheme.js +1 -1
- package/dist/theme/syntax/defineSyntaxTheme.js +1 -1
- package/dist/theme/syntax/presets.d.ts +1 -1
- package/dist/theme/syntax/presets.js +1 -1
- package/dist/theme/syntax/tokens.d.ts +1 -1
- package/dist/theme/syntax/tokens.js +1 -1
- package/dist/theme/themeAdaptations.d.ts +25 -1
- package/dist/theme/themeAdaptations.d.ts.map +1 -1
- package/dist/theme/themeAdaptations.js +30 -1
- package/dist/theme/tokens.d.ts.map +1 -1
- package/dist/theme/tokens.js +16 -1
- package/dist/theme/tokens.stylex.d.ts +42 -2
- package/dist/theme/tokens.stylex.d.ts.map +1 -1
- package/dist/theme/tokens.stylex.js +54 -3
- package/dist/theme/useTheme.d.ts +4 -2
- package/dist/theme/useTheme.d.ts.map +1 -1
- package/dist/theme/useTheme.js +10 -4
- package/dist/utils/edgeAutoscroll.d.ts +53 -0
- package/dist/utils/edgeAutoscroll.d.ts.map +1 -0
- package/dist/utils/edgeAutoscroll.js +81 -0
- package/dist/utils/hitArea.d.ts +72 -0
- package/dist/utils/hitArea.d.ts.map +1 -0
- package/dist/utils/hitArea.js +681 -0
- package/dist/utils/interactionOverlay.stylex.d.ts +4 -1
- package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
- package/dist/utils/interactionOverlay.stylex.js +4 -1
- package/dist/utils/pressFeedback.d.ts +5 -1
- package/dist/utils/pressFeedback.d.ts.map +1 -1
- package/dist/utils/pressFeedback.js +285 -54
- package/dist/utils/pressGesture.d.ts +13 -1
- package/dist/utils/pressGesture.d.ts.map +1 -1
- package/dist/utils/pressGesture.js +40 -1
- package/dist/utils/touchPresentation.d.ts +48 -0
- package/dist/utils/touchPresentation.d.ts.map +1 -0
- package/dist/utils/touchPresentation.js +133 -0
- package/locales/af-ZA.json +1 -1
- package/locales/ar-SA.json +1 -1
- package/locales/ca-ES.json +1 -1
- package/locales/cs-CZ.json +1 -1
- package/locales/da-DK.json +1 -1
- package/locales/de-DE.json +1 -1
- package/locales/el-GR.json +1 -1
- package/locales/en.json +132 -0
- package/locales/es-ES.json +1 -1
- package/locales/fi-FI.json +1 -1
- package/locales/fr-FR.json +1 -1
- package/locales/he-IL.json +1 -1
- package/locales/hu-HU.json +1 -1
- package/locales/it-IT.json +1 -1
- package/locales/ja-JP.json +1 -1
- package/locales/ko-KR.json +1 -1
- package/locales/nl-NL.json +1 -1
- package/locales/no-NO.json +1 -1
- package/locales/pl-PL.json +1 -1
- package/locales/pseudo.json +99 -0
- package/locales/pt-BR.json +1 -1
- package/locales/pt-PT.json +1 -1
- package/locales/ro-RO.json +1 -1
- package/locales/ru-RU.json +1 -1
- package/locales/sr-SP.json +1 -1
- package/locales/sv-SE.json +1 -1
- package/locales/tr-TR.json +1 -1
- package/locales/uk-UA.json +1 -1
- package/locales/vi-VN.json +1 -1
- package/locales/zh-CN.json +1 -1
- package/locales/zh-TW.json +1 -1
- package/package.json +63 -8
- package/src/AlertDialog/AlertDialog.spec.md +85 -31
- package/src/AlertDialog/AlertDialog.tsx +1 -1
- package/src/AlertDialog/__tests__/AlertDialog.a11y.chromium.spec.ts +1 -0
- package/src/AppShell/AppShell.spec.md +334 -0
- package/src/AppShell/AppShell.tsx +170 -2
- package/src/AspectRatio/AspectRatio.spec.md +179 -0
- package/src/AspectRatio/__tests__/AspectRatioFitLayers.a11y.browser.spec.ts +1 -0
- package/src/Avatar/Avatar.spec.md +253 -0
- package/src/Avatar/AvatarStatusDot.spec.md +93 -79
- package/src/Avatar/AvatarStatusDot.test.tsx +22 -0
- package/src/Avatar/AvatarStatusDot.tsx +2 -2
- package/src/AvatarGroup/AvatarGroup.spec.md +205 -0
- package/src/AvatarGroup/AvatarGroupOverflow.spec.md +123 -120
- package/src/Badge/Badge.spec.md +207 -0
- package/src/Badge/Badge.test.tsx +13 -0
- package/src/Badge/Badge.tsx +38 -2
- package/src/Banner/Banner.spec.md +41 -28
- package/src/Banner/Banner.test.tsx +118 -16
- package/src/Banner/Banner.tsx +94 -7
- package/src/Blockquote/Blockquote.spec.md +171 -0
- package/src/BottomSheet/BottomSheet.doc.mjs +106 -24
- package/src/BottomSheet/BottomSheet.spec.md +271 -40
- package/src/BottomSheet/BottomSheet.test.tsx +491 -5
- package/src/BottomSheet/BottomSheet.tsx +544 -145
- package/src/BottomSheet/BottomSheetHostContext.ts +44 -0
- package/src/BottomSheet/BottomSheetPanel.test.tsx +73 -19
- package/src/BottomSheet/BottomSheetPanel.tsx +178 -63
- package/src/BottomSheet/BottomSheetReplace.test.tsx +1638 -0
- package/src/BottomSheet/BottomSheetStacking.announce.test.tsx +246 -0
- package/src/BottomSheet/BottomSheetStacking.test.tsx +3184 -0
- package/src/BottomSheet/BottomSheetSwitcher.doc.mjs +27 -31
- package/src/BottomSheet/BottomSheetSwitcher.spec.md +138 -43
- package/src/BottomSheet/BottomSheetSwitcher.tsx +275 -26
- package/src/BottomSheet/BottomSheetSwitcherContext.ts +6 -0
- package/src/BottomSheet/__tests__/BottomSheetDrag.a11y.chromium.spec.ts +1 -0
- package/src/BottomSheet/__tests__/BottomSheetFocusReturn.a11y.browser.spec.ts +1 -0
- package/src/BottomSheet/__tests__/BottomSheetKeyboard.a11y.browser.spec.ts +4 -1
- package/src/BottomSheet/__tests__/BottomSheetNativeModal.a11y.browser.spec.ts +1 -0
- package/src/BottomSheet/__tests__/BottomSheetPinchZoom.a11y.chromium.spec.ts +1 -0
- package/src/BottomSheet/__tests__/BottomSheetToastOutlet.a11y.chromium.spec.ts +83 -0
- package/src/BottomSheet/bottomSheetEscape.ts +21 -0
- package/src/BottomSheet/bottomSheetStack.ts +2054 -0
- package/src/BottomSheet/useSheetGestures.ts +68 -12
- package/src/Breadcrumbs/BreadcrumbItem.spec.md +104 -60
- package/src/Breadcrumbs/BreadcrumbItem.tsx +30 -1
- package/src/Breadcrumbs/Breadcrumbs.spec.md +165 -0
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +90 -0
- package/src/Breadcrumbs/__tests__/Breadcrumbs.a11y.chromium.spec.ts +1 -0
- package/src/Button/Button.spec.md +322 -0
- package/src/Button/Button.test.tsx +8 -1
- package/src/Button/Button.tsx +36 -7
- package/src/Button/__tests__/Button.a11y.chromium.spec.ts +1 -0
- package/src/ButtonGroup/ButtonGroup.spec.md +220 -0
- package/src/Calendar/__tests__/Calendar.a11y.chromium.spec.ts +1 -0
- package/src/Card/Card.spec.md +205 -0
- package/src/Carousel/__tests__/Carousel.a11y.chromium.spec.ts +1 -0
- package/src/Center/Center.spec.md +104 -124
- package/src/Chat/ChatComposer.test.tsx +54 -0
- package/src/Chat/ChatComposer.tsx +41 -27
- package/src/Chat/ChatComposerInput.test.tsx +165 -21
- package/src/Chat/ChatComposerInput.tsx +73 -16
- package/src/Chat/ChatMessageMetadata.tsx +1 -1
- package/src/Chat/ChatPastedTextToken.test.tsx +71 -0
- package/src/Chat/ChatPastedTextToken.tsx +8 -7
- package/src/Chat/ChatToolCalls.tsx +5 -5
- package/src/Chat/__tests__/ChatLayoutScrollButton.a11y.chromium.spec.ts +22 -4
- package/src/Chat/__tests__/ChatLayoutScrollButtonSurface.a11y.chromium.spec.ts +1 -0
- package/src/Chat/__tests__/ChatMessageList.a11y.chromium.spec.ts +1 -0
- package/src/Chat/__tests__/ChatMessageMetadata.a11y.chromium.spec.ts +1 -0
- package/src/Chat/__tests__/ChatSendButton.a11y.chromium.spec.ts +1 -0
- package/src/Chat/__tests__/ChatSystemMessage.a11y.chromium.spec.ts +1 -0
- package/src/Chat/__tests__/ChatTokenizedText.a11y.chromium.spec.ts +1 -0
- package/src/Chat/__tests__/useChatStreamScroll.a11y.chromium.spec.ts +1 -0
- package/src/CheckboxInput/CheckboxInput.spec.md +97 -66
- package/src/CheckboxInput/__tests__/Checkbox.a11y.chromium.spec.ts +1 -0
- package/src/CheckboxList/CheckboxList.spec.md +92 -78
- package/src/CheckboxList/CheckboxListItem.spec.md +86 -60
- package/src/CheckboxList/__tests__/CheckboxList.a11y.chromium.spec.ts +1 -0
- package/src/ClickableCard/ClickableCard.doc.mjs +1 -2
- package/src/ClickableCard/ClickableCard.spec.md +124 -128
- package/src/ClickableCard/ClickableCard.test.tsx +14 -3
- package/src/ClickableCard/ClickableCard.tsx +44 -28
- package/src/Code/Code.spec.md +30 -32
- package/src/CodeBlock/CodeBlock.doc.mjs +21 -4
- package/src/CodeBlock/CodeBlock.spec.md +96 -61
- package/src/CodeBlock/CodeBlock.test.tsx +97 -1
- package/src/CodeBlock/CodeBlock.tsx +132 -22
- package/src/CodeBlock/CodeLanguage.test.tsx +173 -0
- package/src/CodeBlock/__tests__/CodeBlockCopyClearance.a11y.chromium.spec.ts +290 -0
- package/src/CodeBlock/__tests__/CodeBlockLanguages.a11y.chromium.spec.ts +64 -0
- package/src/CodeBlock/__tests__/CodeBlockOverflowStop.a11y.chromium.spec.ts +1 -0
- package/src/CodeBlock/__tests__/DiffRowPaint.a11y.chromium.spec.ts +1 -0
- package/src/CodeBlock/grammar.ts +291 -0
- package/src/CodeBlock/index.ts +7 -0
- package/src/CodeBlock/languages/dockerfile.ts +43 -0
- package/src/CodeBlock/languages/graphql.ts +30 -0
- package/src/CodeBlock/languages/java.ts +28 -0
- package/src/CodeBlock/languages/lua.ts +21 -0
- package/src/CodeBlock/languages/objective-c.ts +26 -0
- package/src/CodeBlock/languages/powershell.ts +31 -0
- package/src/CodeBlock/languages/ruby.ts +29 -0
- package/src/CodeBlock/languages/thrift.ts +32 -0
- package/src/CodeBlock/languages/toml.ts +36 -0
- package/src/CodeBlock/languages.test.ts +402 -0
- package/src/CodeBlock/tokenizer.ts +176 -16
- package/src/CodeBlock/tokenizerBudget.test.ts +112 -0
- package/src/Collapsible/Collapsible.doc.mjs +6 -0
- package/src/Collapsible/Collapsible.spec.md +26 -23
- package/src/Collapsible/Collapsible.tsx +121 -2
- package/src/Collapsible/__tests__/Collapsible.a11y.chromium.spec.ts +1 -0
- package/src/Collapsible/__tests__/CollapsibleGroup.a11y.chromium.spec.ts +1 -0
- package/src/Collapsible/__tests__/CollapsibleGroupAccordion.a11y.chromium.spec.ts +1 -0
- package/src/CommandPalette/CommandPalette.perf.test.ts +8 -4
- package/src/CommandPalette/CommandPalette.tsx +17 -1
- package/src/CommandPalette/CommandPaletteEmpty.doc.mjs +6 -3
- package/src/CommandPalette/CommandPaletteEmpty.spec.md +190 -0
- package/src/CommandPalette/CommandPaletteEmpty.tsx +4 -0
- package/src/CommandPalette/CommandPaletteInput.tsx +21 -2
- package/src/CommandPalette/__tests__/CommandPalette.a11y.chromium.spec.ts +1 -0
- package/src/CommandPalette/__tests__/CommandPaletteEmptyAudit.a11y.chromium.spec.ts +715 -0
- package/src/CommandPalette/__tests__/CommandPaletteFooter.a11y.chromium.spec.ts +3 -2
- package/src/CommandPalette/__tests__/CommandPaletteInputAudit.a11y.chromium.spec.ts +1 -0
- package/src/CommandPalette/__tests__/CommandPaletteItemAudit.a11y.chromium.spec.ts +1 -0
- package/src/CommandPalette/busyStartSettle.ts +26 -0
- package/src/ComplexSelector/ComplexSelector.doc.mjs +1 -1
- package/src/ComplexSelector/ComplexSelector.focusableDisabled.test.tsx +1 -1
- package/src/ComplexSelector/ComplexSelector.fr10.test.tsx +9 -9
- package/src/ComplexSelector/ComplexSelector.spec.md +161 -107
- package/src/ComplexSelector/ComplexSelector.test.tsx +236 -17
- package/src/ComplexSelector/ComplexSelector.tsx +69 -4
- package/src/ComplexSelector/__tests__/ComplexSelector.a11y.chromium.spec.ts +965 -0
- package/src/ContextMenu/ContextMenu.doc.mjs +1 -1
- package/src/ContextMenu/ContextMenu.spec.md +38 -30
- package/src/ContextMenu/ContextMenu.test.tsx +189 -11
- package/src/ContextMenu/ContextMenu.tsx +75 -17
- package/src/ContextMenu/__tests__/ContextMenuAudit.a11y.chromium.spec.ts +1 -0
- package/src/ContextMenu/__tests__/ContextMenuCursorAnchor.a11y.browser.spec.ts +1 -0
- package/src/ContextMenu/__tests__/ContextMenuLongPress.a11y.chromium.spec.ts +117 -0
- package/src/DateInput/DateInput.tsx +9 -4
- package/src/DateInput/DateInputTouch.test.tsx +10 -1
- package/src/DateInput/NativeDateField.tsx +2 -1
- package/src/DateInput/TouchDateField.tsx +2 -1
- package/src/DateInput/Wheel.tsx +4 -1
- package/src/DateInput/__tests__/DateInputAudit.a11y.chromium.spec.ts +1 -0
- package/src/DateInput/__tests__/WheelPinchZoom.a11y.chromium.spec.ts +171 -0
- package/src/Dialog/Dialog.doc.mjs +201 -47
- package/src/Dialog/Dialog.spec.md +20 -4
- package/src/Dialog/Dialog.tsx +37 -10
- package/src/Dialog/__tests__/Dialog.a11y.browser.spec.ts +1 -0
- package/src/Dialog/__tests__/Dialog.a11y.chromium.spec.ts +1 -0
- package/src/Dialog/__tests__/Dialog.reduced-motion.a11y.browser.spec.ts +252 -0
- package/src/Divider/Divider.spec.md +79 -70
- package/src/Drawer/Drawer.tsx +38 -35
- package/src/Drawer/__tests__/DrawerAudit.a11y.chromium.spec.ts +1 -0
- package/src/Drawer/__tests__/DrawerHeaderAudit.a11y.chromium.spec.ts +1 -0
- package/src/DropdownMenu/DropdownMenu.spec.md +14 -6
- package/src/DropdownMenu/DropdownMenu.ssr.test.tsx +44 -8
- package/src/DropdownMenu/DropdownMenu.test.tsx +107 -5
- package/src/DropdownMenu/DropdownMenu.tsx +51 -34
- package/src/DropdownMenu/DropdownMenuGroup.doc.mjs +2 -2
- package/src/DropdownMenu/DropdownMenuGroup.tsx +12 -6
- package/src/DropdownMenu/DropdownMenuItem.tsx +5 -5
- package/src/DropdownMenu/DropdownMenuRadioItem.doc.mjs +5 -2
- package/src/DropdownMenu/DropdownMenuRadioItem.spec.md +226 -0
- package/src/DropdownMenu/DropdownMenuRadioItem.tsx +32 -16
- package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +158 -0
- package/src/DropdownMenu/DropdownMenuSheetFirstOpen.test.tsx +72 -0
- package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +9 -0
- package/src/DropdownMenu/DropdownMenuSubMenu.spec.md +225 -0
- package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +105 -0
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +6 -6
- package/src/DropdownMenu/MenuBottomSheet.tsx +42 -7
- package/src/DropdownMenu/MenuBottomSheetActionList.tsx +3 -3
- package/src/DropdownMenu/__tests__/DropdownMenuDividerAudit.a11y.chromium.spec.ts +1 -0
- package/src/DropdownMenu/__tests__/DropdownMenuDrillIn.a11y.chromium.spec.ts +1 -0
- package/src/DropdownMenu/__tests__/DropdownMenuFocusReturn.a11y.browser.spec.ts +1 -0
- package/src/DropdownMenu/__tests__/DropdownMenuGroupAudit.a11y.chromium.spec.ts +1 -0
- package/src/DropdownMenu/__tests__/DropdownMenuItemAudit.a11y.chromium.spec.ts +1 -0
- package/src/DropdownMenu/__tests__/DropdownMenuRadioGroupAudit.a11y.chromium.spec.ts +1 -0
- package/src/DropdownMenu/__tests__/DropdownMenuRadioItemAudit.a11y.chromium.spec.ts +540 -0
- package/src/DropdownMenu/__tests__/DropdownMenuSubMenuAudit.a11y.chromium.spec.ts +671 -0
- package/src/DropdownMenu/__tests__/Menu.a11y.chromium.spec.ts +1 -0
- package/src/DropdownMenu/__tests__/MenuButton.a11y.chromium.spec.ts +1 -0
- package/src/DropdownMenu/__tests__/MenuHeaderFooter.a11y.chromium.spec.ts +1 -0
- package/src/DropdownMenu/__tests__/MenuHoverFocus.a11y.chromium.spec.ts +238 -0
- package/src/DropdownMenu/__tests__/MenuPinchZoom.a11y.chromium.spec.ts +1 -0
- package/src/DropdownMenu/__tests__/MenuPress.a11y.chromium.spec.ts +1 -0
- package/src/DropdownMenu/__tests__/SubMenuHeaderFooter.a11y.chromium.spec.ts +1 -0
- package/src/DropdownMenu/lazyMenuBottomSheet.ts +28 -2
- package/src/DropdownMenu/menuBottomSheet.stylex.ts +33 -0
- package/src/DropdownMenu/menuItemHover.ts +13 -1
- package/src/DropdownMenu/menuTouchAction.stylex.ts +28 -0
- package/src/DropdownMenu/modules/useMenuPress.spec.md +90 -62
- package/src/DropdownMenu/useMenuDrillIn.tsx +7 -5
- package/src/EmptyState/EmptyState.announce.test.tsx +227 -0
- package/src/EmptyState/EmptyState.doc.mjs +1 -1
- package/src/EmptyState/EmptyState.spec.md +22 -14
- package/src/EmptyState/EmptyState.test.tsx +8 -8
- package/src/EmptyState/EmptyState.tsx +7 -5
- package/src/Field/Field.spec.md +57 -48
- package/src/Field/Field.tsx +1 -1
- package/src/Field/FieldLabel.spec.md +70 -59
- package/src/Field/FieldLabel.tsx +1 -1
- package/src/Field/PanelSearchInput.tsx +23 -13
- package/src/Field/__tests__/FieldLabelAudit.a11y.chromium.spec.ts +1 -0
- package/src/Field/inputDisabledFocus.ts +28 -0
- package/src/Field/inputStyles.stylex.ts +15 -15
- package/src/FieldStatus/FieldStatus.test.tsx +12 -0
- package/src/FieldStatus/FieldStatus.tsx +12 -3
- package/src/FieldStatus/__tests__/StatusMessage.a11y.chromium.spec.ts +1 -0
- package/src/FileInput/FileInput.doc.mjs +1 -1
- package/src/FileInput/FileInput.test.tsx +102 -0
- package/src/FileInput/FileInput.tsx +18 -12
- package/src/FormLayout/FormLayout.spec.md +69 -51
- package/src/Grid/Grid.spec.md +72 -69
- package/src/Grid/GridSpan.spec.md +158 -0
- package/src/Heading/Heading.spec.md +198 -0
- package/src/HoverCard/HoverCard.spec.md +244 -0
- package/src/HoverCard/HoverCard.test.tsx +93 -3
- package/src/Icon/Icon.doc.mjs +67 -5
- package/src/Icon/Icon.test.tsx +548 -9
- package/src/Icon/Icon.tsx +79 -15
- package/src/Icon/IconSize.stylex.ts +27 -11
- package/src/Icon/globalIconRegistry.test.tsx +395 -3
- package/src/Icon/globalIconRegistry.tsx +184 -36
- package/src/Icon/index.ts +29 -1
- package/src/Icon/useIcon.ts +5 -1
- package/src/IconButton/IconButton.spec.md +197 -0
- package/src/IconButton/IconButton.test.tsx +5 -2
- package/src/InputGroup/InputGroup.spec.md +199 -0
- package/src/InputGroup/InputGroup.test.tsx +120 -0
- package/src/InputGroup/InputGroup.tsx +59 -52
- package/src/InputGroup/InputGroupInternalContext.ts +15 -0
- package/src/InputGroup/InputGroupText.spec.md +139 -0
- package/src/InputGroup/InputGroupText.tsx +2 -0
- package/src/InputGroup/groupStyles.ts +22 -11
- package/src/Item/Item.test.tsx +158 -1
- package/src/Item/Item.tsx +42 -7
- package/src/Item/ItemMarkerColumns.a11y.chromium.spec.ts +211 -0
- package/src/Item/ItemMarkerColumnsContext.tsx +20 -0
- package/src/Item/ItemSwipeLayer.tsx +9 -0
- package/src/Item/__tests__/ItemSwipeActions.a11y.chromium.spec.ts +1 -0
- package/src/Item/__tests__/ItemSwipePinchZoom.a11y.chromium.spec.ts +186 -0
- package/src/Item/useSwipeAction.ts +71 -5
- package/src/Kbd/Kbd.test.tsx +95 -0
- package/src/Kbd/Kbd.tsx +30 -23
- package/src/Layer/LayerProvider.spec.md +149 -0
- package/src/Layer/__tests__/LayerReducedMotion.a11y.chromium.spec.ts +176 -0
- package/src/Layer/__tests__/TouchTrigger.a11y.chromium.spec.ts +200 -0
- package/src/Layer/layerAnimations.stylex.ts +22 -2
- package/src/Layer/layerDismissalInvariants.test.tsx +9 -0
- package/src/Layer/layerSlideRules.ts +141 -8
- package/src/Layer/layerStack.ts +129 -62
- package/src/Layer/modalOutlet.ts +156 -15
- package/src/Layer/preserveAnimations.ts +304 -0
- package/src/Layer/useLayer.doc.mjs +1 -1
- package/src/Layer/useLayer.test.tsx +850 -0
- package/src/Layer/useLayer.tsx +644 -58
- package/src/Layer/useLayerDismissal.test.tsx +85 -2
- package/src/Layer/useLayerDismissal.ts +12 -9
- package/src/Layer/useTouchTrigger.ts +95 -41
- package/src/Layout/Layout.tsx +18 -0
- package/src/Layout/LayoutContent.tsx +5 -14
- package/src/Layout/LayoutFooter.tsx +2 -0
- package/src/Layout/LayoutHeader.tsx +2 -0
- package/src/Layout/__tests__/Layout.a11y.chromium.spec.ts +1 -0
- package/src/Layout/layoutEdges.stylex.ts +25 -0
- package/src/Lightbox/Lightbox.spec.md +9 -8
- package/src/Lightbox/Lightbox.test.tsx +83 -0
- package/src/Lightbox/Lightbox.tsx +149 -125
- package/src/Lightbox/LightboxKeyboard.a11y.browser.spec.ts +78 -0
- package/src/Lightbox/LightboxViewport.a11y.browser.spec.ts +70 -0
- package/src/Link/Link.spec.md +229 -0
- package/src/Link/LinkProvider.spec.md +167 -0
- package/src/Link/__tests__/Link.a11y.chromium.spec.ts +1 -0
- package/src/Link/__tests__/Link.navigation.a11y.chromium.spec.ts +1 -0
- package/src/List/List.spec.md +113 -34
- package/src/List/List.tsx +13 -1
- package/src/List/ListContext.tsx +19 -5
- package/src/List/ListItem.doc.mjs +3 -3
- package/src/List/ListItem.tsx +97 -28
- package/src/List/ListMarkers.a11y.chromium.spec.ts +904 -0
- package/src/Markdown/Markdown.codeLanguages.test.tsx +137 -0
- package/src/Markdown/Markdown.doc.mjs +12 -0
- package/src/Markdown/Markdown.fr23.bench.ts +3 -1
- package/src/Markdown/Markdown.fr23.perf.test.ts +45 -3
- package/src/Markdown/Markdown.fr23.sampling.ts +13 -4
- package/src/Markdown/Markdown.spec.md +71 -59
- package/src/Markdown/Markdown.test.tsx +50 -0
- package/src/Markdown/Markdown.tsx +61 -8
- package/src/Markdown/MarkdownTable.a11y.chromium.spec.ts +1 -0
- package/src/Markdown/__tests__/MarkdownNesting.a11y.chromium.spec.ts +1 -0
- package/src/MobileNav/MobileNav.doc.mjs +2 -2
- package/src/MobileNav/MobileNav.spec.md +161 -64
- package/src/MobileNav/MobileNav.test.tsx +27 -10
- package/src/MobileNav/MobileNav.tsx +51 -38
- package/src/MobileNav/MobileNavPinchZoom.a11y.chromium.spec.ts +1 -0
- package/src/MobileNav/MobileNavToggle.test.tsx +63 -0
- package/src/MobileNav/MobileNavToggle.tsx +13 -5
- package/src/MobileNav/__tests__/MobileNavWidth.a11y.chromium.spec.ts +103 -0
- package/src/MoreMenu/MoreMenu.doc.mjs +2 -2
- package/src/MoreMenu/MoreMenu.spec.md +88 -53
- package/src/MultiSelector/CreateRow.a11y.chromium.spec.ts +67 -9
- package/src/MultiSelector/MultiSelector.disabledFocus.a11y.chromium.spec.ts +1 -0
- package/src/MultiSelector/MultiSelector.test.tsx +122 -10
- package/src/MultiSelector/MultiSelector.tsx +24 -4
- package/src/MultiSelector/OptionActions.a11y.chromium.spec.ts +1 -0
- package/src/MultiSelector/__tests__/MultiSelector.a11y.chromium.spec.ts +1 -0
- package/src/NavIcon/NavIcon.spec.md +66 -38
- package/src/NavMenu/NavHeadingMenu.spec.md +104 -46
- package/src/NavMenu/NavHeadingMenu.test.tsx +276 -2
- package/src/NavMenu/NavHeadingMenu.tsx +42 -4
- package/src/NavMenu/NavHeadingMenuItem.tsx +60 -6
- package/src/NavMenu/NavMenuContext.tsx +11 -0
- package/src/NavMenu/__tests__/NavMenusSlideSelection.a11y.chromium.spec.ts +137 -0
- package/src/NumberInput/NumberInput.doc.mjs +6 -6
- package/src/NumberInput/NumberInput.spec.md +248 -0
- package/src/NumberInput/NumberInput.test.tsx +187 -14
- package/src/NumberInput/NumberInput.tsx +86 -24
- package/src/NumberInput/__tests__/NumberInput.a11y.chromium.spec.ts +1 -0
- package/src/Overlay/Overlay.doc.mjs +2 -2
- package/src/Overlay/Overlay.test.tsx +72 -4
- package/src/Overlay/Overlay.tsx +18 -8
- package/src/Pagination/Pagination.test.tsx +2 -2
- package/src/Popover/Popover.doc.mjs +38 -2
- package/src/Popover/Popover.spec.md +90 -11
- package/src/Popover/Popover.test.tsx +340 -2
- package/src/Popover/Popover.tsx +401 -35
- package/src/Popover/PopoverPresentation.test.tsx +952 -0
- package/src/Popover/__tests__/PopoverSecondDocument.a11y.chromium.spec.ts +205 -0
- package/src/Popover/index.ts +5 -1
- package/src/Popover/lazyPopoverBottomSheet.ts +57 -0
- package/src/Popover/usePopover.tsx +11 -5
- package/src/PowerSearch/PowerSearch.spec.md +423 -53
- package/src/PowerSearch/PowerSearch.test.tsx +77 -1
- package/src/PowerSearch/PowerSearch.tsx +7 -5
- package/src/ProgressBar/ProgressBar.test.tsx +12 -0
- package/src/ProgressBar/ProgressBar.tsx +18 -0
- package/src/ProgressBar/__tests__/ProgressBar.a11y.chromium.spec.ts +1 -0
- package/src/RadioList/RadioList.spec.md +227 -0
- package/src/RadioList/RadioList.test.tsx +34 -7
- package/src/RadioList/RadioListItem.press.source-build.test.mjs +80 -0
- package/src/RadioList/RadioListItem.spec.md +223 -0
- package/src/RadioList/RadioListItem.tsx +26 -12
- package/src/RadioList/__tests__/RadioGroup.a11y.chromium.spec.ts +1 -0
- package/src/Resizable/__tests__/ResizeHandle.a11y.chromium.spec.ts +1 -0
- package/src/ScrollableArea/ScrollableArea.spec.md +6 -5
- package/src/ScrollableArea/ScrollableArea.test.tsx +5 -0
- package/src/ScrollableArea/ScrollableArea.tsx +4 -0
- package/src/Section/Section.spec.md +102 -44
- package/src/SegmentedControl/SegmentedControl.spec.md +162 -53
- package/src/SegmentedControl/SegmentedControl.test.tsx +46 -0
- package/src/SegmentedControl/SegmentedControl.tsx +7 -3
- package/src/SegmentedControl/SegmentedControlItem.spec.md +206 -0
- package/src/SelectableCard/SelectableCard.doc.mjs +7 -6
- package/src/SelectableCard/SelectableCard.spec.md +230 -0
- package/src/SelectableCard/SelectableCard.test.tsx +11 -1
- package/src/SelectableCard/SelectableCard.tsx +49 -33
- package/src/Selector/Selector.sheetActiveDescendant.test.tsx +95 -0
- package/src/Selector/Selector.spec.md +12 -4
- package/src/Selector/Selector.test.tsx +114 -8
- package/src/Selector/Selector.tsx +30 -6
- package/src/Selector/__tests__/ComboboxField.a11y.chromium.spec.ts +458 -0
- package/src/Selector/__tests__/EmptyStateAnnouncement.a11y.chromium.spec.ts +1 -0
- package/src/Selector/__tests__/Listbox.a11y.chromium.spec.ts +1 -0
- package/src/Selector/__tests__/Selector.a11y.chromium.spec.ts +1 -0
- package/src/Selector/__tests__/Selector.combobox.a11y.chromium.spec.ts +1 -0
- package/src/Selector/hooks.ts +234 -10
- package/src/Selector/useCombobox.doc.mjs +156 -9
- package/src/Selector/useCombobox.public.test.tsx +89 -0
- package/src/Selector/useCombobox.test.tsx +444 -0
- package/src/SideNav/SideNav.spec.md +50 -30
- package/src/SideNav/SideNav.test.tsx +425 -25
- package/src/SideNav/SideNav.tsx +85 -1
- package/src/SideNav/SideNavCollapseButton.spec.md +161 -0
- package/src/SideNav/SideNavHeading.spec.md +226 -0
- package/src/SideNav/SideNavHeading.tsx +102 -6
- package/src/SideNav/SideNavItem.spec.md +246 -0
- package/src/SideNav/SideNavItem.tsx +40 -9
- package/src/SideNav/SideNavRailMotion.test.tsx +620 -0
- package/src/SideNav/SideNavSection.spec.md +153 -0
- package/src/SideNav/__tests__/SideNavRailMotion.interaction.browser.spec.ts +417 -0
- package/src/SideNav/railMotion.ts +315 -0
- package/src/Skeleton/Skeleton.spec.md +99 -42
- package/src/Skeleton/Skeleton.test.tsx +108 -1
- package/src/Skeleton/Skeleton.tsx +30 -2
- package/src/Slider/Slider.fr10.test.tsx +34 -0
- package/src/Slider/Slider.test.tsx +172 -0
- package/src/Slider/Slider.tsx +70 -14
- package/src/Slider/__tests__/Slider.a11y.chromium.spec.ts +1 -0
- package/src/Spinner/Spinner.spec.md +231 -0
- package/src/Stack/Stack.spec.md +104 -56
- package/src/StatusDot/StatusDot.spec.md +139 -51
- package/src/StatusDot/StatusDot.test.tsx +13 -0
- package/src/StatusDot/StatusDot.tsx +27 -0
- package/src/Stepper/Step.spec.md +206 -0
- package/src/Stepper/Step.tsx +19 -3
- package/src/Stepper/Stepper.test.tsx +50 -0
- package/src/Switch/Switch.focusRing.source-build.test.mjs +81 -0
- package/src/Switch/Switch.spec.md +150 -66
- package/src/Switch/Switch.tsx +11 -9
- package/src/Switch/__tests__/Switch.a11y.chromium.spec.ts +1 -0
- package/src/Switch/switch.markers.stylex.ts +7 -2
- package/src/TabList/Tab.spec.md +201 -0
- package/src/TabList/Tab.tsx +7 -1
- package/src/TabList/TabList.doc.mjs +3 -3
- package/src/TabList/TabList.test.tsx +27 -0
- package/src/TabList/TabMenu.spec.md +198 -0
- package/src/TabList/TabMenu.tsx +24 -1
- package/src/TabList/__tests__/TabListOverflow.interaction.browser.spec.ts +99 -0
- package/src/TabList/__tests__/Tabs.a11y.chromium.spec.ts +1 -0
- package/src/Table/Table.spec.md +54 -30
- package/src/Table/TableCell.tsx +9 -0
- package/src/Table/TableHeaderCell.tsx +2 -0
- package/src/Table/TableRow.tsx +3 -0
- package/src/Table/__tests__/Table.a11y.chromium.spec.ts +129 -0
- package/src/Table/__tests__/Table.a11y.contracts.ts +35 -0
- package/src/Table/__tests__/Table.a11y.renders.tsx +112 -0
- package/src/Table/__tests__/Table.a11y.states.ts +140 -0
- package/src/Table/__tests__/Table.a11y.test.tsx +198 -0
- package/src/Table/__tests__/TableMinWidth.a11y.chromium.spec.ts +1 -0
- package/src/Table/__tests__/TableRowGlide.a11y.browser.spec.ts +382 -0
- package/src/Table/__tests__/TableScroll.a11y.chromium.spec.ts +1 -0
- package/src/Table/__tests__/TableStickyDividers.a11y.browser.spec.ts +560 -0
- package/src/Table/glidingDivider.ts +336 -0
- package/src/Table/plugins/columnResize/useTableColumnResize.tsx +23 -8
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.glide.test.tsx +280 -0
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +91 -9
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +471 -10
- package/src/Table/plugins/rowStatus/useTableRowStatus.spec.md +4 -4
- package/src/Table/plugins/sortable/__tests__/useTableSortable.a11y.test.tsx +174 -0
- package/src/Table/plugins/sortable/__tests__/useTableSortable.a11y.ts +86 -0
- package/src/Table/plugins/sortable/useTableSortable.test.tsx +0 -12
- package/src/Table/plugins/stickyColumns/useTableStickyColumns.test.tsx +51 -1
- package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +312 -12
- package/src/Table/rowDivider.ts +154 -0
- package/src/Table/useTableRowExpansion.doc.mjs +8 -0
- package/src/Text/Text.spec.md +114 -127
- package/src/TextArea/TextArea.doc.mjs +6 -6
- package/src/TextArea/TextArea.spec.md +164 -64
- package/src/TextArea/TextArea.test.tsx +65 -6
- package/src/TextArea/TextArea.tsx +27 -15
- package/src/TextInput/TextInput.doc.mjs +8 -8
- package/src/TextInput/TextInput.spec.md +260 -0
- package/src/TextInput/TextInput.test.tsx +126 -10
- package/src/TextInput/TextInput.tsx +57 -23
- package/src/TextInput/__tests__/TextInput.a11y.chromium.spec.ts +1 -0
- package/src/Thumbnail/Thumbnail.doc.mjs +1 -2
- package/src/Thumbnail/Thumbnail.spec.md +244 -0
- package/src/Thumbnail/Thumbnail.test.tsx +120 -7
- package/src/Thumbnail/Thumbnail.tsx +77 -31
- package/src/TimeInput/TimeInput.spec.md +273 -0
- package/src/TimeInput/TimeInput.tsx +12 -4
- package/src/TimeInput/TouchTimeField.tsx +2 -1
- package/src/Timestamp/Timestamp.spec.md +252 -0
- package/src/Toast/Toast.spec.md +300 -0
- package/src/Toast/ToastViewport.modalHost.test.tsx +630 -5
- package/src/Toast/ToastViewport.test.tsx +137 -0
- package/src/Toast/ToastViewport.tsx +63 -6
- package/src/ToggleButton/ToggleButton.spec.md +256 -0
- package/src/ToggleButton/ToggleButtonGroup.spec.md +195 -0
- package/src/ToggleButton/__tests__/ToggleButton.a11y.chromium.spec.ts +1 -0
- package/src/Token/Token.spec.md +271 -0
- package/src/Token/__tests__/TokenRemoveTarget.a11y.chromium.spec.ts +1 -0
- package/src/Tokenizer/Tokenizer.props-type.test.tsx +126 -0
- package/src/Tokenizer/Tokenizer.spec.md +313 -72
- package/src/Tokenizer/Tokenizer.ssr.test.tsx +196 -0
- package/src/Tokenizer/Tokenizer.test.tsx +44 -8
- package/src/Tokenizer/Tokenizer.tsx +586 -41
- package/src/Tokenizer/TokenizerBottomSheet.test.tsx +2719 -0
- package/src/Tokenizer/TokenizerBottomSheet.tsx +957 -0
- package/src/Tokenizer/__tests__/TokenizerEndLane.a11y.chromium.spec.ts +61 -27
- package/src/Toolbar/Toolbar.spec.md +103 -49
- package/src/Toolbar/__tests__/Toolbar.a11y.chromium.spec.ts +1 -0
- package/src/Tooltip/Tooltip.spec.md +161 -36
- package/src/Tooltip/Tooltip.test.tsx +171 -3
- package/src/Tooltip/__tests__/Tooltip.a11y.chromium.spec.ts +1 -0
- package/src/Tooltip/__tests__/Tooltip.a11y.states.ts +2 -2
- package/src/Tooltip/__tests__/TooltipFocusReturn.a11y.chromium.spec.ts +1 -0
- package/src/Tooltip/__tests__/TooltipHoverBridge.a11y.chromium.spec.ts +1 -0
- package/src/Tooltip/__tests__/TooltipTallContent.a11y.browser.spec.ts +673 -0
- package/src/Tooltip/__tests__/TooltipTallContentTracking.a11y.browser.spec.ts +1162 -0
- package/src/Tooltip/useTooltip.tsx +7 -2
- package/src/TopNav/TopNav.spec.md +190 -0
- package/src/TopNav/TopNav.test.tsx +89 -0
- package/src/TopNav/TopNavHeading.spec.md +211 -0
- package/src/TopNav/TopNavHeading.tsx +35 -2
- package/src/TopNav/TopNavItem.spec.md +189 -0
- package/src/TopNav/TopNavMegaMenu.reduced-motion.source-build.test.mjs +83 -0
- package/src/TopNav/TopNavMegaMenu.spec.md +190 -0
- package/src/TopNav/TopNavMegaMenu.tsx +21 -4
- package/src/TopNav/TopNavMegaMenuFeaturedCard.spec.md +150 -0
- package/src/TopNav/TopNavMegaMenuItem.spec.md +155 -0
- package/src/TopNav/TopNavMenu.spec.md +202 -0
- package/src/TopNav/TopNavMenu.test.tsx +65 -1
- package/src/TopNav/TopNavMenu.tsx +30 -1
- package/src/TopNav/__tests__/TopNavMobileLongHeading.a11y.chromium.spec.ts +1 -0
- package/src/TreeList/TreeList.doc.mjs +13 -0
- package/src/TreeList/TreeList.spec.md +54 -35
- package/src/TreeList/TreeList.tsx +234 -2
- package/src/TreeList/TreeListBranches.tsx +8 -6
- package/src/TreeList/TreeListItem.tsx +12 -6
- package/src/TreeList/__tests__/TreeList.a11y.chromium.spec.ts +19 -6
- package/src/TreeList/__tests__/TreeListGuideAlignment.interaction.browser.spec.ts +127 -0
- package/src/TreeList/__tests__/TreeListRowNames.a11y.chromium.spec.ts +1 -0
- package/src/Typeahead/BaseTypeahead.emptyState.a11y.chromium.spec.ts +138 -0
- package/src/Typeahead/BaseTypeahead.test.tsx +201 -4
- package/src/Typeahead/BaseTypeahead.tsx +26 -10
- package/src/Typeahead/Typeahead.test.tsx +114 -1
- package/src/Typeahead/Typeahead.tsx +34 -16
- package/src/VisuallyHidden/VisuallyHidden.spec.md +170 -0
- package/src/__tests__/BusyOwnerAnnouncement.test.tsx +66 -5
- package/src/__tests__/CardPress.a11y.chromium.spec.ts +353 -0
- package/src/__tests__/DisabledTriggerFocus.a11y.chromium.spec.ts +2 -1
- package/src/__tests__/PressModality.a11y.chromium.spec.ts +392 -0
- package/src/__tests__/PressedState.a11y.chromium.spec.ts +1 -0
- package/src/__tests__/pressState.ts +43 -1
- package/src/__tests__/unthemedLength.ts +34 -0
- package/src/gestures/GestureArena.ts +966 -0
- package/src/gestures/GestureRecognizer.ts +626 -0
- package/src/gestures/LongPressGestureRecognizer.ts +186 -0
- package/src/gestures/PanGestureRecognizer.ts +410 -0
- package/src/gestures/TapGestureRecognizer.ts +192 -0
- package/src/gestures/VelocityTracker.ts +194 -0
- package/src/gestures/__tests__/LongPressGestureRecognizer.test.ts +141 -0
- package/src/gestures/__tests__/PanGestureRecognizer.test.ts +327 -0
- package/src/gestures/__tests__/TapGestureRecognizer.test.ts +154 -0
- package/src/gestures/__tests__/VelocityTracker.streams.test.ts +243 -0
- package/src/gestures/__tests__/VelocityTracker.test.ts +261 -0
- package/src/gestures/__tests__/arena.test.ts +824 -0
- package/src/gestures/__tests__/arenaContinuous.test.ts +207 -0
- package/src/gestures/__tests__/arenaTapLongPress.test.ts +211 -0
- package/src/gestures/__tests__/fixtures/pointer-streams/README.md +82 -0
- package/src/gestures/__tests__/fixtures/pointer-streams/android-chromium-fling.json +130 -0
- package/src/gestures/__tests__/fixtures/pointer-streams/android-chromium-slow.json +860 -0
- package/src/gestures/__tests__/fixtures/pointer-streams/android-chromium-stop-release.json +357 -0
- package/src/gestures/__tests__/fixtures/pointer-streams/android-firefox-fling.json +66 -0
- package/src/gestures/__tests__/fixtures/pointer-streams/android-firefox-slow.json +268 -0
- package/src/gestures/__tests__/fixtures/pointer-streams/android-firefox-stop-release.json +128 -0
- package/src/gestures/__tests__/fixtures/pointer-streams/capture.html +123 -0
- package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-mouse-fling.json +64 -0
- package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-mouse-slow.json +268 -0
- package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-mouse-stop-release.json +124 -0
- package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-pen-fling.json +64 -0
- package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-pen-slow.json +268 -0
- package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-pen-stop-release.json +124 -0
- package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-touch-fling.json +84 -0
- package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-touch-slow.json +381 -0
- package/src/gestures/__tests__/fixtures/pointer-streams/desktop-chromium-touch-stop-release.json +171 -0
- package/src/gestures/__tests__/fixtures/pointer-streams/ios-safari-fling.json +45 -0
- package/src/gestures/__tests__/fixtures/pointer-streams/ios-safari-slow.json +101 -0
- package/src/gestures/__tests__/fixtures/pointer-streams/ios-safari-stop-release.json +130 -0
- package/src/gestures/__tests__/harness.ts +204 -0
- package/src/gestures/geometry.ts +55 -0
- package/src/gestures/types.ts +161 -0
- package/src/hooks/AnnounceRenderedText.tsx +27 -0
- package/src/hooks/ModalAnnounceProvider.tsx +155 -0
- package/src/hooks/__tests__/MenuPressShadowRoot.a11y.chromium.spec.ts +98 -4
- package/src/hooks/__tests__/menuLinkClicks.ts +71 -0
- package/src/hooks/actionGroupTracker.exports.test.ts +28 -0
- package/src/hooks/actionGroupTracker.test.ts +510 -0
- package/src/hooks/actionGroupTracker.ts +449 -0
- package/src/hooks/index.ts +6 -0
- package/src/hooks/menuPressOnItems.ts +40 -0
- package/src/hooks/modalAnnounce.ts +439 -0
- package/src/hooks/scrollGeometry.ts +71 -4
- package/src/hooks/useAdaptivePresentation.ts +46 -9
- package/src/hooks/useAnimatedLayout.doc.mjs +101 -0
- package/src/hooks/useAnimatedLayout.ts +61 -0
- package/src/hooks/useAnnounce.doc.mjs +4 -4
- package/src/hooks/useAnnounce.modal.test.tsx +1291 -0
- package/src/hooks/useAnnounce.test.tsx +64 -4
- package/src/hooks/useAnnounce.ts +452 -28
- package/src/hooks/useAnnounceRenderedText.adopters.test.tsx +226 -0
- package/src/hooks/useAnnounceRenderedText.ts +81 -11
- package/src/hooks/useBusyAnnouncement.adopters.test.tsx +69 -0
- package/src/hooks/useBusyAnnouncement.test.tsx +112 -0
- package/src/hooks/useBusyAnnouncement.ts +64 -54
- package/src/hooks/useFocusTrap.doc.mjs +3 -3
- package/src/hooks/useFocusTrap.test.tsx +135 -2
- package/src/hooks/useFocusTrap.ts +59 -27
- package/src/hooks/useMenuHover.ts +6 -2
- package/src/hooks/useMenuPress.doc.mjs +2 -2
- package/src/hooks/useMenuPress.test.tsx +5 -2
- package/src/hooks/useMenuPress.ts +72 -37
- package/src/hooks/usePressFeedback.doc.mjs +4 -4
- package/src/hooks/usePressFeedback.ts +5 -2
- package/src/hooks/useScrollableArea.test.tsx +344 -3
- package/src/hooks/useScrollableArea.ts +120 -12
- package/src/i18n/generated-locales/en.generated.ts +35 -0
- package/src/i18n/generated-locales/pseudo.generated.ts +37 -0
- package/src/internal/tokenizer-presentation.test.ts +29 -0
- package/src/internal/tokenizer-presentation.ts +25 -0
- package/src/internal/touch.test.ts +44 -0
- package/src/internal/touch.ts +41 -0
- package/src/motion/LayoutChangeSnapshot.tsx +50 -0
- package/src/motion/MEASUREMENTS.md +271 -0
- package/src/motion/README.md +218 -0
- package/src/motion/__tests__/animatedLayout.interaction.browser.spec.ts +1613 -0
- package/src/motion/__tests__/animatedLayoutAdopters.interaction.browser.spec.ts +217 -0
- package/src/motion/__tests__/animatedLayoutBundle.ts +17 -0
- package/src/motion/animatedLayout.boundary.test.ts +155 -0
- package/src/motion/animatedLayout.swap.test.ts +827 -0
- package/src/motion/animatedLayout.test.ts +1154 -0
- package/src/motion/animatedLayout.ts +1801 -0
- package/src/motion/animatedLayoutAdopters.test.tsx +500 -0
- package/src/motion/animator.test.ts +2653 -0
- package/src/motion/animator.ts +2794 -0
- package/src/motion/bezier.test.ts +52 -0
- package/src/motion/bezier.ts +64 -0
- package/src/motion/coast.test.ts +99 -0
- package/src/motion/coast.ts +150 -0
- package/src/motion/decay.test.ts +120 -0
- package/src/motion/decay.ts +126 -0
- package/src/motion/projection.test.ts +107 -0
- package/src/motion/projection.ts +116 -0
- package/src/motion/reducedMotion.stylex.ts +41 -0
- package/src/motion/reducedMotion.test.ts +129 -0
- package/src/motion/reducedMotion.ts +94 -0
- package/src/motion/reducedMotionPlan.test.ts +182 -0
- package/src/motion/reducedMotionPlan.ts +263 -0
- package/src/motion/resolveSnapPoint.test.ts +189 -0
- package/src/motion/resolveSnapPoint.ts +169 -0
- package/src/motion/roleValue.ts +105 -0
- package/src/motion/roles.test.ts +256 -0
- package/src/motion/roles.ts +262 -0
- package/src/motion/rubberBand.test.ts +88 -0
- package/src/motion/rubberBand.ts +115 -0
- package/src/motion/selectPage.test.ts +31 -0
- package/src/motion/selectPage.ts +55 -0
- package/src/motion/spring.test.ts +650 -0
- package/src/motion/spring.ts +551 -0
- package/src/motion/transientCopy.ts +374 -0
- package/src/motion/uikit/gestures.test.ts +89 -0
- package/src/motion/uikit/gestures.ts +359 -0
- package/src/motion/uikit/index.ts +80 -0
- package/src/motion/uikit/navigation.ts +83 -0
- package/src/motion/uikit/scroll.ts +141 -0
- package/src/motion/uikit/springRows.test.ts +71 -0
- package/src/motion/uikit/springs.ts +514 -0
- package/src/motion/uikit/timing.ts +210 -0
- package/src/motion/uikit/uikit.test.ts +364 -0
- package/src/motion/uikit/values.test.ts +110 -0
- package/src/reset.a11y.chromium.spec.ts +1 -0
- package/src/reset.until-found.a11y.browser.spec.ts +1 -0
- package/src/serverSafeComponents.test.ts +10 -0
- package/src/tailwind-theme.css +51 -1
- package/src/tailwind-theme.test.ts +51 -0
- package/src/theme/Theme.test.tsx +28 -0
- package/src/theme/__tests__/SpacingRootFontSize.a11y.chromium.spec.ts +1 -0
- package/src/theme/declarationBoundary.ts +282 -1
- package/src/theme/defineTheme.test.ts +529 -12
- package/src/theme/defineTheme.ts +231 -19
- package/src/theme/derivedVarRegistry.test.ts +34 -5
- package/src/theme/derivedVarRegistry.ts +4 -0
- package/src/theme/expandMotionScale.test.ts +17 -0
- package/src/theme/extensibleAxes.test.ts +74 -29
- package/src/theme/generateThemeRules.ts +772 -35
- package/src/theme/index.ts +3 -0
- package/src/theme/onMediaTokens.test.ts +186 -0
- package/src/theme/statusColor.ts +189 -0
- package/src/theme/statusRoleDerivation.ts +289 -0
- package/src/theme/syntax/SyntaxTheme.tsx +1 -1
- package/src/theme/syntax/defineSyntaxTheme.ts +1 -1
- package/src/theme/syntax/presets.ts +1 -1
- package/src/theme/syntax/tokens.ts +1 -1
- package/src/theme/themeAdaptations.test.ts +412 -0
- package/src/theme/themeAdaptations.ts +43 -1
- package/src/theme/tokens.stylex.ts +36 -2
- package/src/theme/tokens.test.ts +111 -1
- package/src/theme/tokens.ts +23 -1
- package/src/theme/useTheme.ts +10 -4
- package/src/utils/customPropertyArmLayering.test.ts +131 -0
- package/src/utils/edgeAutoscroll.test.ts +192 -0
- package/src/utils/edgeAutoscroll.ts +111 -0
- package/src/utils/hitArea.test.ts +628 -0
- package/src/utils/hitArea.ts +770 -0
- package/src/utils/interactionOverlay.stylex.ts +4 -1
- package/src/utils/pressFeedback.test.ts +310 -2
- package/src/utils/pressFeedback.ts +306 -54
- package/src/utils/pressGesture.test.ts +50 -0
- package/src/utils/pressGesture.ts +40 -2
- package/src/utils/touchPresentation.test.ts +323 -0
- package/src/utils/touchPresentation.ts +153 -0
|
@@ -0,0 +1,1801 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file animatedLayout.ts
|
|
5
|
+
* @input The DOM (layout rectangles, computed style), Web Animations, the
|
|
6
|
+
* internal `springs.settle` motion role (motion/roles.ts) and the Reduce Motion
|
|
7
|
+
* cross-fade clock (uikit/timing.ts)
|
|
8
|
+
* @output Exports `createAnimatedLayout` and the opaque `AnimatedLayout`
|
|
9
|
+
* handle, `reportLayoutChange`, `playLayoutChange`, `holdLayoutExit` /
|
|
10
|
+
* `releaseLayoutExit`, the in-place swap (`holdLayoutSwap` /
|
|
11
|
+
* `playLayoutSwap`), `playLayoutFrames` and `applyLayoutChangeTransition`:
|
|
12
|
+
* the one module
|
|
13
|
+
* that produces the
|
|
14
|
+
* size-change glide `spec:AST-105` defines
|
|
15
|
+
* (`architecture:react-component-runtime` INV12)
|
|
16
|
+
* @position Motion foundation, internal to core. A handle comes from the
|
|
17
|
+
* public `useAnimatedLayout` hook; a component that takes it reports its
|
|
18
|
+
* size changes through this module.
|
|
19
|
+
*
|
|
20
|
+
* How it works:
|
|
21
|
+
* - `measureBefore()` runs before the change commits: from the changed
|
|
22
|
+
* element it walks up to the handle's container and, at each level,
|
|
23
|
+
* records the rectangles of the element siblings after it and before it (a
|
|
24
|
+
* centered, end-aligned or space-between row, or `order`, moves those too),
|
|
25
|
+
* through `parentElement`, `nextElementSibling` and
|
|
26
|
+
* `previousElementSibling`, descending only into an element with
|
|
27
|
+
* `display: contents` (it has no box). Each level's walk stops at the first
|
|
28
|
+
* sibling outside the band a change can move content into view from: the
|
|
29
|
+
* area's visible part plus one viewport, or the changed element's size if
|
|
30
|
+
* larger, above and below. So its cost grows with depth plus the siblings
|
|
31
|
+
* near the visible part, never with a list's length.
|
|
32
|
+
* - `animate()` runs after the commit (a layout effect). Every change in the
|
|
33
|
+
* same area reported in one frame is measured together after the commit,
|
|
34
|
+
* once, in a microtask, so each element moves once, by its total change.
|
|
35
|
+
* - An element moves only when its rectangle changed and it is in the area's
|
|
36
|
+
* visible part, before or after. Absolute, fixed, top-layer, hidden and
|
|
37
|
+
* zero-size elements are skipped (an absolute child rides with its moving
|
|
38
|
+
* parent); a stuck sticky element does not change rectangle, so it stays.
|
|
39
|
+
* - The move is a compositor-only `translate` (replace composition) from the
|
|
40
|
+
* old place to the new one, sampled from `springs.settle` into linear
|
|
41
|
+
* keyframes and corrected for a scaled ancestor. An element already gliding
|
|
42
|
+
* keeps that motion and adds the new move: the rest of its curve and the
|
|
43
|
+
* new move are summed into one new glide, velocity included. Nothing
|
|
44
|
+
* animates height, and nothing scrolls the area.
|
|
45
|
+
* - A measurement no commit claims by the next frame is dropped.
|
|
46
|
+
* - The changed element plays its own entrance on the same spring, started in
|
|
47
|
+
* the same frame (`playLayoutChange`), or its exit: kept where it is while
|
|
48
|
+
* it gives up its space and conceals (`holdLayoutExit`). A disclosure's
|
|
49
|
+
* indicator turns on the same motion (`applyLayoutChangeTransition`).
|
|
50
|
+
* - A swap holds old content as one transient copy, inert and hidden from
|
|
51
|
+
* assistive technology, while new content enters in its place, on the same
|
|
52
|
+
* motion, and removes it when the swap ends (`holdLayoutSwap`,
|
|
53
|
+
* `playLayoutSwap`; `spec:AST-105` FR8). The caller shapes the frames over
|
|
54
|
+
* the swap's progress and, riding a gliding element, how far it has moved,
|
|
55
|
+
* so every part keeps to that glide; under Reduce Motion with a coarse
|
|
56
|
+
* pointer only opacity changes.
|
|
57
|
+
* - Frames on elements the page renders can play on the same motion with no
|
|
58
|
+
* copy (`playLayoutFrames`), such as a surface reaching over a gap a glide
|
|
59
|
+
* opens, and are released when the motion ends.
|
|
60
|
+
* - Every pointer (`spec:AST-105` FR5). Under Reduce Motion nothing travels
|
|
61
|
+
* (`design:reduced-motion` DR1–DR3): a cross-fade under a coarse primary
|
|
62
|
+
* pointer, an immediate change otherwise.
|
|
63
|
+
* - Without a handle nothing happens: the component keeps its jump
|
|
64
|
+
* (`spec:AST-105` FR2).
|
|
65
|
+
*/
|
|
66
|
+
|
|
67
|
+
import {motionRole} from './roles';
|
|
68
|
+
import {
|
|
69
|
+
inertCopy,
|
|
70
|
+
isCopyable,
|
|
71
|
+
paintedBackground,
|
|
72
|
+
placeOver,
|
|
73
|
+
visiblePartCopy,
|
|
74
|
+
wrapText,
|
|
75
|
+
} from './transientCopy';
|
|
76
|
+
import {isSpring} from './roleValue';
|
|
77
|
+
import {solveSpring, toSpring, type SpringDescription} from './spring';
|
|
78
|
+
import {registerSpringsTable, SETTLE_SPRING} from './uikit/springs';
|
|
79
|
+
import {reducedMotionCrossFade} from './uikit/timing';
|
|
80
|
+
|
|
81
|
+
/** The shared motion role (`spec:AST-105` FR4). */
|
|
82
|
+
const ROLE_ID = 'springs.settle';
|
|
83
|
+
/** Below this many pixels a shift is not worth a move. */
|
|
84
|
+
const MIN_SHIFT_PX = 0.5;
|
|
85
|
+
/** The touch cross-fade's cap (`design:reduced-motion` DR2). */
|
|
86
|
+
const CROSS_FADE_CAP_MS = 200;
|
|
87
|
+
/** Keyframes per second the spring is sampled at. */
|
|
88
|
+
const SAMPLES_PER_SECOND = 60;
|
|
89
|
+
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
// Motion
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
|
|
94
|
+
/** How a change plays under the reader's settings. */
|
|
95
|
+
type LayoutMotion =
|
|
96
|
+
| {readonly kind: 'spring'; readonly progress: SpringProgress}
|
|
97
|
+
| {
|
|
98
|
+
readonly kind: 'fade';
|
|
99
|
+
readonly durationMs: number;
|
|
100
|
+
readonly easing: string;
|
|
101
|
+
}
|
|
102
|
+
| {readonly kind: 'instant'};
|
|
103
|
+
|
|
104
|
+
/** The settle spring as remaining distance (1 → 0) over its duration. */
|
|
105
|
+
interface SpringProgress {
|
|
106
|
+
readonly durationMs: number;
|
|
107
|
+
/** Remaining fraction of the move at `t` ms. */
|
|
108
|
+
remaining(t: number): number;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function matches(element: Element, query: string): boolean {
|
|
112
|
+
const view = element.ownerDocument.defaultView;
|
|
113
|
+
return (
|
|
114
|
+
typeof view?.matchMedia === 'function' && view.matchMedia(query).matches
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* `springs.settle` from the internal role registry: one shared value for the
|
|
120
|
+
* glide, the changed element and the indicator. Motion roles are internal
|
|
121
|
+
* (`spec:AST-094` DEC-11): no theme, scope or custom property changes it.
|
|
122
|
+
*/
|
|
123
|
+
function settleSpring(): SpringDescription {
|
|
124
|
+
registerSpringsTable();
|
|
125
|
+
const value = motionRole(ROLE_ID)?.value;
|
|
126
|
+
return isSpring(value) ? value : SETTLE_SPRING;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function springProgress(description: SpringDescription): SpringProgress {
|
|
130
|
+
const curve = solveSpring(toSpring(description), {from: 1, to: 0});
|
|
131
|
+
const durationMs = Math.max(1, curve.settleTime(0.001) * 1000);
|
|
132
|
+
return {
|
|
133
|
+
durationMs,
|
|
134
|
+
remaining: t => (t >= durationMs ? 0 : curve.value(t / 1000)),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** The motion a change in `area` plays now. */
|
|
139
|
+
function layoutMotion(area: Element): LayoutMotion {
|
|
140
|
+
if (matches(area, '(prefers-reduced-motion: reduce)')) {
|
|
141
|
+
if (!matches(area, '(pointer: coarse)')) {
|
|
142
|
+
return {kind: 'instant'};
|
|
143
|
+
}
|
|
144
|
+
const [x1, y1, x2, y2] = reducedMotionCrossFade.curve;
|
|
145
|
+
return {
|
|
146
|
+
kind: 'fade',
|
|
147
|
+
durationMs: Math.min(
|
|
148
|
+
CROSS_FADE_CAP_MS,
|
|
149
|
+
reducedMotionCrossFade.durationMs,
|
|
150
|
+
),
|
|
151
|
+
easing: `cubic-bezier(${x1}, ${y1}, ${x2}, ${y2})`,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
return {kind: 'spring', progress: springProgress(settleSpring())};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Linear keyframes over `durationMs`, one per frame, from `frame(t ms)`. */
|
|
158
|
+
function sampleOver(
|
|
159
|
+
durationMs: number,
|
|
160
|
+
frame: (t: number) => Keyframe,
|
|
161
|
+
): Keyframe[] {
|
|
162
|
+
const count = Math.max(
|
|
163
|
+
2,
|
|
164
|
+
Math.ceil((durationMs / 1000) * SAMPLES_PER_SECOND) + 1,
|
|
165
|
+
);
|
|
166
|
+
const keyframes: Keyframe[] = [];
|
|
167
|
+
for (let i = 0; i < count; i++) {
|
|
168
|
+
const offset = i / (count - 1);
|
|
169
|
+
keyframes.push({...frame(offset * durationMs), offset});
|
|
170
|
+
}
|
|
171
|
+
return keyframes;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Linear keyframes sampled from the spring, one per frame. */
|
|
175
|
+
function sampleKeyframes(
|
|
176
|
+
progress: SpringProgress,
|
|
177
|
+
frame: (remaining: number) => Keyframe,
|
|
178
|
+
): Keyframe[] {
|
|
179
|
+
return sampleOver(progress.durationMs, t => frame(progress.remaining(t)));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** The spring as a CSS `linear()` easing, for a CSS transition. */
|
|
183
|
+
function linearEasing(progress: SpringProgress): string {
|
|
184
|
+
const stops: string[] = [];
|
|
185
|
+
const count = 24;
|
|
186
|
+
for (let i = 0; i <= count; i++) {
|
|
187
|
+
const fraction = i / count;
|
|
188
|
+
const value = 1 - progress.remaining(fraction * progress.durationMs);
|
|
189
|
+
stops.push(`${round(value)} ${round(fraction * 100)}%`);
|
|
190
|
+
}
|
|
191
|
+
return `linear(${stops.join(', ')})`;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function round(value: number): number {
|
|
195
|
+
return Math.round(value * 1000) / 1000;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// ---------------------------------------------------------------------------
|
|
199
|
+
// Playing
|
|
200
|
+
// ---------------------------------------------------------------------------
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Play `keyframes` on `element`. Every option here (linear easing over sampled
|
|
204
|
+
* keyframes, replace composition) is one any Web Animations engine takes, so
|
|
205
|
+
* a failure means no Web Animations at all: the change then lands at once.
|
|
206
|
+
*/
|
|
207
|
+
function safeAnimate(
|
|
208
|
+
element: Element,
|
|
209
|
+
keyframes: Keyframe[],
|
|
210
|
+
options: KeyframeAnimationOptions,
|
|
211
|
+
): Animation | null {
|
|
212
|
+
if (typeof (element as HTMLElement).animate !== 'function') {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
let animation: Animation;
|
|
216
|
+
try {
|
|
217
|
+
animation = (element as HTMLElement).animate(keyframes, options);
|
|
218
|
+
} catch {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
ours.add(animation);
|
|
222
|
+
// Started on the document timeline's current time, not on the next frame:
|
|
223
|
+
// a retargeted glide keeps moving through the frame it is replaced in, and
|
|
224
|
+
// every animation of one change shares the same start.
|
|
225
|
+
const now = element.ownerDocument.timeline?.currentTime;
|
|
226
|
+
if (now != null) {
|
|
227
|
+
animation.startTime = now;
|
|
228
|
+
}
|
|
229
|
+
return animation;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/** Every animation this module started, so it can tell the app's apart. */
|
|
233
|
+
const ours = new WeakSet<Animation>();
|
|
234
|
+
|
|
235
|
+
const TRANSFORM_PROPERTIES = ['transform', 'translate', 'rotate', 'scale'];
|
|
236
|
+
|
|
237
|
+
/** The numbers in a CSS value, units dropped. */
|
|
238
|
+
function numbersIn(value: string): number[] {
|
|
239
|
+
return (value.match(/-?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?/gi) ?? []).map(
|
|
240
|
+
Number,
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Whether a transform value leaves the element where it is: nothing at all
|
|
246
|
+
* (a swipe's `translate3d(0, 0, 0)` at rest, a button's `scale(1)`, computed
|
|
247
|
+
* as `matrix(1, 0, 0, 1, 0, 0)`), or a scale in place (a pressed button's
|
|
248
|
+
* `scale(0.98)`). A glide's `translate` composes with either; a translation,
|
|
249
|
+
* rotation or skew of its own is the app moving the element.
|
|
250
|
+
*/
|
|
251
|
+
function staysInPlace(property: string, value: string): boolean {
|
|
252
|
+
if (value === 'none') {
|
|
253
|
+
// No transform at all (a keyframe a press's own transition starts from).
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
if (property === 'scale') {
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
if (value.includes('var(')) {
|
|
260
|
+
// An unresolved custom property in an app's own keyframes: its value is
|
|
261
|
+
// unknown here, so the app moves the element.
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
if (property === 'translate') {
|
|
265
|
+
return numbersIn(value).every(n => n === 0);
|
|
266
|
+
}
|
|
267
|
+
if (property === 'rotate') {
|
|
268
|
+
// An angle, after an optional axis: only the angle matters.
|
|
269
|
+
const numbers = numbersIn(value);
|
|
270
|
+
return numbers.length > 0 && numbers[numbers.length - 1] === 0;
|
|
271
|
+
}
|
|
272
|
+
// A list of transform functions, as computed (`matrix()`, `matrix3d()`)
|
|
273
|
+
// or as written.
|
|
274
|
+
const functions = [...value.matchAll(/([a-z0-9]+)\(([^)]*)\)/gi)];
|
|
275
|
+
return (
|
|
276
|
+
functions.length > 0 &&
|
|
277
|
+
functions.every(([, name, args]) => {
|
|
278
|
+
const numbers = numbersIn(args);
|
|
279
|
+
const fn = name.toLowerCase();
|
|
280
|
+
if (fn === 'matrix') {
|
|
281
|
+
// a b c d e f: no skew, rotation or translation.
|
|
282
|
+
return (
|
|
283
|
+
numbers.length === 6 &&
|
|
284
|
+
[1, 2, 4, 5].every(index => numbers[index] === 0)
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
if (fn === 'matrix3d') {
|
|
288
|
+
// Only the diagonal: a scale, nothing else.
|
|
289
|
+
return (
|
|
290
|
+
numbers.length === 16 &&
|
|
291
|
+
numbers.every((n, index) => index % 5 === 0 || n === 0)
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
if (fn === 'rotate3d') {
|
|
295
|
+
return numbers[3] === 0;
|
|
296
|
+
}
|
|
297
|
+
if (fn.startsWith('scale')) {
|
|
298
|
+
return true;
|
|
299
|
+
}
|
|
300
|
+
if (
|
|
301
|
+
fn.startsWith('translate') ||
|
|
302
|
+
fn.startsWith('rotate') ||
|
|
303
|
+
fn.startsWith('skew')
|
|
304
|
+
) {
|
|
305
|
+
return numbers.every(n => n === 0);
|
|
306
|
+
}
|
|
307
|
+
return false;
|
|
308
|
+
})
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Whether the app moves `element` itself: its own `transform`, `translate`
|
|
314
|
+
* or `rotate`, or a running animation of one this module did not start. A
|
|
315
|
+
* value that leaves it in place (nothing, or a scale) is not a move.
|
|
316
|
+
*/
|
|
317
|
+
function movedByApp(element: Element): boolean {
|
|
318
|
+
const style = element.ownerDocument.defaultView?.getComputedStyle(element);
|
|
319
|
+
if (
|
|
320
|
+
style != null &&
|
|
321
|
+
TRANSFORM_PROPERTIES.some(property => {
|
|
322
|
+
const value = style.getPropertyValue(property);
|
|
323
|
+
return value !== '' && value !== 'none' && !staysInPlace(property, value);
|
|
324
|
+
})
|
|
325
|
+
) {
|
|
326
|
+
return true;
|
|
327
|
+
}
|
|
328
|
+
if (typeof element.getAnimations !== 'function') {
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
return element.getAnimations().some(animation => {
|
|
332
|
+
if (ours.has(animation)) {
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
const effect = animation.effect;
|
|
336
|
+
if (!(effect instanceof KeyframeEffect)) {
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
return effect
|
|
340
|
+
.getKeyframes()
|
|
341
|
+
.some(frame =>
|
|
342
|
+
TRANSFORM_PROPERTIES.some(
|
|
343
|
+
property =>
|
|
344
|
+
property in frame &&
|
|
345
|
+
!staysInPlace(property, String(frame[property])),
|
|
346
|
+
),
|
|
347
|
+
);
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/** An offset in the element's own px, as a function of ms into a glide. */
|
|
352
|
+
type OffsetCurve = (t: number) => {readonly x: number; readonly y: number};
|
|
353
|
+
|
|
354
|
+
const AT_REST: OffsetCurve = () => ({x: 0, y: 0});
|
|
355
|
+
|
|
356
|
+
/** A glide an element is playing, so a new change can retarget it. */
|
|
357
|
+
interface Glide {
|
|
358
|
+
readonly animation: Animation;
|
|
359
|
+
readonly offsetAt: OffsetCurve;
|
|
360
|
+
readonly durationMs: number;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
const glides = new WeakMap<Element, Glide>();
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* The glide `element` is playing now, if any. For an adopter that draws
|
|
367
|
+
* something with each moving element (a table row's divider): it finds what
|
|
368
|
+
* moves without reading the DOM.
|
|
369
|
+
*/
|
|
370
|
+
export function glideOf(element: Element): Animation | null {
|
|
371
|
+
return glides.get(element)?.animation ?? null;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// ---------------------------------------------------------------------------
|
|
375
|
+
// Handles
|
|
376
|
+
// ---------------------------------------------------------------------------
|
|
377
|
+
|
|
378
|
+
const AREA = Symbol('astryx.animatedLayout.area');
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* The opaque handle `useAnimatedLayout` returns (`spec:AST-105` FR1): no
|
|
382
|
+
* public members. A component that receives it reports its size changes to
|
|
383
|
+
* the handle's container, the area the glide stays inside.
|
|
384
|
+
*/
|
|
385
|
+
export interface AnimatedLayout {
|
|
386
|
+
readonly [AREA]: () => Element | null;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/** A handle over `area` (the container element, read when a change runs). */
|
|
390
|
+
export function createAnimatedLayout(
|
|
391
|
+
area: () => Element | null,
|
|
392
|
+
): AnimatedLayout {
|
|
393
|
+
// Not enumerable and frozen: the handle shows no fields to a caller.
|
|
394
|
+
return Object.freeze(
|
|
395
|
+
Object.defineProperty({}, AREA, {value: area}),
|
|
396
|
+
) as AnimatedLayout;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function areaOf(handle: AnimatedLayout, element: Element): Element | null {
|
|
400
|
+
const area = handle[AREA]();
|
|
401
|
+
return area != null && area !== element && area.contains(element)
|
|
402
|
+
? area
|
|
403
|
+
: null;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// ---------------------------------------------------------------------------
|
|
407
|
+
// The walk
|
|
408
|
+
// ---------------------------------------------------------------------------
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Whether `element` takes part: in flow, rendered, not in the top layer.
|
|
412
|
+
* `display: contents` is handled by the caller.
|
|
413
|
+
*/
|
|
414
|
+
function takesPart(element: Element, style: CSSStyleDeclaration): boolean {
|
|
415
|
+
if (
|
|
416
|
+
style.display === 'none' ||
|
|
417
|
+
style.visibility === 'hidden' ||
|
|
418
|
+
style.position === 'absolute' ||
|
|
419
|
+
style.position === 'fixed'
|
|
420
|
+
) {
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
423
|
+
try {
|
|
424
|
+
if (element.matches(':popover-open, :modal')) {
|
|
425
|
+
return false;
|
|
426
|
+
}
|
|
427
|
+
} catch {
|
|
428
|
+
// An engine without these pseudo-classes has no top layer to skip.
|
|
429
|
+
}
|
|
430
|
+
return true;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* The band of the page a change can move content into or out of view: the
|
|
435
|
+
* area's visible part, extended above and below by one viewport or by the
|
|
436
|
+
* size of every element changing in the frame, whichever is larger (a
|
|
437
|
+
* collapse pulls content up by at most its size, and changes in one frame
|
|
438
|
+
* add up). Content outside it before the change stays outside it, so the
|
|
439
|
+
* walk stops there.
|
|
440
|
+
*/
|
|
441
|
+
interface Band {
|
|
442
|
+
/** Its top edge, in client px. */
|
|
443
|
+
readonly start: number;
|
|
444
|
+
/** Its bottom edge, in client px. */
|
|
445
|
+
readonly end: number;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function bandFor(visible: DOMRect, reach: number): Band {
|
|
449
|
+
return {start: visible.top - reach, end: visible.bottom + reach};
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* What one frame's walks read, kept so a level two changes share, or a walk
|
|
454
|
+
* repeated when the band grows, reads each element once.
|
|
455
|
+
*/
|
|
456
|
+
interface WalkCache {
|
|
457
|
+
readonly rects: Map<Element, DOMRect>;
|
|
458
|
+
/** Whether the element takes part, or `contents` for a boxless element. */
|
|
459
|
+
readonly parts: Map<Element, boolean | 'contents'>;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
function partOf(element: Element, cache: WalkCache): boolean | 'contents' {
|
|
463
|
+
let part = cache.parts.get(element);
|
|
464
|
+
if (part === undefined) {
|
|
465
|
+
const style = element.ownerDocument.defaultView?.getComputedStyle(element);
|
|
466
|
+
part =
|
|
467
|
+
style == null
|
|
468
|
+
? false
|
|
469
|
+
: style.display === 'contents'
|
|
470
|
+
? 'contents'
|
|
471
|
+
: takesPart(element, style);
|
|
472
|
+
cache.parts.set(element, part);
|
|
473
|
+
}
|
|
474
|
+
return part;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Whether a container lays its children out across the block direction, so
|
|
479
|
+
* DOM order does not run down the page: multi-column, a wrapping column flex
|
|
480
|
+
* box, or a grid that flows by column. The band says nothing about where its
|
|
481
|
+
* later children sit, so a walk there runs through the level.
|
|
482
|
+
*/
|
|
483
|
+
function flowsAcross(container: Element | null): boolean {
|
|
484
|
+
if (container == null) {
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
const style =
|
|
488
|
+
container.ownerDocument.defaultView?.getComputedStyle(container);
|
|
489
|
+
if (style == null) {
|
|
490
|
+
return false;
|
|
491
|
+
}
|
|
492
|
+
const count = style.getPropertyValue('column-count');
|
|
493
|
+
const width = style.getPropertyValue('column-width');
|
|
494
|
+
return (
|
|
495
|
+
(count !== '' && count !== 'auto') ||
|
|
496
|
+
(width !== '' && width !== 'auto') ||
|
|
497
|
+
(style.display.includes('flex') &&
|
|
498
|
+
style.flexDirection.startsWith('column') &&
|
|
499
|
+
style.flexWrap.startsWith('wrap')) ||
|
|
500
|
+
(style.display.includes('grid') &&
|
|
501
|
+
style.getPropertyValue('grid-auto-flow').startsWith('column'))
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* The box a sticky element sticks to: its nearest scrolling ancestor's, or
|
|
507
|
+
* the viewport.
|
|
508
|
+
*/
|
|
509
|
+
function scrollportOf(element: Element): {start: number; end: number} {
|
|
510
|
+
const view = element.ownerDocument.defaultView;
|
|
511
|
+
for (
|
|
512
|
+
let node = element.parentElement;
|
|
513
|
+
node != null && node !== element.ownerDocument.documentElement;
|
|
514
|
+
node = node.parentElement
|
|
515
|
+
) {
|
|
516
|
+
const overflow = view?.getComputedStyle(node).overflowY ?? 'visible';
|
|
517
|
+
if (
|
|
518
|
+
node === element.ownerDocument.body &&
|
|
519
|
+
view?.getComputedStyle(element.ownerDocument.documentElement)
|
|
520
|
+
.overflowY === 'visible'
|
|
521
|
+
) {
|
|
522
|
+
// The body's overflow applies to the viewport while the root's is
|
|
523
|
+
// visible: the body is no scroller of its own.
|
|
524
|
+
continue;
|
|
525
|
+
}
|
|
526
|
+
if (overflow !== 'visible' && overflow !== 'clip') {
|
|
527
|
+
const box = node.getBoundingClientRect();
|
|
528
|
+
return {
|
|
529
|
+
start: box.top + node.clientTop,
|
|
530
|
+
end: box.top + node.clientTop + node.clientHeight,
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
return {start: 0, end: view?.innerHeight ?? 0};
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Whether a sticky element is stuck: resting against its scrollport's edge
|
|
539
|
+
* at its inset. A stuck element takes its final place; an unstuck one is in
|
|
540
|
+
* flow.
|
|
541
|
+
*/
|
|
542
|
+
function isStuck(element: Element, cache: WalkCache): boolean {
|
|
543
|
+
const style = element.ownerDocument.defaultView?.getComputedStyle(element);
|
|
544
|
+
if (style?.position !== 'sticky') {
|
|
545
|
+
return false;
|
|
546
|
+
}
|
|
547
|
+
const rect = rectOf(element, cache);
|
|
548
|
+
const edge = scrollportOf(element);
|
|
549
|
+
const top = Number.parseFloat(style.top);
|
|
550
|
+
const bottom = Number.parseFloat(style.bottom);
|
|
551
|
+
return (
|
|
552
|
+
(Number.isFinite(top) && Math.abs(rect.top - (edge.start + top)) < 1) ||
|
|
553
|
+
(Number.isFinite(bottom) && Math.abs(rect.bottom - (edge.end - bottom)) < 1)
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
function rectOf(element: Element, cache: WalkCache): DOMRect {
|
|
558
|
+
let rect = cache.rects.get(element);
|
|
559
|
+
if (rect === undefined) {
|
|
560
|
+
rect = element.getBoundingClientRect();
|
|
561
|
+
cache.rects.set(element, rect);
|
|
562
|
+
}
|
|
563
|
+
return rect;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* The elements a change can move, each with its rectangle before the change:
|
|
568
|
+
* the changed element's ancestors up to the area (a centered column moves
|
|
569
|
+
* the card around the change), and at each of their levels the siblings
|
|
570
|
+
* after and before (a centered, end-aligned or space-between row, or
|
|
571
|
+
* `order`, moves those too). A `display: contents` element has no box: its
|
|
572
|
+
* children stand in its place, walked in the same direction. At each level
|
|
573
|
+
* the walk stops at the first sibling outside `band`, so its cost grows with
|
|
574
|
+
* depth plus the siblings near the visible part, never with the length of a
|
|
575
|
+
* list; where the area opts out of scroll anchoring (`walksToBand`), the walk
|
|
576
|
+
* after a change above the band goes on to the band, a cost that grows with
|
|
577
|
+
* that distance. Inside a positioned, stuck sticky or top-layer ancestor only the
|
|
578
|
+
* content after the change is taken.
|
|
579
|
+
*/
|
|
580
|
+
function collectCandidates(
|
|
581
|
+
changed: Element,
|
|
582
|
+
area: Element,
|
|
583
|
+
band: Band,
|
|
584
|
+
cache: WalkCache,
|
|
585
|
+
walksToBand: boolean,
|
|
586
|
+
ancestors: Set<Element>,
|
|
587
|
+
befores: Set<Element>,
|
|
588
|
+
): Map<Element, DOMRect> {
|
|
589
|
+
const out = new Map<Element, DOMRect>();
|
|
590
|
+
/** Takes `element`; returns false once it lies outside the band. */
|
|
591
|
+
/** The current level runs through its siblings, ignoring the band. */
|
|
592
|
+
let runsThrough = false;
|
|
593
|
+
const take = (element: Element, isAfter: boolean): boolean => {
|
|
594
|
+
const part = partOf(element, cache);
|
|
595
|
+
if (part === 'contents') {
|
|
596
|
+
for (
|
|
597
|
+
let child = isAfter
|
|
598
|
+
? element.firstElementChild
|
|
599
|
+
: element.lastElementChild;
|
|
600
|
+
child != null;
|
|
601
|
+
child = isAfter
|
|
602
|
+
? child.nextElementSibling
|
|
603
|
+
: child.previousElementSibling
|
|
604
|
+
) {
|
|
605
|
+
if (!take(child, isAfter)) {
|
|
606
|
+
return false;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
return true;
|
|
610
|
+
}
|
|
611
|
+
if (!part) {
|
|
612
|
+
return true;
|
|
613
|
+
}
|
|
614
|
+
const rect = rectOf(element, cache);
|
|
615
|
+
if (runsThrough) {
|
|
616
|
+
out.set(element, rect);
|
|
617
|
+
return true;
|
|
618
|
+
}
|
|
619
|
+
if (rect.top > band.end) {
|
|
620
|
+
return false;
|
|
621
|
+
}
|
|
622
|
+
if (rect.bottom < band.start) {
|
|
623
|
+
// Above the band. Where the scroller opts out of scroll anchoring, the
|
|
624
|
+
// content after a change above the band shifts the rows in view, so
|
|
625
|
+
// the walk after it goes on to the band; with anchoring, it stops.
|
|
626
|
+
return isAfter && walksToBand;
|
|
627
|
+
}
|
|
628
|
+
out.set(element, rect);
|
|
629
|
+
if (!isAfter) {
|
|
630
|
+
befores.add(element);
|
|
631
|
+
}
|
|
632
|
+
return true;
|
|
633
|
+
};
|
|
634
|
+
// The change's chain up to the area, and from where it is inside a
|
|
635
|
+
// positioned, stuck sticky or top-layer ancestor: that ancestor takes its final
|
|
636
|
+
// place, so inside it only the content after the change moves; the
|
|
637
|
+
// ancestors and the siblings before the change stay with it.
|
|
638
|
+
const chain: Element[] = [];
|
|
639
|
+
for (
|
|
640
|
+
let node: Element | null = changed;
|
|
641
|
+
node != null && node !== area;
|
|
642
|
+
node = node.parentElement
|
|
643
|
+
) {
|
|
644
|
+
chain.push(node);
|
|
645
|
+
}
|
|
646
|
+
// The levels below this index are inside a positioned ancestor.
|
|
647
|
+
let positionedFrom = 0;
|
|
648
|
+
for (let index = chain.length - 1; index > 0; index -= 1) {
|
|
649
|
+
if (partOf(chain[index], cache) === false || isStuck(chain[index], cache)) {
|
|
650
|
+
positionedFrom = index;
|
|
651
|
+
break;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
for (const [level, node] of chain.entries()) {
|
|
655
|
+
runsThrough = flowsAcross(node.parentElement);
|
|
656
|
+
if (
|
|
657
|
+
node !== changed &&
|
|
658
|
+
level > positionedFrom &&
|
|
659
|
+
partOf(node, cache) === true
|
|
660
|
+
) {
|
|
661
|
+
// An ancestor of the change in flow: where its layout moves it (a
|
|
662
|
+
// centered column), it glides, and what is inside moves only by its own
|
|
663
|
+
// change. A positioned, stuck sticky or top-layer ancestor, and every
|
|
664
|
+
// ancestor inside it, takes its final place.
|
|
665
|
+
out.set(node, rectOf(node, cache));
|
|
666
|
+
ancestors.add(node);
|
|
667
|
+
}
|
|
668
|
+
for (
|
|
669
|
+
let sibling = node.nextElementSibling;
|
|
670
|
+
sibling != null && take(sibling, true);
|
|
671
|
+
sibling = sibling.nextElementSibling
|
|
672
|
+
) {
|
|
673
|
+
// The siblings after it, until one lies past the band.
|
|
674
|
+
}
|
|
675
|
+
if (level < positionedFrom) {
|
|
676
|
+
continue;
|
|
677
|
+
}
|
|
678
|
+
for (
|
|
679
|
+
let sibling = node.previousElementSibling;
|
|
680
|
+
sibling != null && take(sibling, false);
|
|
681
|
+
sibling = sibling.previousElementSibling
|
|
682
|
+
) {
|
|
683
|
+
// The siblings before it, until one lies before the band.
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
return out;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// ---------------------------------------------------------------------------
|
|
690
|
+
// Batches: every change in one area in one frame moves together
|
|
691
|
+
// ---------------------------------------------------------------------------
|
|
692
|
+
|
|
693
|
+
interface Batch {
|
|
694
|
+
readonly area: Element;
|
|
695
|
+
readonly changed: Set<Element>;
|
|
696
|
+
readonly before: Map<Element, DOMRect>;
|
|
697
|
+
/** What each changed element's walk found, so a dropped change moves none. */
|
|
698
|
+
readonly candidates: Map<Element, Element[]>;
|
|
699
|
+
/** The changed elements' sizes before the change, added up. */
|
|
700
|
+
changedSize: number;
|
|
701
|
+
/** How far past the visible part the walks reach (0 before the first). */
|
|
702
|
+
reach: number;
|
|
703
|
+
/** The area's visible part, read once per frame. */
|
|
704
|
+
visible: DOMRect | null;
|
|
705
|
+
/** Whether the area opts out of scroll anchoring, read once per frame. */
|
|
706
|
+
walksToBand: boolean | null;
|
|
707
|
+
/** The change's ancestors among the candidates. */
|
|
708
|
+
readonly ancestors: Set<Element>;
|
|
709
|
+
/** The siblings before the change among the candidates. */
|
|
710
|
+
readonly befores: Set<Element>;
|
|
711
|
+
/**
|
|
712
|
+
* Where the area's content sat before the change, read once per frame: the
|
|
713
|
+
* area's place in view less its scroll offset, so a scroll of the area, an
|
|
714
|
+
* outer scroller or the page shows up as a change of it.
|
|
715
|
+
*/
|
|
716
|
+
originBefore: {readonly x: number; readonly y: number} | null;
|
|
717
|
+
readonly cache: WalkCache;
|
|
718
|
+
scheduled: boolean;
|
|
719
|
+
/** Called after every reading and before any glide starts. */
|
|
720
|
+
readonly beforeMove: ((candidates: ReadonlyArray<Element>) => void)[];
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
const batches = new Map<Element, Batch>();
|
|
724
|
+
|
|
725
|
+
function batchFor(area: Element): Batch {
|
|
726
|
+
let batch = batches.get(area);
|
|
727
|
+
if (batch == null) {
|
|
728
|
+
const created: Batch = {
|
|
729
|
+
area,
|
|
730
|
+
changed: new Set(),
|
|
731
|
+
before: new Map(),
|
|
732
|
+
candidates: new Map(),
|
|
733
|
+
changedSize: 0,
|
|
734
|
+
reach: 0,
|
|
735
|
+
visible: null,
|
|
736
|
+
walksToBand: null,
|
|
737
|
+
ancestors: new Set(),
|
|
738
|
+
befores: new Set(),
|
|
739
|
+
originBefore: null,
|
|
740
|
+
cache: {rects: new Map(), parts: new Map()},
|
|
741
|
+
scheduled: false,
|
|
742
|
+
beforeMove: [],
|
|
743
|
+
};
|
|
744
|
+
batches.set(area, created);
|
|
745
|
+
// A measurement no commit claims by the next frame (a controlled owner
|
|
746
|
+
// refused the change) is dropped, so it never moves rows later and holds
|
|
747
|
+
// no elements.
|
|
748
|
+
const view = area.ownerDocument.defaultView;
|
|
749
|
+
const drop = () => {
|
|
750
|
+
if (batches.get(area) === created && !created.scheduled) {
|
|
751
|
+
batches.delete(area);
|
|
752
|
+
}
|
|
753
|
+
};
|
|
754
|
+
if (typeof view?.requestAnimationFrame === 'function') {
|
|
755
|
+
view.requestAnimationFrame(drop);
|
|
756
|
+
} else {
|
|
757
|
+
setTimeout(drop, 16);
|
|
758
|
+
}
|
|
759
|
+
batch = created;
|
|
760
|
+
}
|
|
761
|
+
return batch;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
function intersects(a: DOMRect, b: DOMRect): boolean {
|
|
765
|
+
return (
|
|
766
|
+
a.width > 0 &&
|
|
767
|
+
a.height > 0 &&
|
|
768
|
+
a.right > b.left &&
|
|
769
|
+
a.left < b.right &&
|
|
770
|
+
a.bottom > b.top &&
|
|
771
|
+
a.top < b.bottom
|
|
772
|
+
);
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
/** The part of the area the person can see: its box within the viewport. */
|
|
776
|
+
/** Where the area's scrolled content starts, in client px. */
|
|
777
|
+
function originOf(area: Element): {x: number; y: number} {
|
|
778
|
+
const box = area.getBoundingClientRect();
|
|
779
|
+
return {x: box.left - area.scrollLeft, y: box.top - area.scrollTop};
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
function visibleRect(area: Element): DOMRect {
|
|
783
|
+
const box = area.getBoundingClientRect();
|
|
784
|
+
const view = area.ownerDocument.defaultView;
|
|
785
|
+
const width = view?.innerWidth ?? box.right;
|
|
786
|
+
const height = view?.innerHeight ?? box.bottom;
|
|
787
|
+
const left = Math.max(box.left, 0);
|
|
788
|
+
const top = Math.max(box.top, 0);
|
|
789
|
+
return new DOMRect(
|
|
790
|
+
left,
|
|
791
|
+
top,
|
|
792
|
+
Math.max(0, Math.min(box.right, width) - left),
|
|
793
|
+
Math.max(0, Math.min(box.bottom, height) - top),
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
/** The element's rendered scale against its layout size (a scaled ancestor). */
|
|
798
|
+
function scaleOf(
|
|
799
|
+
element: Element,
|
|
800
|
+
rect: DOMRect,
|
|
801
|
+
own: {readonly x: number; readonly y: number} = {x: 1, y: 1},
|
|
802
|
+
): {x: number; y: number} {
|
|
803
|
+
const html = element as HTMLElement;
|
|
804
|
+
const x =
|
|
805
|
+
html.offsetWidth > 0 && rect.width > 0
|
|
806
|
+
? rect.width / html.offsetWidth / own.x
|
|
807
|
+
: 1;
|
|
808
|
+
const y =
|
|
809
|
+
html.offsetHeight > 0 && rect.height > 0
|
|
810
|
+
? rect.height / html.offsetHeight / own.y
|
|
811
|
+
: 1;
|
|
812
|
+
// Subpixel rounding makes an unscaled element read a hair off 1; only a
|
|
813
|
+
// real scale is corrected.
|
|
814
|
+
return {
|
|
815
|
+
x: Math.abs(x - 1) < 0.01 ? 1 : x || 1,
|
|
816
|
+
y: Math.abs(y - 1) < 0.01 ? 1 : y || 1,
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* The scale an element's own `scale` and `transform` give it, on each axis
|
|
822
|
+
* (a follower that keeps one in place, `staysInPlace`). A glide's `translate`
|
|
823
|
+
* does not go through them: the individual transform properties apply
|
|
824
|
+
* `translate` first, in the parent's space.
|
|
825
|
+
*/
|
|
826
|
+
function ownScaleOf(element: Element): {x: number; y: number} {
|
|
827
|
+
const style = element.ownerDocument.defaultView?.getComputedStyle(element);
|
|
828
|
+
if (style == null) {
|
|
829
|
+
return {x: 1, y: 1};
|
|
830
|
+
}
|
|
831
|
+
let x = 1;
|
|
832
|
+
let y = 1;
|
|
833
|
+
const scale = style.getPropertyValue('scale');
|
|
834
|
+
if (scale !== '' && scale !== 'none') {
|
|
835
|
+
const [sx = 1, sy = sx] = numbersIn(scale);
|
|
836
|
+
// Its size, not its direction: a negative scale flips the element in
|
|
837
|
+
// place, and its measured box stays positive.
|
|
838
|
+
x *= Math.abs(sx);
|
|
839
|
+
y *= Math.abs(sy);
|
|
840
|
+
}
|
|
841
|
+
// The computed transform is a matrix: its first column's length is the
|
|
842
|
+
// scale on x, its second's on y.
|
|
843
|
+
const matrix = /^matrix(3d)?\(([^)]*)\)/.exec(
|
|
844
|
+
style.getPropertyValue('transform'),
|
|
845
|
+
);
|
|
846
|
+
if (matrix != null) {
|
|
847
|
+
const m = numbersIn(matrix[2]);
|
|
848
|
+
const [a = 1, b = 0, c = 0, d = 1] =
|
|
849
|
+
matrix[1] == null ? m : [m[0], m[1], m[4], m[5]];
|
|
850
|
+
x *= Math.hypot(a, b);
|
|
851
|
+
y *= Math.hypot(c, d);
|
|
852
|
+
}
|
|
853
|
+
return {x: x || 1, y: y || 1};
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
function flush(batch: Batch): void {
|
|
857
|
+
batches.delete(batch.area);
|
|
858
|
+
const notify = (candidates: ReadonlyArray<Element>) => {
|
|
859
|
+
for (const callback of batch.beforeMove) {
|
|
860
|
+
callback(candidates);
|
|
861
|
+
}
|
|
862
|
+
};
|
|
863
|
+
// What each change's walk measured before it: an element added by the
|
|
864
|
+
// change has no old place, and one it removed is gone.
|
|
865
|
+
const followers = new Set<Element>();
|
|
866
|
+
for (const changed of batch.changed) {
|
|
867
|
+
for (const element of batch.candidates.get(changed) ?? []) {
|
|
868
|
+
if (element.isConnected) {
|
|
869
|
+
followers.add(element);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
if (followers.size === 0) {
|
|
874
|
+
notify([]);
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
const motion = layoutMotion(batch.area);
|
|
878
|
+
if (motion.kind === 'instant') {
|
|
879
|
+
notify([]);
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
const visible = visibleRect(batch.area);
|
|
883
|
+
// Every running glide stops first and every new place is read before any
|
|
884
|
+
// glide starts, so no reading includes another's new motion.
|
|
885
|
+
const entries: {
|
|
886
|
+
readonly element: Element;
|
|
887
|
+
readonly before: DOMRect;
|
|
888
|
+
readonly carried: OffsetCurve;
|
|
889
|
+
readonly carriedMs: number;
|
|
890
|
+
after?: DOMRect;
|
|
891
|
+
rawX?: number;
|
|
892
|
+
rawY?: number;
|
|
893
|
+
isMovedByApp?: boolean;
|
|
894
|
+
scale?: {x: number; y: number};
|
|
895
|
+
}[] = [];
|
|
896
|
+
for (const element of followers) {
|
|
897
|
+
const before = batch.before.get(element);
|
|
898
|
+
if (before == null || (before.width === 0 && before.height === 0)) {
|
|
899
|
+
// Added by the change, or not rendered before it: it has no old place.
|
|
900
|
+
// A changed element an earlier change displaced does have one, and
|
|
901
|
+
// moves with its row while it plays its own entrance or exit.
|
|
902
|
+
continue;
|
|
903
|
+
}
|
|
904
|
+
// An element already gliding keeps that motion and adds the new move: the
|
|
905
|
+
// running glide stops (so its rectangle is its new layout place) and the
|
|
906
|
+
// rest of its curve carries into the one new glide, velocity included,
|
|
907
|
+
// summed with the new move.
|
|
908
|
+
const running = glides.get(element);
|
|
909
|
+
let carried = AT_REST;
|
|
910
|
+
let carriedMs = 0;
|
|
911
|
+
if (running != null) {
|
|
912
|
+
const time = Number(running.animation.currentTime);
|
|
913
|
+
const elapsed = Number.isFinite(time) ? Math.max(0, time) : 0;
|
|
914
|
+
if (elapsed < running.durationMs) {
|
|
915
|
+
carried = t => running.offsetAt(elapsed + t);
|
|
916
|
+
carriedMs = running.durationMs - elapsed;
|
|
917
|
+
}
|
|
918
|
+
running.animation.cancel();
|
|
919
|
+
glides.delete(element);
|
|
920
|
+
}
|
|
921
|
+
entries.push({element, before, carried, carriedMs});
|
|
922
|
+
}
|
|
923
|
+
// Every reading (places, transforms, scales) before any glide starts: a
|
|
924
|
+
// glide started between two readings would make the next one lay the page
|
|
925
|
+
// out again, once per element (on a long page, the whole cost).
|
|
926
|
+
const byElement = new Map<Element, (typeof entries)[number]>();
|
|
927
|
+
// An ancestor of the change, and a sibling before it, move by their layout
|
|
928
|
+
// change alone: when scroll anchoring re-scrolls the area, an outer
|
|
929
|
+
// scroller or the page (a change above the visible part), or the area
|
|
930
|
+
// itself moves as its content grows (a dialog re-centered), their place in
|
|
931
|
+
// view shifts by that while their place in the area stays.
|
|
932
|
+
const origin = originOf(batch.area);
|
|
933
|
+
const scrolledX = origin.x - (batch.originBefore?.x ?? origin.x);
|
|
934
|
+
const scrolledY = origin.y - (batch.originBefore?.y ?? origin.y);
|
|
935
|
+
// Netted only where that makes the move smaller: an element the browser
|
|
936
|
+
// kept in place (scroll anchoring for another change in the same frame)
|
|
937
|
+
// stays where it is.
|
|
938
|
+
const nearer = (raw: number, shift: number) =>
|
|
939
|
+
Math.abs(raw + shift) < Math.abs(raw) ? raw + shift : raw;
|
|
940
|
+
for (const entry of entries) {
|
|
941
|
+
entry.after = entry.element.getBoundingClientRect();
|
|
942
|
+
// The move is the inline-start edge's, by the container's direction (it
|
|
943
|
+
// decides where the element sits): in a right-to-left container an
|
|
944
|
+
// element that narrows keeps its left edge and moves its right one.
|
|
945
|
+
const container = entry.element.parentElement ?? entry.element;
|
|
946
|
+
const isRtl =
|
|
947
|
+
container.ownerDocument.defaultView?.getComputedStyle(container)
|
|
948
|
+
.direction === 'rtl';
|
|
949
|
+
const rawX = isRtl
|
|
950
|
+
? entry.before.right - entry.after.right
|
|
951
|
+
: entry.before.left - entry.after.left;
|
|
952
|
+
const rawY = entry.before.top - entry.after.top;
|
|
953
|
+
// The siblings before the change stay with the ancestors around them.
|
|
954
|
+
const isAncestor =
|
|
955
|
+
batch.ancestors.has(entry.element) || batch.befores.has(entry.element);
|
|
956
|
+
entry.rawX = isAncestor ? nearer(rawX, scrolledX) : rawX;
|
|
957
|
+
entry.rawY = isAncestor ? nearer(rawY, scrolledY) : rawY;
|
|
958
|
+
byElement.set(entry.element, entry);
|
|
959
|
+
}
|
|
960
|
+
for (const entry of entries) {
|
|
961
|
+
const after = entry.after as DOMRect;
|
|
962
|
+
if (intersects(entry.before, visible) || intersects(after, visible)) {
|
|
963
|
+
entry.isMovedByApp = movedByApp(entry.element);
|
|
964
|
+
// Only its ancestors' scale is corrected: its own scale or transform
|
|
965
|
+
// (a press's scale) does not apply to the glide's `translate`.
|
|
966
|
+
entry.scale = scaleOf(entry.element, after, ownScaleOf(entry.element));
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
// An adopter's own readings join them here, before any glide starts.
|
|
970
|
+
notify(entries.map(entry => entry.element));
|
|
971
|
+
for (const entry of entries) {
|
|
972
|
+
const {element, before, carried, carriedMs} = entry;
|
|
973
|
+
const after = entry.after as DOMRect;
|
|
974
|
+
// Nested changes compose: an element inside another moving element moves
|
|
975
|
+
// only by its own change, whatever order the changes were reported in.
|
|
976
|
+
let dx = entry.rawX ?? 0;
|
|
977
|
+
let dy = entry.rawY ?? 0;
|
|
978
|
+
for (
|
|
979
|
+
let ancestor = element.parentElement;
|
|
980
|
+
ancestor != null && ancestor !== batch.area;
|
|
981
|
+
ancestor = ancestor.parentElement
|
|
982
|
+
) {
|
|
983
|
+
const moving = byElement.get(ancestor);
|
|
984
|
+
if (moving != null) {
|
|
985
|
+
dx -= moving.rawX ?? 0;
|
|
986
|
+
dy -= moving.rawY ?? 0;
|
|
987
|
+
break;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
if (Math.abs(dx) < MIN_SHIFT_PX && Math.abs(dy) < MIN_SHIFT_PX) {
|
|
991
|
+
continue;
|
|
992
|
+
}
|
|
993
|
+
if (!intersects(before, visible) && !intersects(after, visible)) {
|
|
994
|
+
// Outside the visible part before and after: it lands silently.
|
|
995
|
+
continue;
|
|
996
|
+
}
|
|
997
|
+
if (motion.kind === 'fade') {
|
|
998
|
+
safeAnimate(element, [{opacity: 0}, {opacity: 1}], {
|
|
999
|
+
duration: motion.durationMs,
|
|
1000
|
+
easing: motion.easing,
|
|
1001
|
+
});
|
|
1002
|
+
continue;
|
|
1003
|
+
}
|
|
1004
|
+
if (entry.isMovedByApp === true) {
|
|
1005
|
+
// The app moves it itself: it takes its final place at once
|
|
1006
|
+
// (`spec:AST-105` Coverage).
|
|
1007
|
+
continue;
|
|
1008
|
+
}
|
|
1009
|
+
// Where it shows now, against its new place, in its own px; the part the
|
|
1010
|
+
// carried glide does not cover is the new move.
|
|
1011
|
+
const scale = entry.scale ?? {x: 1, y: 1};
|
|
1012
|
+
const now = carried(0);
|
|
1013
|
+
const moveX = dx / scale.x - now.x;
|
|
1014
|
+
const moveY = dy / scale.y - now.y;
|
|
1015
|
+
const {progress} = motion;
|
|
1016
|
+
const offsetAt: OffsetCurve = t => {
|
|
1017
|
+
const remaining = progress.remaining(t);
|
|
1018
|
+
const carry = carried(t);
|
|
1019
|
+
return {x: carry.x + moveX * remaining, y: carry.y + moveY * remaining};
|
|
1020
|
+
};
|
|
1021
|
+
const durationMs = Math.max(progress.durationMs, carriedMs);
|
|
1022
|
+
// One replace-composited `translate`: the compositor runs it (INV12).
|
|
1023
|
+
const animation = safeAnimate(
|
|
1024
|
+
element,
|
|
1025
|
+
sampleOver(durationMs, t => {
|
|
1026
|
+
const offset = offsetAt(t);
|
|
1027
|
+
return {translate: `${offset.x}px ${offset.y}px`};
|
|
1028
|
+
}),
|
|
1029
|
+
{duration: durationMs, easing: 'linear'},
|
|
1030
|
+
);
|
|
1031
|
+
if (animation != null) {
|
|
1032
|
+
const glide: Glide = {animation, offsetAt, durationMs};
|
|
1033
|
+
glides.set(element, glide);
|
|
1034
|
+
animation.addEventListener?.('finish', () => {
|
|
1035
|
+
if (glides.get(element) === glide) {
|
|
1036
|
+
glides.delete(element);
|
|
1037
|
+
}
|
|
1038
|
+
});
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
type Target = {readonly current: Element | null} | (() => Element | null);
|
|
1044
|
+
|
|
1045
|
+
function resolve(target: Target): Element | null {
|
|
1046
|
+
return typeof target === 'function' ? target() : target.current;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
export interface LayoutChange {
|
|
1050
|
+
/** Before the change commits (in the event handler that causes it). */
|
|
1051
|
+
measureBefore(): void;
|
|
1052
|
+
/**
|
|
1053
|
+
* After it commits (a layout effect). Returns whether the change was
|
|
1054
|
+
* measured: an unmeasured change (an owner set the state directly) moves
|
|
1055
|
+
* nothing, and the component plays no entrance for it either.
|
|
1056
|
+
*
|
|
1057
|
+
* `beforeMove`, when given, runs once the new places are read and before
|
|
1058
|
+
* any glide starts, with the elements the glide may move: whatever the
|
|
1059
|
+
* component reads from the layout for the glide, it reads there, so the page
|
|
1060
|
+
* is not laid out again (`playLayoutChange` included).
|
|
1061
|
+
*/
|
|
1062
|
+
animate(beforeMove?: (candidates: ReadonlyArray<Element>) => void): boolean;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
/**
|
|
1066
|
+
* Report a size change of `target` to the handle's area. Call
|
|
1067
|
+
* `measureBefore()` before the change commits and `animate()` after it; the
|
|
1068
|
+
* content after `target`, up to the area, glides from its old place.
|
|
1069
|
+
* Changes in one area in one frame move together. Without a handle, or
|
|
1070
|
+
* outside its container, nothing moves.
|
|
1071
|
+
*/
|
|
1072
|
+
export function reportLayoutChange(
|
|
1073
|
+
handle: AnimatedLayout | null | undefined,
|
|
1074
|
+
target: Target,
|
|
1075
|
+
): LayoutChange {
|
|
1076
|
+
return {
|
|
1077
|
+
measureBefore() {
|
|
1078
|
+
const element = resolve(target);
|
|
1079
|
+
if (element == null || handle == null) {
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
const area = areaOf(handle, element);
|
|
1083
|
+
if (area == null) {
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
1086
|
+
const batch = batchFor(area);
|
|
1087
|
+
if (batch.changed.has(element)) {
|
|
1088
|
+
return;
|
|
1089
|
+
}
|
|
1090
|
+
batch.changed.add(element);
|
|
1091
|
+
batch.changedSize += rectOf(element, batch.cache).height;
|
|
1092
|
+
batch.visible ??= visibleRect(area);
|
|
1093
|
+
batch.originBefore ??= originOf(area);
|
|
1094
|
+
batch.walksToBand ??=
|
|
1095
|
+
area.ownerDocument.defaultView
|
|
1096
|
+
?.getComputedStyle(area)
|
|
1097
|
+
.getPropertyValue('overflow-anchor') === 'none';
|
|
1098
|
+
// Changes in one frame add up: every change's walk reaches the band
|
|
1099
|
+
// their summed size can pull into view. When that outgrows the band
|
|
1100
|
+
// walked so far, the band at least doubles and every change is walked
|
|
1101
|
+
// again (from the cache), so a frame of many changes re-walks a few
|
|
1102
|
+
// times, not once per change.
|
|
1103
|
+
const needed = Math.max(batch.visible.height, batch.changedSize);
|
|
1104
|
+
const walks = needed > batch.reach ? [...batch.changed] : [element];
|
|
1105
|
+
if (needed > batch.reach) {
|
|
1106
|
+
batch.reach = Math.max(needed, batch.reach * 2);
|
|
1107
|
+
}
|
|
1108
|
+
const band = bandFor(batch.visible, batch.reach);
|
|
1109
|
+
for (const changed of walks) {
|
|
1110
|
+
const candidates = collectCandidates(
|
|
1111
|
+
changed,
|
|
1112
|
+
area,
|
|
1113
|
+
band,
|
|
1114
|
+
batch.cache,
|
|
1115
|
+
batch.walksToBand,
|
|
1116
|
+
batch.ancestors,
|
|
1117
|
+
batch.befores,
|
|
1118
|
+
);
|
|
1119
|
+
for (const [candidate, rect] of candidates) {
|
|
1120
|
+
if (!batch.before.has(candidate)) {
|
|
1121
|
+
batch.before.set(candidate, rect);
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
batch.candidates.set(changed, [...candidates.keys()]);
|
|
1125
|
+
}
|
|
1126
|
+
},
|
|
1127
|
+
animate(beforeMove) {
|
|
1128
|
+
const element = resolve(target);
|
|
1129
|
+
if (element == null || handle == null) {
|
|
1130
|
+
return false;
|
|
1131
|
+
}
|
|
1132
|
+
const area = areaOf(handle, element);
|
|
1133
|
+
const batch = area == null ? undefined : batches.get(area);
|
|
1134
|
+
if (batch == null || !batch.changed.has(element)) {
|
|
1135
|
+
return false;
|
|
1136
|
+
}
|
|
1137
|
+
if (beforeMove != null) {
|
|
1138
|
+
batch.beforeMove.push(beforeMove);
|
|
1139
|
+
}
|
|
1140
|
+
if (!batch.scheduled) {
|
|
1141
|
+
batch.scheduled = true;
|
|
1142
|
+
// After every layout effect of this commit, before paint.
|
|
1143
|
+
queueMicrotask(() => flush(batch));
|
|
1144
|
+
}
|
|
1145
|
+
return true;
|
|
1146
|
+
},
|
|
1147
|
+
};
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
/**
|
|
1151
|
+
* The changed element's own animation, on the same motion as the content
|
|
1152
|
+
* after it: content that appears reveals downward from its top edge. Plays
|
|
1153
|
+
* only with a handle, inside its area and in the area's visible part.
|
|
1154
|
+
* Returns the entrance it started, or null when it played none.
|
|
1155
|
+
*/
|
|
1156
|
+
export function playLayoutChange(
|
|
1157
|
+
handle: AnimatedLayout | null | undefined,
|
|
1158
|
+
element: Element,
|
|
1159
|
+
): Animation | null {
|
|
1160
|
+
if (handle == null) {
|
|
1161
|
+
return null;
|
|
1162
|
+
}
|
|
1163
|
+
const area = areaOf(handle, element);
|
|
1164
|
+
if (area == null) {
|
|
1165
|
+
return null;
|
|
1166
|
+
}
|
|
1167
|
+
if (!intersects(element.getBoundingClientRect(), visibleRect(area))) {
|
|
1168
|
+
return null;
|
|
1169
|
+
}
|
|
1170
|
+
const motion = layoutMotion(area);
|
|
1171
|
+
if (motion.kind === 'instant') {
|
|
1172
|
+
return null;
|
|
1173
|
+
}
|
|
1174
|
+
if (motion.kind === 'fade') {
|
|
1175
|
+
return safeAnimate(element, [{opacity: 0}, {opacity: 1}], {
|
|
1176
|
+
duration: motion.durationMs,
|
|
1177
|
+
easing: motion.easing,
|
|
1178
|
+
});
|
|
1179
|
+
}
|
|
1180
|
+
return safeAnimate(
|
|
1181
|
+
element,
|
|
1182
|
+
sampleKeyframes(motion.progress, remaining => ({
|
|
1183
|
+
opacity: 1 - remaining,
|
|
1184
|
+
clipPath: `inset(0 0 ${round(remaining * 100)}% 0)`,
|
|
1185
|
+
})),
|
|
1186
|
+
{duration: motion.progress.durationMs, easing: 'linear'},
|
|
1187
|
+
);
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
/** The inline properties an exit sets, so a release removes exactly them. */
|
|
1191
|
+
const EXIT_PROPERTIES = [
|
|
1192
|
+
'margin-block-end',
|
|
1193
|
+
'margin-inline-end',
|
|
1194
|
+
'pointer-events',
|
|
1195
|
+
] as const;
|
|
1196
|
+
|
|
1197
|
+
/**
|
|
1198
|
+
* The first element after `element` in the area that takes part in layout:
|
|
1199
|
+
* its next sibling, or its nearest ancestor's below the area. A wrapper's
|
|
1200
|
+
* edge is not used: a negative end margin can collapse through it.
|
|
1201
|
+
*/
|
|
1202
|
+
function nextInFlow(element: Element, area: Element): Element | null {
|
|
1203
|
+
const view = element.ownerDocument.defaultView;
|
|
1204
|
+
// The first box at or inside `from` (a `display: contents` element has
|
|
1205
|
+
// none of its own: its children stand in its place).
|
|
1206
|
+
const firstBox = (from: Element): Element | null => {
|
|
1207
|
+
const style = view?.getComputedStyle(from);
|
|
1208
|
+
if (style == null) {
|
|
1209
|
+
return from;
|
|
1210
|
+
}
|
|
1211
|
+
if (style.display === 'contents') {
|
|
1212
|
+
for (
|
|
1213
|
+
let child = from.firstElementChild;
|
|
1214
|
+
child != null;
|
|
1215
|
+
child = child.nextElementSibling
|
|
1216
|
+
) {
|
|
1217
|
+
const box = firstBox(child);
|
|
1218
|
+
if (box != null) {
|
|
1219
|
+
return box;
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
return null;
|
|
1223
|
+
}
|
|
1224
|
+
return takesPart(from, style) ? from : null;
|
|
1225
|
+
};
|
|
1226
|
+
let node: Element | null = element;
|
|
1227
|
+
while (node != null && node !== area) {
|
|
1228
|
+
for (
|
|
1229
|
+
let sibling = node.nextElementSibling;
|
|
1230
|
+
sibling != null;
|
|
1231
|
+
sibling = sibling.nextElementSibling
|
|
1232
|
+
) {
|
|
1233
|
+
const box = firstBox(sibling);
|
|
1234
|
+
if (box != null) {
|
|
1235
|
+
return box;
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
node = node.parentElement;
|
|
1239
|
+
}
|
|
1240
|
+
return null;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
/**
|
|
1244
|
+
* An element's place: its block start, and its inline start (RTL read right
|
|
1245
|
+
* to left).
|
|
1246
|
+
*/
|
|
1247
|
+
function placeOf(
|
|
1248
|
+
element: Element,
|
|
1249
|
+
rtl: boolean,
|
|
1250
|
+
): {block: number; inline: number} {
|
|
1251
|
+
const rect = element.getBoundingClientRect();
|
|
1252
|
+
return {block: rect.top, inline: rtl ? -rect.right : rect.left};
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
/**
|
|
1256
|
+
* Keeps `element` where it is, in flow (so it scrolls and clips with its
|
|
1257
|
+
* container), while the content after it takes the place it takes once the
|
|
1258
|
+
* element is hidden: a negative end margin measured against that content,
|
|
1259
|
+
* so a gap or collapsing margins come out exact. Returns false, setting
|
|
1260
|
+
* nothing, when no margin reaches that place.
|
|
1261
|
+
*/
|
|
1262
|
+
function giveUpSpace(element: HTMLElement, area: Element): boolean {
|
|
1263
|
+
const view = element.ownerDocument.defaultView;
|
|
1264
|
+
const parent =
|
|
1265
|
+
element.parentElement == null
|
|
1266
|
+
? undefined
|
|
1267
|
+
: view?.getComputedStyle(element.parentElement);
|
|
1268
|
+
const isRow =
|
|
1269
|
+
parent != null &&
|
|
1270
|
+
parent.display.includes('flex') &&
|
|
1271
|
+
parent.flexDirection.startsWith('row');
|
|
1272
|
+
const rtl = view?.getComputedStyle(element).direction === 'rtl';
|
|
1273
|
+
const property = isRow ? 'margin-inline-end' : 'margin-block-end';
|
|
1274
|
+
const size = isRow ? element.offsetWidth : element.offsetHeight;
|
|
1275
|
+
const next = nextInFlow(element, area);
|
|
1276
|
+
if (next == null) {
|
|
1277
|
+
// Nothing after it in the area to land anywhere.
|
|
1278
|
+
element.style.setProperty(property, `${-size}px`);
|
|
1279
|
+
return true;
|
|
1280
|
+
}
|
|
1281
|
+
const own = element.style.getPropertyValue(property);
|
|
1282
|
+
const ownPriority = element.style.getPropertyPriority(property);
|
|
1283
|
+
const axis = isRow ? 'inline' : 'block';
|
|
1284
|
+
// The content after its container must land too: a flex-row item that
|
|
1285
|
+
// sets its row's height moves what follows the row.
|
|
1286
|
+
const afterParent =
|
|
1287
|
+
element.parentElement == null || element.parentElement === area
|
|
1288
|
+
? null
|
|
1289
|
+
: nextInFlow(element.parentElement, area);
|
|
1290
|
+
const checked = afterParent == null ? [next] : [next, afterParent];
|
|
1291
|
+
// The element's scale, read in the layout the caller's visibility check
|
|
1292
|
+
// already laid out.
|
|
1293
|
+
const scale = scaleOf(element, element.getBoundingClientRect());
|
|
1294
|
+
// Where the content after it goes once it is hidden, read with it taken
|
|
1295
|
+
// out of flow (not `display: none`, which would restart the CSS animations
|
|
1296
|
+
// inside it).
|
|
1297
|
+
const position = element.style.getPropertyValue('position');
|
|
1298
|
+
const positionPriority = element.style.getPropertyPriority('position');
|
|
1299
|
+
element.style.setProperty('position', 'absolute', 'important');
|
|
1300
|
+
const targets = checked.map(box => placeOf(box, rtl));
|
|
1301
|
+
const target = targets[0];
|
|
1302
|
+
if (position === '') {
|
|
1303
|
+
element.style.removeProperty('position');
|
|
1304
|
+
} else {
|
|
1305
|
+
element.style.setProperty('position', position, positionPriority);
|
|
1306
|
+
}
|
|
1307
|
+
// The reading is in screen px, the margin in the element's own: under a
|
|
1308
|
+
// scaled ancestor a distance is divided by the scale on this axis.
|
|
1309
|
+
const perPx = isRow ? scale.x : scale.y;
|
|
1310
|
+
// A first guess (its box), then one correction from the measured result:
|
|
1311
|
+
// a gap, a collapsed margin or the element's own margins.
|
|
1312
|
+
element.style.setProperty(property, `${-size}px`);
|
|
1313
|
+
const guess = placeOf(next, rtl)[axis];
|
|
1314
|
+
const correction = (target[axis] - guess) / perPx;
|
|
1315
|
+
element.style.setProperty(property, `${-size + correction}px`);
|
|
1316
|
+
// Everything checked must land on both axes: a flex-row item that sets
|
|
1317
|
+
// its row's height frees no block space with an inline margin.
|
|
1318
|
+
const missed = checked.some((box, index) => {
|
|
1319
|
+
const landed = placeOf(box, rtl);
|
|
1320
|
+
return (
|
|
1321
|
+
Math.abs(landed.block - targets[index].block) > 1 ||
|
|
1322
|
+
Math.abs(landed.inline - targets[index].inline) > 1
|
|
1323
|
+
);
|
|
1324
|
+
});
|
|
1325
|
+
if (missed) {
|
|
1326
|
+
if (own === '') {
|
|
1327
|
+
element.style.removeProperty(property);
|
|
1328
|
+
} else {
|
|
1329
|
+
element.style.setProperty(property, own, ownPriority);
|
|
1330
|
+
}
|
|
1331
|
+
return false;
|
|
1332
|
+
}
|
|
1333
|
+
return true;
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
/** Exits holding an element back, so a release can stop one. */
|
|
1337
|
+
const exits = new WeakMap<Element, Animation | null>();
|
|
1338
|
+
|
|
1339
|
+
/** What an exit replaced on its element, so a release puts back exactly it. */
|
|
1340
|
+
interface Replaced {
|
|
1341
|
+
readonly inert: boolean;
|
|
1342
|
+
readonly styles: ReadonlyArray<readonly [string, string, string]>;
|
|
1343
|
+
}
|
|
1344
|
+
const replaced = new WeakMap<Element, Replaced>();
|
|
1345
|
+
|
|
1346
|
+
/**
|
|
1347
|
+
* The changed element's exit (`spec:AST-105` FR4): content that disappears
|
|
1348
|
+
* keeps its place on screen but gives up its space (a negative end margin
|
|
1349
|
+
* measured against the layout without it, so the content after it glides up
|
|
1350
|
+
* at once to exactly where it ends, and it still scrolls and clips with its
|
|
1351
|
+
* container), is inert (no focus, no pointer, nothing read), conceals upward
|
|
1352
|
+
* from its bottom edge on the same motion, and then `done` runs, when the
|
|
1353
|
+
* component hides or unmounts it. Under Reduce Motion with a coarse primary pointer it
|
|
1354
|
+
* fades instead. Call it in the layout effect of the commit that closes the
|
|
1355
|
+
* element, after the change's `animate()` reported it measured, in the same
|
|
1356
|
+
* task: the glide reads the layout once the element has given up its space.
|
|
1357
|
+
*
|
|
1358
|
+
* Returns false, holding nothing, when the exit lands at once: no handle, a
|
|
1359
|
+
* close no change in the area measured, outside the area or its visible part,
|
|
1360
|
+
* Reduce Motion with a fine pointer, or a layout no end margin can free (a
|
|
1361
|
+
* grid track and its gap, a flex-row item that sets its row's height); in
|
|
1362
|
+
* that last case the content after it takes its final place at once too.
|
|
1363
|
+
* The component then hides the element itself.
|
|
1364
|
+
*/
|
|
1365
|
+
export function holdLayoutExit(
|
|
1366
|
+
handle: AnimatedLayout | null | undefined,
|
|
1367
|
+
element: HTMLElement,
|
|
1368
|
+
done: () => void,
|
|
1369
|
+
): boolean {
|
|
1370
|
+
if (handle == null) {
|
|
1371
|
+
return false;
|
|
1372
|
+
}
|
|
1373
|
+
const area = areaOf(handle, element);
|
|
1374
|
+
if (
|
|
1375
|
+
area == null ||
|
|
1376
|
+
!intersects(element.getBoundingClientRect(), visibleRect(area))
|
|
1377
|
+
) {
|
|
1378
|
+
return false;
|
|
1379
|
+
}
|
|
1380
|
+
// Only a measured close exits: the content after it glides into its place.
|
|
1381
|
+
const batch = batches.get(area);
|
|
1382
|
+
if (
|
|
1383
|
+
batch == null ||
|
|
1384
|
+
![...batch.changed].some(
|
|
1385
|
+
changed => changed === element || changed.contains(element),
|
|
1386
|
+
)
|
|
1387
|
+
) {
|
|
1388
|
+
return false;
|
|
1389
|
+
}
|
|
1390
|
+
const motion = layoutMotion(area);
|
|
1391
|
+
if (motion.kind === 'instant') {
|
|
1392
|
+
return false;
|
|
1393
|
+
}
|
|
1394
|
+
releaseLayoutExit(element);
|
|
1395
|
+
const prior: Replaced = {
|
|
1396
|
+
inert: element.hasAttribute('inert'),
|
|
1397
|
+
styles: EXIT_PROPERTIES.map(
|
|
1398
|
+
property =>
|
|
1399
|
+
[
|
|
1400
|
+
property,
|
|
1401
|
+
element.style.getPropertyValue(property),
|
|
1402
|
+
element.style.getPropertyPriority(property),
|
|
1403
|
+
] as const,
|
|
1404
|
+
),
|
|
1405
|
+
};
|
|
1406
|
+
if (!giveUpSpace(element, area)) {
|
|
1407
|
+
// A layout no end margin can free (a grid track and its gap, a flex-row
|
|
1408
|
+
// item that sets its row's height): it hides at once, and the content
|
|
1409
|
+
// after it takes its final place at once (`spec:AST-105` out of
|
|
1410
|
+
// coverage).
|
|
1411
|
+
for (const changed of [...batch.changed]) {
|
|
1412
|
+
if (changed === element || changed.contains(element)) {
|
|
1413
|
+
batch.changed.delete(changed);
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
return false;
|
|
1417
|
+
}
|
|
1418
|
+
replaced.set(element, prior);
|
|
1419
|
+
// Out of reach while it conceals: no focus, no pointer, nothing read.
|
|
1420
|
+
element.setAttribute('inert', '');
|
|
1421
|
+
element.style.setProperty('pointer-events', 'none');
|
|
1422
|
+
const animation =
|
|
1423
|
+
motion.kind === 'fade'
|
|
1424
|
+
? safeAnimate(element, [{opacity: 1}, {opacity: 0}], {
|
|
1425
|
+
duration: motion.durationMs,
|
|
1426
|
+
easing: motion.easing,
|
|
1427
|
+
fill: 'forwards',
|
|
1428
|
+
})
|
|
1429
|
+
: safeAnimate(
|
|
1430
|
+
element,
|
|
1431
|
+
sampleKeyframes(motion.progress, remaining => ({
|
|
1432
|
+
opacity: remaining,
|
|
1433
|
+
clipPath: `inset(0 0 ${round((1 - remaining) * 100)}% 0)`,
|
|
1434
|
+
})),
|
|
1435
|
+
{
|
|
1436
|
+
duration: motion.progress.durationMs,
|
|
1437
|
+
easing: 'linear',
|
|
1438
|
+
fill: 'forwards',
|
|
1439
|
+
},
|
|
1440
|
+
);
|
|
1441
|
+
exits.set(element, animation);
|
|
1442
|
+
if (animation == null) {
|
|
1443
|
+
// No Web Animations: nothing to wait for.
|
|
1444
|
+
done();
|
|
1445
|
+
return true;
|
|
1446
|
+
}
|
|
1447
|
+
animation.addEventListener?.('finish', () => {
|
|
1448
|
+
if (exits.get(element) === animation) {
|
|
1449
|
+
done();
|
|
1450
|
+
}
|
|
1451
|
+
});
|
|
1452
|
+
return true;
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
/**
|
|
1456
|
+
* Puts an element `holdLayoutExit` held back: stops its exit and puts back
|
|
1457
|
+
* what the exit replaced (its `inert` and inline values as they were). Called
|
|
1458
|
+
* once the component has hidden the element, or when the element opens again
|
|
1459
|
+
* mid-exit.
|
|
1460
|
+
*/
|
|
1461
|
+
export function releaseLayoutExit(element: HTMLElement): void {
|
|
1462
|
+
if (!exits.has(element)) {
|
|
1463
|
+
return;
|
|
1464
|
+
}
|
|
1465
|
+
exits.get(element)?.cancel();
|
|
1466
|
+
exits.delete(element);
|
|
1467
|
+
const prior = replaced.get(element);
|
|
1468
|
+
replaced.delete(element);
|
|
1469
|
+
if (prior?.inert !== true) {
|
|
1470
|
+
element.removeAttribute('inert');
|
|
1471
|
+
}
|
|
1472
|
+
for (const [property, value, priority] of prior?.styles ?? []) {
|
|
1473
|
+
if (value === '') {
|
|
1474
|
+
element.style.removeProperty(property);
|
|
1475
|
+
} else {
|
|
1476
|
+
element.style.setProperty(property, value, priority);
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
// ---------------------------------------------------------------------------
|
|
1482
|
+
// The in-place swap
|
|
1483
|
+
// ---------------------------------------------------------------------------
|
|
1484
|
+
|
|
1485
|
+
/**
|
|
1486
|
+
* Old content held as one transient copy while new content enters in its
|
|
1487
|
+
* place (`spec:AST-105` FR8): inert, hidden from assistive technology, and
|
|
1488
|
+
* removed when the swap ends (`architecture:component-style-authoring` INV7).
|
|
1489
|
+
*/
|
|
1490
|
+
export interface LayoutSwap {
|
|
1491
|
+
readonly area: Element;
|
|
1492
|
+
readonly copy: HTMLElement;
|
|
1493
|
+
/** Where the old content showed, in viewport coordinates. */
|
|
1494
|
+
readonly rect: DOMRect;
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
/** How far a ridden element has moved since the swap began. */
|
|
1498
|
+
export interface LayoutRide {
|
|
1499
|
+
readonly x: number;
|
|
1500
|
+
readonly y: number;
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
/**
|
|
1504
|
+
* How a swap plays, as frames over its progress (0 → 1) and, with
|
|
1505
|
+
* `rideWith`, the ridden element's travel so far.
|
|
1506
|
+
*/
|
|
1507
|
+
export interface LayoutSwapMotion {
|
|
1508
|
+
/** The box the copy is laid out in, over the old content's place. */
|
|
1509
|
+
readonly host: Element;
|
|
1510
|
+
/** The copy's frames while it travels. */
|
|
1511
|
+
readonly copy: (p: number, ride: LayoutRide) => Keyframe;
|
|
1512
|
+
/** Its text's opacity, on its own curve, when that differs from the copy's. */
|
|
1513
|
+
readonly copyText?: (p: number) => number;
|
|
1514
|
+
/** The copy paints above its neighbours, in the background it shows. */
|
|
1515
|
+
readonly isOpaque?: boolean;
|
|
1516
|
+
/**
|
|
1517
|
+
* An element the glide moves, such as the column the old content sat in.
|
|
1518
|
+
* Every part plays over its glide, frame by frame, and is told how far it
|
|
1519
|
+
* has moved; the copy rides it unless `isCopyMoved` is false. Without a
|
|
1520
|
+
* glide (it lands silently) the ride is the whole `travel` at once (its
|
|
1521
|
+
* old place less its new).
|
|
1522
|
+
*/
|
|
1523
|
+
readonly rideWith?: {
|
|
1524
|
+
readonly element: Element;
|
|
1525
|
+
readonly travel: LayoutRide;
|
|
1526
|
+
readonly isCopyMoved?: boolean;
|
|
1527
|
+
};
|
|
1528
|
+
/** Called once when the swap ends, however it ends. */
|
|
1529
|
+
readonly onEnd?: () => void;
|
|
1530
|
+
/** Elements the page already renders, entering with the swap. */
|
|
1531
|
+
readonly incoming: ReadonlyArray<{
|
|
1532
|
+
readonly element: Element;
|
|
1533
|
+
readonly frames: (p: number, ride: LayoutRide) => Keyframe;
|
|
1534
|
+
}>;
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
const NO_RIDE: LayoutRide = {x: 0, y: 0};
|
|
1538
|
+
|
|
1539
|
+
/**
|
|
1540
|
+
* Before a change commits: hold `element`'s old content as one transient copy
|
|
1541
|
+
* (`spec:AST-105` FR8). With `isVisiblePart`, the copy is the element's
|
|
1542
|
+
* visible part, its content scrolled as it was (a scroll container). Returns
|
|
1543
|
+
* null without a handle, outside its area, under an immediate change, or for
|
|
1544
|
+
* content too large to copy.
|
|
1545
|
+
*/
|
|
1546
|
+
export function holdLayoutSwap(
|
|
1547
|
+
handle: AnimatedLayout | null | undefined,
|
|
1548
|
+
element: HTMLElement,
|
|
1549
|
+
{isVisiblePart = false}: {isVisiblePart?: boolean} = {},
|
|
1550
|
+
): LayoutSwap | null {
|
|
1551
|
+
if (handle == null || typeof element.animate !== 'function') {
|
|
1552
|
+
return null;
|
|
1553
|
+
}
|
|
1554
|
+
const area = areaOf(handle, element);
|
|
1555
|
+
if (
|
|
1556
|
+
area == null ||
|
|
1557
|
+
layoutMotion(area).kind === 'instant' ||
|
|
1558
|
+
!isCopyable(element)
|
|
1559
|
+
) {
|
|
1560
|
+
return null;
|
|
1561
|
+
}
|
|
1562
|
+
const box = element.getBoundingClientRect();
|
|
1563
|
+
if (!isVisiblePart) {
|
|
1564
|
+
const copy = inertCopy(element);
|
|
1565
|
+
return copy == null ? null : {area, copy, rect: box};
|
|
1566
|
+
}
|
|
1567
|
+
const part = visiblePartCopy(element);
|
|
1568
|
+
return part == null ? null : {area, ...part};
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
/**
|
|
1572
|
+
* After the change commits, before paint: the copy leaves while the incoming
|
|
1573
|
+
* elements enter, on FR4's one motion, every part started on the same
|
|
1574
|
+
* timeline time. Under Reduce Motion with a coarse pointer, only opacity
|
|
1575
|
+
* changes (`design:reduced-motion` DR2). Returns what ends the swap at once;
|
|
1576
|
+
* it also ends when its motion does, and the copy is removed.
|
|
1577
|
+
*/
|
|
1578
|
+
export function playLayoutSwap(
|
|
1579
|
+
swap: LayoutSwap,
|
|
1580
|
+
how: LayoutSwapMotion,
|
|
1581
|
+
): () => void {
|
|
1582
|
+
const motion = layoutMotion(swap.area);
|
|
1583
|
+
if (motion.kind === 'instant') {
|
|
1584
|
+
return () => {};
|
|
1585
|
+
}
|
|
1586
|
+
const {copy} = swap;
|
|
1587
|
+
placeOver(copy, how.host, swap.rect);
|
|
1588
|
+
if (how.isOpaque === true) {
|
|
1589
|
+
copy.style.zIndex = '1';
|
|
1590
|
+
copy.style.backgroundColor = paintedBackground(copy);
|
|
1591
|
+
}
|
|
1592
|
+
const animations: Animation[] = [];
|
|
1593
|
+
let isDone = false;
|
|
1594
|
+
const end = () => {
|
|
1595
|
+
if (isDone) {
|
|
1596
|
+
return;
|
|
1597
|
+
}
|
|
1598
|
+
isDone = true;
|
|
1599
|
+
animations.forEach(animation => animation.cancel());
|
|
1600
|
+
copy.remove();
|
|
1601
|
+
how.onEnd?.();
|
|
1602
|
+
};
|
|
1603
|
+
const {copyText, rideWith} = how;
|
|
1604
|
+
const fadedText =
|
|
1605
|
+
copyText != null && motion.kind === 'spring' ? wrapText(copy) : [];
|
|
1606
|
+
// Each part as a function of time: its frame, or the copy's with its ride.
|
|
1607
|
+
const parts: [Element, (p: number, ride: LayoutRide) => Keyframe][] = [];
|
|
1608
|
+
if (motion.kind === 'spring') {
|
|
1609
|
+
const moves = rideWith != null && rideWith.isCopyMoved !== false;
|
|
1610
|
+
parts.push([
|
|
1611
|
+
copy,
|
|
1612
|
+
(p, ride) => ({
|
|
1613
|
+
...how.copy(p, ride),
|
|
1614
|
+
...(moves ? {translate: `${ride.x}px ${ride.y}px`} : null),
|
|
1615
|
+
}),
|
|
1616
|
+
]);
|
|
1617
|
+
for (const span of fadedText) {
|
|
1618
|
+
parts.push([span, p => ({opacity: copyText?.(p) ?? 1})]);
|
|
1619
|
+
}
|
|
1620
|
+
for (const {element, frames} of how.incoming) {
|
|
1621
|
+
parts.push([element, frames]);
|
|
1622
|
+
}
|
|
1623
|
+
} else {
|
|
1624
|
+
// Reduce Motion with a coarse pointer: only opacity changes.
|
|
1625
|
+
parts.push([copy, p => ({opacity: 1 - p})]);
|
|
1626
|
+
for (const {element} of how.incoming) {
|
|
1627
|
+
parts.push([element, p => ({opacity: p})]);
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
const playAll = (
|
|
1631
|
+
durationMs: number,
|
|
1632
|
+
progressAt: (t: number) => number,
|
|
1633
|
+
rideAt: (t: number) => LayoutRide,
|
|
1634
|
+
options: KeyframeAnimationOptions,
|
|
1635
|
+
sample: (shape: (t: number) => Keyframe) => Keyframe[],
|
|
1636
|
+
) => {
|
|
1637
|
+
for (const [element, shape] of parts) {
|
|
1638
|
+
const animation = safeAnimate(
|
|
1639
|
+
element,
|
|
1640
|
+
sample(t => shape(progressAt(t), rideAt(t))),
|
|
1641
|
+
{duration: durationMs, fill: 'both', ...options},
|
|
1642
|
+
);
|
|
1643
|
+
if (animation != null) {
|
|
1644
|
+
animations.push(animation);
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
if (animations.length === 0) {
|
|
1648
|
+
end();
|
|
1649
|
+
} else {
|
|
1650
|
+
// Every part runs on one clock, so the first to finish ends them all.
|
|
1651
|
+
animations[0].addEventListener?.('finish', end);
|
|
1652
|
+
}
|
|
1653
|
+
};
|
|
1654
|
+
if (motion.kind === 'fade') {
|
|
1655
|
+
playAll(
|
|
1656
|
+
motion.durationMs,
|
|
1657
|
+
t => (t <= 0 ? 0 : 1),
|
|
1658
|
+
() => NO_RIDE,
|
|
1659
|
+
{easing: motion.easing},
|
|
1660
|
+
shape => [shape(0), shape(motion.durationMs)],
|
|
1661
|
+
);
|
|
1662
|
+
return end;
|
|
1663
|
+
}
|
|
1664
|
+
const {progress} = motion;
|
|
1665
|
+
const progressAt = (t: number) => 1 - progress.remaining(t);
|
|
1666
|
+
if (rideWith == null) {
|
|
1667
|
+
playAll(
|
|
1668
|
+
progress.durationMs,
|
|
1669
|
+
progressAt,
|
|
1670
|
+
() => NO_RIDE,
|
|
1671
|
+
{easing: 'linear'},
|
|
1672
|
+
shape => sampleOver(progress.durationMs, shape),
|
|
1673
|
+
);
|
|
1674
|
+
return end;
|
|
1675
|
+
}
|
|
1676
|
+
// After this commit's glides start (the batch flushes in a microtask queued
|
|
1677
|
+
// before this one), before the frame paints: every part plays over the
|
|
1678
|
+
// ridden element's glide, told how far it has moved from where it showed.
|
|
1679
|
+
queueMicrotask(() => {
|
|
1680
|
+
if (isDone) {
|
|
1681
|
+
return;
|
|
1682
|
+
}
|
|
1683
|
+
const glide = glides.get(rideWith.element);
|
|
1684
|
+
const durationMs = glide?.durationMs ?? progress.durationMs;
|
|
1685
|
+
const rideAt = (t: number): LayoutRide => {
|
|
1686
|
+
if (glide == null) {
|
|
1687
|
+
return {x: -rideWith.travel.x, y: -rideWith.travel.y};
|
|
1688
|
+
}
|
|
1689
|
+
const now = glide.offsetAt(t);
|
|
1690
|
+
const start = glide.offsetAt(0);
|
|
1691
|
+
return {x: now.x - start.x, y: now.y - start.y};
|
|
1692
|
+
};
|
|
1693
|
+
playAll(durationMs, progressAt, rideAt, {easing: 'linear'}, shape =>
|
|
1694
|
+
sampleOver(durationMs, shape),
|
|
1695
|
+
);
|
|
1696
|
+
});
|
|
1697
|
+
return end;
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
/**
|
|
1701
|
+
* After a change commits, before paint: elements the page already renders
|
|
1702
|
+
* play frames over the change's progress on FR4's one motion, with no copy,
|
|
1703
|
+
* such as a surface reaching over a gap a glide opens. Under Reduce Motion
|
|
1704
|
+
* with a coarse pointer, only opacity changes; under an immediate change,
|
|
1705
|
+
* nothing plays. Returns what ends them at once.
|
|
1706
|
+
*/
|
|
1707
|
+
export function playLayoutFrames(
|
|
1708
|
+
handle: AnimatedLayout | null | undefined,
|
|
1709
|
+
parts: LayoutSwapMotion['incoming'],
|
|
1710
|
+
): () => void {
|
|
1711
|
+
const area = handle?.[AREA]() ?? null;
|
|
1712
|
+
const motion = area == null ? null : layoutMotion(area);
|
|
1713
|
+
if (motion == null || motion.kind === 'instant') {
|
|
1714
|
+
return () => {};
|
|
1715
|
+
}
|
|
1716
|
+
const animations: Animation[] = [];
|
|
1717
|
+
for (const {element, frames: shape} of parts) {
|
|
1718
|
+
const animation =
|
|
1719
|
+
motion.kind === 'spring'
|
|
1720
|
+
? safeAnimate(
|
|
1721
|
+
element,
|
|
1722
|
+
sampleKeyframes(motion.progress, remaining =>
|
|
1723
|
+
shape(1 - remaining, NO_RIDE),
|
|
1724
|
+
),
|
|
1725
|
+
{
|
|
1726
|
+
duration: motion.progress.durationMs,
|
|
1727
|
+
easing: 'linear',
|
|
1728
|
+
fill: 'both',
|
|
1729
|
+
},
|
|
1730
|
+
)
|
|
1731
|
+
: safeAnimate(element, [{opacity: 0}, {opacity: 1}], {
|
|
1732
|
+
duration: motion.durationMs,
|
|
1733
|
+
easing: motion.easing,
|
|
1734
|
+
});
|
|
1735
|
+
if (animation != null) {
|
|
1736
|
+
animations.push(animation);
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
// Held through the motion, then released: every part shares one clock, so
|
|
1740
|
+
// the first to finish ends them all and each element shows its own styles.
|
|
1741
|
+
const end = () => animations.forEach(animation => animation.cancel());
|
|
1742
|
+
animations[0]?.addEventListener?.('finish', end);
|
|
1743
|
+
return end;
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
/**
|
|
1747
|
+
* A disclosure's indicator (its chevron) turns on the same motion as the
|
|
1748
|
+
* glide: its CSS transition takes the spring as a `linear()` easing, and an
|
|
1749
|
+
* immediate change under Reduce Motion. Without a handle the inline values are
|
|
1750
|
+
* cleared, so the component's own transition applies. An engine without
|
|
1751
|
+
* `linear()` drops that value and keeps the component's easing.
|
|
1752
|
+
*/
|
|
1753
|
+
export function applyLayoutChangeTransition(
|
|
1754
|
+
handle: AnimatedLayout | null | undefined,
|
|
1755
|
+
element: HTMLElement | SVGElement | null,
|
|
1756
|
+
): void {
|
|
1757
|
+
if (element == null) {
|
|
1758
|
+
return;
|
|
1759
|
+
}
|
|
1760
|
+
const area = handle == null ? null : areaOf(handle, element);
|
|
1761
|
+
if (area == null) {
|
|
1762
|
+
element.style.removeProperty('transition-duration');
|
|
1763
|
+
element.style.removeProperty('transition-timing-function');
|
|
1764
|
+
return;
|
|
1765
|
+
}
|
|
1766
|
+
const motion = layoutMotion(area);
|
|
1767
|
+
if (motion.kind !== 'spring') {
|
|
1768
|
+
element.style.setProperty('transition-duration', '0s');
|
|
1769
|
+
element.style.removeProperty('transition-timing-function');
|
|
1770
|
+
return;
|
|
1771
|
+
}
|
|
1772
|
+
element.style.setProperty(
|
|
1773
|
+
'transition-duration',
|
|
1774
|
+
`${Math.round(motion.progress.durationMs)}ms`,
|
|
1775
|
+
);
|
|
1776
|
+
element.style.setProperty(
|
|
1777
|
+
'transition-timing-function',
|
|
1778
|
+
linearEasing(motion.progress),
|
|
1779
|
+
);
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
/**
|
|
1783
|
+
* Lands `element`'s running glide at once: it takes its layout place, and a
|
|
1784
|
+
* later change starts from there (a change its caller lands rather than
|
|
1785
|
+
* animates, such as a rail that snaps).
|
|
1786
|
+
*/
|
|
1787
|
+
export function landLayoutGlide(element: Element): void {
|
|
1788
|
+
const glide = glides.get(element);
|
|
1789
|
+
if (glide != null) {
|
|
1790
|
+
glides.delete(element);
|
|
1791
|
+
glide.animation.cancel();
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
/**
|
|
1796
|
+
* @internal The motion a change in `area` plays, for tests and for SideNav's
|
|
1797
|
+
* rail motion, which plays on the same clock (`component:SideNav` FR6).
|
|
1798
|
+
*/
|
|
1799
|
+
export function layoutMotionFor(area: Element): LayoutMotion {
|
|
1800
|
+
return layoutMotion(area);
|
|
1801
|
+
}
|