@mortenbrudvik/waveui 0.4.0 → 0.7.0
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/README.md +1221 -173
- package/dist/_virtual/_rolldown/runtime.cjs +1 -0
- package/dist/components/button/Button.cjs +2 -0
- package/dist/components/button/Button.cjs.map +1 -0
- package/dist/components/button/Button.mjs +50 -0
- package/dist/components/button/Button.mjs.map +1 -0
- package/dist/components/button/Button.semantics.cjs +2 -0
- package/dist/components/button/Button.semantics.cjs.map +1 -0
- package/dist/components/button/Button.semantics.mjs +61 -0
- package/dist/components/button/Button.semantics.mjs.map +1 -0
- package/dist/components/button/Button.slots.cjs +2 -0
- package/dist/components/button/Button.slots.cjs.map +1 -0
- package/dist/components/button/Button.slots.mjs +47 -0
- package/dist/components/button/Button.slots.mjs.map +1 -0
- package/dist/components/button/CompoundButton.cjs +2 -0
- package/dist/components/button/CompoundButton.cjs.map +1 -0
- package/dist/components/button/CompoundButton.mjs +53 -0
- package/dist/components/button/CompoundButton.mjs.map +1 -0
- package/dist/components/button/Link.cjs +2 -0
- package/dist/components/button/Link.cjs.map +1 -0
- package/dist/components/button/Link.mjs +37 -0
- package/dist/components/button/Link.mjs.map +1 -0
- package/dist/components/button/MenuButton.cjs +2 -0
- package/dist/components/button/MenuButton.cjs.map +1 -0
- package/dist/components/button/MenuButton.mjs +45 -0
- package/dist/components/button/MenuButton.mjs.map +1 -0
- package/dist/components/button/SplitButton.cjs +2 -0
- package/dist/components/button/SplitButton.cjs.map +1 -0
- package/dist/components/button/SplitButton.mjs +66 -0
- package/dist/components/button/SplitButton.mjs.map +1 -0
- package/dist/components/button/ToggleButton.cjs +2 -0
- package/dist/components/button/ToggleButton.cjs.map +1 -0
- package/dist/components/button/ToggleButton.mjs +65 -0
- package/dist/components/button/ToggleButton.mjs.map +1 -0
- package/dist/components/button/Toolbar.cjs +2 -0
- package/dist/components/button/Toolbar.cjs.map +1 -0
- package/dist/components/button/Toolbar.context.cjs +2 -0
- package/dist/components/button/Toolbar.context.cjs.map +1 -0
- package/dist/components/button/Toolbar.context.mjs +31 -0
- package/dist/components/button/Toolbar.context.mjs.map +1 -0
- package/dist/components/button/Toolbar.mjs +63 -0
- package/dist/components/button/Toolbar.mjs.map +1 -0
- package/dist/components/button/Toolbar.parts.cjs +2 -0
- package/dist/components/button/Toolbar.parts.cjs.map +1 -0
- package/dist/components/button/Toolbar.parts.mjs +131 -0
- package/dist/components/button/Toolbar.parts.mjs.map +1 -0
- package/dist/components/button/buttonStyles.cjs +2 -0
- package/dist/components/button/buttonStyles.cjs.map +1 -0
- package/dist/components/button/buttonStyles.mjs +39 -0
- package/dist/components/button/buttonStyles.mjs.map +1 -0
- package/dist/components/data-display/Avatar.cjs +2 -0
- package/dist/components/data-display/Avatar.cjs.map +1 -0
- package/dist/components/data-display/Avatar.mjs +157 -0
- package/dist/components/data-display/Avatar.mjs.map +1 -0
- package/dist/components/data-display/AvatarGroup.cjs +2 -0
- package/dist/components/data-display/AvatarGroup.cjs.map +1 -0
- package/dist/components/data-display/AvatarGroup.mjs +134 -0
- package/dist/components/data-display/AvatarGroup.mjs.map +1 -0
- package/dist/components/data-display/Badge.cjs +2 -0
- package/dist/components/data-display/Badge.cjs.map +1 -0
- package/dist/components/data-display/Badge.colors.cjs +2 -0
- package/dist/components/data-display/Badge.colors.cjs.map +1 -0
- package/dist/components/data-display/Badge.colors.mjs +58 -0
- package/dist/components/data-display/Badge.colors.mjs.map +1 -0
- package/dist/components/data-display/Badge.mjs +32 -0
- package/dist/components/data-display/Badge.mjs.map +1 -0
- package/dist/components/data-display/CounterBadge.cjs +2 -0
- package/dist/components/data-display/CounterBadge.cjs.map +1 -0
- package/dist/components/data-display/CounterBadge.mjs +28 -0
- package/dist/components/data-display/CounterBadge.mjs.map +1 -0
- package/dist/components/data-display/Divider.cjs +2 -0
- package/dist/components/data-display/Divider.cjs.map +1 -0
- package/dist/components/data-display/Divider.mjs +52 -0
- package/dist/components/data-display/Divider.mjs.map +1 -0
- package/dist/components/data-display/Image.cjs +2 -0
- package/dist/components/data-display/Image.cjs.map +1 -0
- package/dist/components/data-display/Image.mjs +32 -0
- package/dist/components/data-display/Image.mjs.map +1 -0
- package/dist/components/data-display/InfoLabel.cjs +2 -0
- package/dist/components/data-display/InfoLabel.cjs.map +1 -0
- package/dist/components/data-display/InfoLabel.mjs +104 -0
- package/dist/components/data-display/InfoLabel.mjs.map +1 -0
- package/dist/components/data-display/List.cjs +2 -0
- package/dist/components/data-display/List.cjs.map +1 -0
- package/dist/components/data-display/List.mjs +381 -0
- package/dist/components/data-display/List.mjs.map +1 -0
- package/dist/components/data-display/List.registry.cjs +2 -0
- package/dist/components/data-display/List.registry.cjs.map +1 -0
- package/dist/components/data-display/List.registry.mjs +101 -0
- package/dist/components/data-display/List.registry.mjs.map +1 -0
- package/dist/components/data-display/Persona.cjs +2 -0
- package/dist/components/data-display/Persona.cjs.map +1 -0
- package/dist/components/data-display/Persona.mjs +48 -0
- package/dist/components/data-display/Persona.mjs.map +1 -0
- package/dist/components/data-display/PresenceBadge.cjs +2 -0
- package/dist/components/data-display/PresenceBadge.cjs.map +1 -0
- package/dist/components/data-display/PresenceBadge.mjs +71 -0
- package/dist/components/data-display/PresenceBadge.mjs.map +1 -0
- package/dist/components/data-display/Tag.cjs +2 -0
- package/dist/components/data-display/Tag.cjs.map +1 -0
- package/dist/components/data-display/Tag.mjs +147 -0
- package/dist/components/data-display/Tag.mjs.map +1 -0
- package/dist/components/feedback/MessageBar.cjs +2 -0
- package/dist/components/feedback/MessageBar.cjs.map +1 -0
- package/dist/components/feedback/MessageBar.mjs +144 -0
- package/dist/components/feedback/MessageBar.mjs.map +1 -0
- package/dist/components/feedback/MessageBar.status.cjs +2 -0
- package/dist/components/feedback/MessageBar.status.cjs.map +1 -0
- package/dist/components/feedback/MessageBar.status.mjs +45 -0
- package/dist/components/feedback/MessageBar.status.mjs.map +1 -0
- package/dist/components/feedback/ProgressBar.cjs +2 -0
- package/dist/components/feedback/ProgressBar.cjs.map +1 -0
- package/dist/components/feedback/ProgressBar.mjs +72 -0
- package/dist/components/feedback/ProgressBar.mjs.map +1 -0
- package/dist/components/feedback/Skeleton.cjs +2 -0
- package/dist/components/feedback/Skeleton.cjs.map +1 -0
- package/dist/components/feedback/Skeleton.mjs +47 -0
- package/dist/components/feedback/Skeleton.mjs.map +1 -0
- package/dist/components/feedback/Spinner.cjs +2 -0
- package/dist/components/feedback/Spinner.cjs.map +1 -0
- package/dist/components/feedback/Spinner.mjs +60 -0
- package/dist/components/feedback/Spinner.mjs.map +1 -0
- package/dist/components/feedback/Toast.cjs +2 -0
- package/dist/components/feedback/Toast.cjs.map +1 -0
- package/dist/components/feedback/Toast.mjs +347 -0
- package/dist/components/feedback/Toast.mjs.map +1 -0
- package/dist/components/input/Checkbox.cjs +2 -0
- package/dist/components/input/Checkbox.cjs.map +1 -0
- package/dist/components/input/Checkbox.mjs +96 -0
- package/dist/components/input/Checkbox.mjs.map +1 -0
- package/dist/components/input/ColorPicker.cjs +6 -0
- package/dist/components/input/ColorPicker.cjs.map +1 -0
- package/dist/components/input/ColorPicker.mjs +236 -0
- package/dist/components/input/ColorPicker.mjs.map +1 -0
- package/dist/components/input/Combobox.cjs +2 -0
- package/dist/components/input/Combobox.cjs.map +1 -0
- package/dist/components/input/Combobox.expand.cjs +2 -0
- package/dist/components/input/Combobox.expand.cjs.map +1 -0
- package/dist/components/input/Combobox.expand.mjs +38 -0
- package/dist/components/input/Combobox.expand.mjs.map +1 -0
- package/dist/components/input/Combobox.mjs +187 -0
- package/dist/components/input/Combobox.mjs.map +1 -0
- package/dist/components/input/DatePicker.cjs +2 -0
- package/dist/components/input/DatePicker.cjs.map +1 -0
- package/dist/components/input/DatePicker.mjs +340 -0
- package/dist/components/input/DatePicker.mjs.map +1 -0
- package/dist/components/input/Dropdown.cjs +2 -0
- package/dist/components/input/Dropdown.cjs.map +1 -0
- package/dist/components/input/Dropdown.mjs +128 -0
- package/dist/components/input/Dropdown.mjs.map +1 -0
- package/dist/components/input/Field.cjs +2 -0
- package/dist/components/input/Field.cjs.map +1 -0
- package/dist/components/input/Field.mjs +200 -0
- package/dist/components/input/Field.mjs.map +1 -0
- package/dist/components/input/Input.cjs +2 -0
- package/dist/components/input/Input.cjs.map +1 -0
- package/dist/components/input/Input.mjs +81 -0
- package/dist/components/input/Input.mjs.map +1 -0
- package/dist/components/input/Label.cjs +2 -0
- package/dist/components/input/Label.cjs.map +1 -0
- package/dist/components/input/Label.mjs +28 -0
- package/dist/components/input/Label.mjs.map +1 -0
- package/dist/components/input/Option.cjs +2 -0
- package/dist/components/input/Option.cjs.map +1 -0
- package/dist/components/input/Option.mjs +169 -0
- package/dist/components/input/Option.mjs.map +1 -0
- package/dist/components/input/RadioGroup.cjs +2 -0
- package/dist/components/input/RadioGroup.cjs.map +1 -0
- package/dist/components/input/RadioGroup.mjs +139 -0
- package/dist/components/input/RadioGroup.mjs.map +1 -0
- package/dist/components/input/Rating.cjs +2 -0
- package/dist/components/input/Rating.cjs.map +1 -0
- package/dist/components/input/Rating.mjs +196 -0
- package/dist/components/input/Rating.mjs.map +1 -0
- package/dist/components/input/SearchBox.cjs +2 -0
- package/dist/components/input/SearchBox.cjs.map +1 -0
- package/dist/components/input/SearchBox.mjs +205 -0
- package/dist/components/input/SearchBox.mjs.map +1 -0
- package/dist/components/input/Select.cjs +2 -0
- package/dist/components/input/Select.cjs.map +1 -0
- package/dist/components/input/Select.mjs +33 -0
- package/dist/components/input/Select.mjs.map +1 -0
- package/dist/components/input/Slider.cjs +2 -0
- package/dist/components/input/Slider.cjs.map +1 -0
- package/dist/components/input/Slider.mjs +79 -0
- package/dist/components/input/Slider.mjs.map +1 -0
- package/dist/components/input/SpinButton.cjs +2 -0
- package/dist/components/input/SpinButton.cjs.map +1 -0
- package/dist/components/input/SpinButton.mjs +157 -0
- package/dist/components/input/SpinButton.mjs.map +1 -0
- package/dist/components/input/SwatchPicker.cjs +2 -0
- package/dist/components/input/SwatchPicker.cjs.map +1 -0
- package/dist/components/input/SwatchPicker.mjs +113 -0
- package/dist/components/input/SwatchPicker.mjs.map +1 -0
- package/dist/components/input/Switch.cjs +2 -0
- package/dist/components/input/Switch.cjs.map +1 -0
- package/dist/components/input/Switch.mjs +92 -0
- package/dist/components/input/Switch.mjs.map +1 -0
- package/dist/components/input/TagPicker.cjs +2 -0
- package/dist/components/input/TagPicker.cjs.map +1 -0
- package/dist/components/input/TagPicker.mjs +249 -0
- package/dist/components/input/TagPicker.mjs.map +1 -0
- package/dist/components/input/Textarea.cjs +2 -0
- package/dist/components/input/Textarea.cjs.map +1 -0
- package/dist/components/input/Textarea.mjs +32 -0
- package/dist/components/input/Textarea.mjs.map +1 -0
- package/dist/components/input/TimePicker.cjs +2 -0
- package/dist/components/input/TimePicker.cjs.map +1 -0
- package/dist/components/input/TimePicker.mjs +292 -0
- package/dist/components/input/TimePicker.mjs.map +1 -0
- package/dist/components/input/colorUtils.cjs +2 -0
- package/dist/components/input/colorUtils.cjs.map +1 -0
- package/dist/components/input/colorUtils.mjs +96 -0
- package/dist/components/input/colorUtils.mjs.map +1 -0
- package/dist/components/input/dateUtils.cjs +2 -0
- package/dist/components/input/dateUtils.cjs.map +1 -0
- package/dist/components/input/dateUtils.mjs +250 -0
- package/dist/components/input/dateUtils.mjs.map +1 -0
- package/dist/components/input/pickerStyles.cjs +2 -0
- package/dist/components/input/pickerStyles.cjs.map +1 -0
- package/dist/components/input/pickerStyles.mjs +10 -0
- package/dist/components/input/pickerStyles.mjs.map +1 -0
- package/dist/components/internal/HiddenInput.cjs +2 -0
- package/dist/components/internal/HiddenInput.cjs.map +1 -0
- package/dist/components/internal/HiddenInput.mjs +88 -0
- package/dist/components/internal/HiddenInput.mjs.map +1 -0
- package/dist/components/layout/Accordion.cjs +2 -0
- package/dist/components/layout/Accordion.cjs.map +1 -0
- package/dist/components/layout/Accordion.mjs +236 -0
- package/dist/components/layout/Accordion.mjs.map +1 -0
- package/dist/components/layout/Card.cjs +2 -0
- package/dist/components/layout/Card.cjs.map +1 -0
- package/dist/components/layout/Card.mjs +121 -0
- package/dist/components/layout/Card.mjs.map +1 -0
- package/dist/components/layout/Carousel.cjs +2 -0
- package/dist/components/layout/Carousel.cjs.map +1 -0
- package/dist/components/layout/Carousel.mjs +205 -0
- package/dist/components/layout/Carousel.mjs.map +1 -0
- package/dist/components/layout/Flex.cjs +2 -0
- package/dist/components/layout/Flex.cjs.map +1 -0
- package/dist/components/layout/Flex.mjs +54 -0
- package/dist/components/layout/Flex.mjs.map +1 -0
- package/dist/components/layout/Grid.cjs +2 -0
- package/dist/components/layout/Grid.cjs.map +1 -0
- package/dist/components/layout/Grid.mjs +62 -0
- package/dist/components/layout/Grid.mjs.map +1 -0
- package/dist/components/layout/Overflow.cjs +2 -0
- package/dist/components/layout/Overflow.cjs.map +1 -0
- package/dist/components/layout/Overflow.mjs +269 -0
- package/dist/components/layout/Overflow.mjs.map +1 -0
- package/dist/components/layout/Stack.cjs +2 -0
- package/dist/components/layout/Stack.cjs.map +1 -0
- package/dist/components/layout/Stack.mjs +39 -0
- package/dist/components/layout/Stack.mjs.map +1 -0
- package/dist/components/layout/TabList.cjs +2 -0
- package/dist/components/layout/TabList.cjs.map +1 -0
- package/dist/components/layout/TabList.mjs +238 -0
- package/dist/components/layout/TabList.mjs.map +1 -0
- package/dist/components/layout/Tree.cjs +2 -0
- package/dist/components/layout/Tree.cjs.map +1 -0
- package/dist/components/layout/Tree.mjs +220 -0
- package/dist/components/layout/Tree.mjs.map +1 -0
- package/dist/components/layout/disclosureIds.cjs +2 -0
- package/dist/components/layout/disclosureIds.cjs.map +1 -0
- package/dist/components/layout/disclosureIds.mjs +12 -0
- package/dist/components/layout/disclosureIds.mjs.map +1 -0
- package/dist/components/motion/Presence.cjs +2 -0
- package/dist/components/motion/Presence.cjs.map +1 -0
- package/dist/components/motion/Presence.mjs +35 -0
- package/dist/components/motion/Presence.mjs.map +1 -0
- package/dist/components/navigation/Breadcrumb.cjs +2 -0
- package/dist/components/navigation/Breadcrumb.cjs.map +1 -0
- package/dist/components/navigation/Breadcrumb.mjs +144 -0
- package/dist/components/navigation/Breadcrumb.mjs.map +1 -0
- package/dist/components/navigation/Menu.cjs +2 -0
- package/dist/components/navigation/Menu.cjs.map +1 -0
- package/dist/components/navigation/Menu.context.cjs +2 -0
- package/dist/components/navigation/Menu.context.cjs.map +1 -0
- package/dist/components/navigation/Menu.context.mjs +82 -0
- package/dist/components/navigation/Menu.context.mjs.map +1 -0
- package/dist/components/navigation/Menu.group.cjs +2 -0
- package/dist/components/navigation/Menu.group.cjs.map +1 -0
- package/dist/components/navigation/Menu.group.mjs +58 -0
- package/dist/components/navigation/Menu.group.mjs.map +1 -0
- package/dist/components/navigation/Menu.items.cjs +2 -0
- package/dist/components/navigation/Menu.items.cjs.map +1 -0
- package/dist/components/navigation/Menu.items.mjs +127 -0
- package/dist/components/navigation/Menu.items.mjs.map +1 -0
- package/dist/components/navigation/Menu.link.cjs +2 -0
- package/dist/components/navigation/Menu.link.cjs.map +1 -0
- package/dist/components/navigation/Menu.link.mjs +41 -0
- package/dist/components/navigation/Menu.link.mjs.map +1 -0
- package/dist/components/navigation/Menu.mjs +27 -0
- package/dist/components/navigation/Menu.mjs.map +1 -0
- package/dist/components/navigation/Menu.popover.cjs +2 -0
- package/dist/components/navigation/Menu.popover.cjs.map +1 -0
- package/dist/components/navigation/Menu.popover.mjs +231 -0
- package/dist/components/navigation/Menu.popover.mjs.map +1 -0
- package/dist/components/navigation/Menu.root.cjs +2 -0
- package/dist/components/navigation/Menu.root.cjs.map +1 -0
- package/dist/components/navigation/Menu.root.mjs +308 -0
- package/dist/components/navigation/Menu.root.mjs.map +1 -0
- package/dist/components/navigation/Menu.selectable.cjs +2 -0
- package/dist/components/navigation/Menu.selectable.cjs.map +1 -0
- package/dist/components/navigation/Menu.selectable.mjs +89 -0
- package/dist/components/navigation/Menu.selectable.mjs.map +1 -0
- package/dist/components/navigation/Menu.shared.cjs +2 -0
- package/dist/components/navigation/Menu.shared.cjs.map +1 -0
- package/dist/components/navigation/Menu.shared.mjs +23 -0
- package/dist/components/navigation/Menu.shared.mjs.map +1 -0
- package/dist/components/navigation/Menu.splitGroup.cjs +2 -0
- package/dist/components/navigation/Menu.splitGroup.cjs.map +1 -0
- package/dist/components/navigation/Menu.splitGroup.mjs +51 -0
- package/dist/components/navigation/Menu.splitGroup.mjs.map +1 -0
- package/dist/components/navigation/Menu.trigger.cjs +2 -0
- package/dist/components/navigation/Menu.trigger.cjs.map +1 -0
- package/dist/components/navigation/Menu.trigger.mjs +79 -0
- package/dist/components/navigation/Menu.trigger.mjs.map +1 -0
- package/dist/components/navigation/Nav.cjs +2 -0
- package/dist/components/navigation/Nav.cjs.map +1 -0
- package/dist/components/navigation/Nav.mjs +276 -0
- package/dist/components/navigation/Nav.mjs.map +1 -0
- package/dist/components/navigation/Pagination.cjs +2 -0
- package/dist/components/navigation/Pagination.cjs.map +1 -0
- package/dist/components/navigation/Pagination.mjs +110 -0
- package/dist/components/navigation/Pagination.mjs.map +1 -0
- package/dist/components/navigation/Stepper.cjs +2 -0
- package/dist/components/navigation/Stepper.cjs.map +1 -0
- package/dist/components/navigation/Stepper.mjs +204 -0
- package/dist/components/navigation/Stepper.mjs.map +1 -0
- package/dist/components/overlays/Dialog.cjs +2 -0
- package/dist/components/overlays/Dialog.cjs.map +1 -0
- package/dist/components/overlays/Dialog.mjs +180 -0
- package/dist/components/overlays/Dialog.mjs.map +1 -0
- package/dist/components/overlays/Dialog.shared.cjs +2 -0
- package/dist/components/overlays/Dialog.shared.cjs.map +1 -0
- package/dist/components/overlays/Dialog.shared.mjs +227 -0
- package/dist/components/overlays/Dialog.shared.mjs.map +1 -0
- package/dist/components/overlays/Drawer.cjs +2 -0
- package/dist/components/overlays/Drawer.cjs.map +1 -0
- package/dist/components/overlays/Drawer.mjs +192 -0
- package/dist/components/overlays/Drawer.mjs.map +1 -0
- package/dist/components/overlays/Popover.cjs +2 -0
- package/dist/components/overlays/Popover.cjs.map +1 -0
- package/dist/components/overlays/Popover.mjs +365 -0
- package/dist/components/overlays/Popover.mjs.map +1 -0
- package/dist/components/overlays/Popover.shared.cjs +2 -0
- package/dist/components/overlays/Popover.shared.cjs.map +1 -0
- package/dist/components/overlays/Popover.shared.mjs +182 -0
- package/dist/components/overlays/Popover.shared.mjs.map +1 -0
- package/dist/components/overlays/TeachingPopover.cjs +2 -0
- package/dist/components/overlays/TeachingPopover.cjs.map +1 -0
- package/dist/components/overlays/TeachingPopover.mjs +181 -0
- package/dist/components/overlays/TeachingPopover.mjs.map +1 -0
- package/dist/components/overlays/Tooltip.cjs +2 -0
- package/dist/components/overlays/Tooltip.cjs.map +1 -0
- package/dist/components/overlays/Tooltip.mjs +160 -0
- package/dist/components/overlays/Tooltip.mjs.map +1 -0
- package/dist/components/portal/Portal.cjs +2 -0
- package/dist/components/portal/Portal.cjs.map +1 -0
- package/dist/components/portal/Portal.mjs +45 -0
- package/dist/components/portal/Portal.mjs.map +1 -0
- package/dist/components/provider/WaveProvider.cjs +2 -0
- package/dist/components/provider/WaveProvider.cjs.map +1 -0
- package/dist/components/provider/WaveProvider.mjs +51 -0
- package/dist/components/provider/WaveProvider.mjs.map +1 -0
- package/dist/components/table/DataGrid.cjs +2 -0
- package/dist/components/table/DataGrid.cjs.map +1 -0
- package/dist/components/table/DataGrid.mjs +489 -0
- package/dist/components/table/DataGrid.mjs.map +1 -0
- package/dist/components/table/Table.cjs +2 -0
- package/dist/components/table/Table.cjs.map +1 -0
- package/dist/components/table/Table.mjs +99 -0
- package/dist/components/table/Table.mjs.map +1 -0
- package/dist/components/table/useGridNavigation.cjs +2 -0
- package/dist/components/table/useGridNavigation.cjs.map +1 -0
- package/dist/components/table/useGridNavigation.mjs +336 -0
- package/dist/components/table/useGridNavigation.mjs.map +1 -0
- package/dist/components/typography/Text.cjs +2 -0
- package/dist/components/typography/Text.cjs.map +1 -0
- package/dist/components/typography/Text.mjs +38 -0
- package/dist/components/typography/Text.mjs.map +1 -0
- package/dist/hooks/useAnnounce.cjs +2 -0
- package/dist/hooks/useAnnounce.cjs.map +1 -0
- package/dist/hooks/useAnnounce.mjs +88 -0
- package/dist/hooks/useAnnounce.mjs.map +1 -0
- package/dist/hooks/useCheckedValues.cjs +2 -0
- package/dist/hooks/useCheckedValues.cjs.map +1 -0
- package/dist/hooks/useCheckedValues.mjs +102 -0
- package/dist/hooks/useCheckedValues.mjs.map +1 -0
- package/dist/hooks/useContextMenuAnchor.cjs +2 -0
- package/dist/hooks/useContextMenuAnchor.cjs.map +1 -0
- package/dist/hooks/useContextMenuAnchor.mjs +132 -0
- package/dist/hooks/useContextMenuAnchor.mjs.map +1 -0
- package/dist/hooks/useControllable.cjs +2 -0
- package/dist/hooks/useControllable.cjs.map +1 -0
- package/dist/hooks/useControllable.mjs +37 -0
- package/dist/hooks/useControllable.mjs.map +1 -0
- package/dist/hooks/useDirection.cjs +2 -0
- package/dist/hooks/useDirection.cjs.map +1 -0
- package/dist/hooks/useDirection.mjs +57 -0
- package/dist/hooks/useDirection.mjs.map +1 -0
- package/dist/hooks/useDismiss.cjs +2 -0
- package/dist/hooks/useDismiss.cjs.map +1 -0
- package/dist/hooks/useDismiss.mjs +57 -0
- package/dist/hooks/useDismiss.mjs.map +1 -0
- package/dist/hooks/useEventCallback.cjs +2 -0
- package/dist/hooks/useEventCallback.cjs.map +1 -0
- package/dist/hooks/useEventCallback.mjs +16 -0
- package/dist/hooks/useEventCallback.mjs.map +1 -0
- package/dist/hooks/useFieldControl.cjs +2 -0
- package/dist/hooks/useFieldControl.cjs.map +1 -0
- package/dist/hooks/useFieldControl.mjs +62 -0
- package/dist/hooks/useFieldControl.mjs.map +1 -0
- package/dist/hooks/useFocusTrap.cjs +2 -0
- package/dist/hooks/useFocusTrap.cjs.map +1 -0
- package/dist/hooks/useFocusTrap.mjs +266 -0
- package/dist/hooks/useFocusTrap.mjs.map +1 -0
- package/dist/hooks/useFormReset.cjs +2 -0
- package/dist/hooks/useFormReset.cjs.map +1 -0
- package/dist/hooks/useFormReset.mjs +33 -0
- package/dist/hooks/useFormReset.mjs.map +1 -0
- package/dist/hooks/useHoverIntent.cjs +2 -0
- package/dist/hooks/useHoverIntent.cjs.map +1 -0
- package/dist/hooks/useHoverIntent.mjs +201 -0
- package/dist/hooks/useHoverIntent.mjs.map +1 -0
- package/dist/hooks/useId.cjs +2 -0
- package/dist/hooks/useId.cjs.map +1 -0
- package/dist/hooks/useId.mjs +11 -0
- package/dist/hooks/useId.mjs.map +1 -0
- package/dist/hooks/useIsClient.cjs +2 -0
- package/dist/hooks/useIsClient.cjs.map +1 -0
- package/dist/hooks/useIsClient.mjs +19 -0
- package/dist/hooks/useIsClient.mjs.map +1 -0
- package/dist/hooks/useListbox.cjs +2 -0
- package/dist/hooks/useListbox.cjs.map +1 -0
- package/dist/hooks/useListbox.mjs +492 -0
- package/dist/hooks/useListbox.mjs.map +1 -0
- package/dist/hooks/useMergedRefs.cjs +2 -0
- package/dist/hooks/useMergedRefs.cjs.map +1 -0
- package/dist/hooks/useMergedRefs.mjs +57 -0
- package/dist/hooks/useMergedRefs.mjs.map +1 -0
- package/dist/hooks/useModalIsolation.cjs +2 -0
- package/dist/hooks/useModalIsolation.cjs.map +1 -0
- package/dist/hooks/useModalIsolation.mjs +87 -0
- package/dist/hooks/useModalIsolation.mjs.map +1 -0
- package/dist/hooks/useModalLayer.cjs +2 -0
- package/dist/hooks/useModalLayer.cjs.map +1 -0
- package/dist/hooks/useModalLayer.mjs +30 -0
- package/dist/hooks/useModalLayer.mjs.map +1 -0
- package/dist/hooks/usePopupPosition.cjs +2 -0
- package/dist/hooks/usePopupPosition.cjs.map +1 -0
- package/dist/hooks/usePopupPosition.mjs +117 -0
- package/dist/hooks/usePopupPosition.mjs.map +1 -0
- package/dist/hooks/usePrefersReducedMotion.cjs +2 -0
- package/dist/hooks/usePrefersReducedMotion.cjs.map +1 -0
- package/dist/hooks/usePrefersReducedMotion.mjs +24 -0
- package/dist/hooks/usePrefersReducedMotion.mjs.map +1 -0
- package/dist/hooks/usePresence.cjs +2 -0
- package/dist/hooks/usePresence.cjs.map +1 -0
- package/dist/hooks/usePresence.mjs +136 -0
- package/dist/hooks/usePresence.mjs.map +1 -0
- package/dist/hooks/usePreserveFocus.cjs +2 -0
- package/dist/hooks/usePreserveFocus.cjs.map +1 -0
- package/dist/hooks/usePreserveFocus.mjs +50 -0
- package/dist/hooks/usePreserveFocus.mjs.map +1 -0
- package/dist/hooks/useRestoreFocus.cjs +2 -0
- package/dist/hooks/useRestoreFocus.cjs.map +1 -0
- package/dist/hooks/useRestoreFocus.mjs +271 -0
- package/dist/hooks/useRestoreFocus.mjs.map +1 -0
- package/dist/hooks/useRovingTabIndex.cjs +2 -0
- package/dist/hooks/useRovingTabIndex.cjs.map +1 -0
- package/dist/hooks/useRovingTabIndex.mjs +389 -0
- package/dist/hooks/useRovingTabIndex.mjs.map +1 -0
- package/dist/hooks/useScrollLock.cjs +2 -0
- package/dist/hooks/useScrollLock.cjs.map +1 -0
- package/dist/hooks/useScrollLock.mjs +71 -0
- package/dist/hooks/useScrollLock.mjs.map +1 -0
- package/dist/hooks/useTriggerElement.cjs +2 -0
- package/dist/hooks/useTriggerElement.cjs.map +1 -0
- package/dist/hooks/useTriggerElement.mjs +126 -0
- package/dist/hooks/useTriggerElement.mjs.map +1 -0
- package/dist/hooks/useTypeahead.cjs +2 -0
- package/dist/hooks/useTypeahead.cjs.map +1 -0
- package/dist/hooks/useTypeahead.mjs +38 -0
- package/dist/hooks/useTypeahead.mjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +9099 -0
- package/dist/index.d.ts +7688 -1027
- package/dist/index.mjs +91 -5695
- package/dist/lib/aria.cjs +2 -0
- package/dist/lib/aria.cjs.map +1 -0
- package/dist/lib/aria.mjs +29 -0
- package/dist/lib/aria.mjs.map +1 -0
- package/dist/lib/children.cjs +2 -0
- package/dist/lib/children.cjs.map +1 -0
- package/dist/lib/children.mjs +37 -0
- package/dist/lib/children.mjs.map +1 -0
- package/dist/lib/cn.cjs +2 -0
- package/dist/lib/cn.cjs.map +1 -0
- package/dist/lib/cn.mjs +64 -0
- package/dist/lib/cn.mjs.map +1 -0
- package/dist/lib/composeEventHandlers.cjs +2 -0
- package/dist/lib/composeEventHandlers.cjs.map +1 -0
- package/dist/lib/composeEventHandlers.mjs +11 -0
- package/dist/lib/composeEventHandlers.mjs.map +1 -0
- package/dist/lib/dev.cjs +2 -0
- package/dist/lib/dev.cjs.map +1 -0
- package/dist/lib/dev.mjs +42 -0
- package/dist/lib/dev.mjs.map +1 -0
- package/dist/lib/direction.cjs +2 -0
- package/dist/lib/direction.cjs.map +1 -0
- package/dist/lib/direction.mjs +35 -0
- package/dist/lib/direction.mjs.map +1 -0
- package/dist/lib/events.cjs +2 -0
- package/dist/lib/events.cjs.map +1 -0
- package/dist/lib/events.mjs +31 -0
- package/dist/lib/events.mjs.map +1 -0
- package/dist/lib/focus.cjs +2 -0
- package/dist/lib/focus.cjs.map +1 -0
- package/dist/lib/focus.mjs +119 -0
- package/dist/lib/focus.mjs.map +1 -0
- package/dist/lib/globalRegistry.cjs +2 -0
- package/dist/lib/globalRegistry.cjs.map +1 -0
- package/dist/lib/globalRegistry.mjs +13 -0
- package/dist/lib/globalRegistry.mjs.map +1 -0
- package/dist/lib/icons.cjs +2 -0
- package/dist/lib/icons.cjs.map +1 -0
- package/dist/lib/icons.mjs +254 -0
- package/dist/lib/icons.mjs.map +1 -0
- package/dist/lib/labelInName.cjs +2 -0
- package/dist/lib/labelInName.cjs.map +1 -0
- package/dist/lib/labelInName.mjs +54 -0
- package/dist/lib/labelInName.mjs.map +1 -0
- package/dist/lib/layers.cjs +2 -0
- package/dist/lib/layers.cjs.map +1 -0
- package/dist/lib/layers.mjs +224 -0
- package/dist/lib/layers.mjs.map +1 -0
- package/dist/lib/mergeProps.cjs +2 -0
- package/dist/lib/mergeProps.cjs.map +1 -0
- package/dist/lib/mergeProps.mjs +21 -0
- package/dist/lib/mergeProps.mjs.map +1 -0
- package/dist/lib/mergeRefs.cjs +2 -0
- package/dist/lib/mergeRefs.cjs.map +1 -0
- package/dist/lib/mergeRefs.mjs +29 -0
- package/dist/lib/mergeRefs.mjs.map +1 -0
- package/dist/lib/renderTrigger.cjs +2 -0
- package/dist/lib/renderTrigger.cjs.map +1 -0
- package/dist/lib/renderTrigger.mjs +29 -0
- package/dist/lib/renderTrigger.mjs.map +1 -0
- package/dist/lib/slot.cjs +2 -0
- package/dist/lib/slot.cjs.map +1 -0
- package/dist/lib/slot.mjs +122 -0
- package/dist/lib/slot.mjs.map +1 -0
- package/dist/lib/styles.cjs +2 -0
- package/dist/lib/styles.cjs.map +1 -0
- package/dist/lib/styles.mjs +16 -0
- package/dist/lib/styles.mjs.map +1 -0
- package/dist/lib/theme.cjs +2 -0
- package/dist/lib/theme.cjs.map +1 -0
- package/dist/lib/theme.mjs +16 -0
- package/dist/lib/theme.mjs.map +1 -0
- package/dist/preflight.css +2 -0
- package/dist/styles.css +2 -0
- package/package.json +149 -100
- package/src/styles/animations.css +7 -39
- package/src/styles/base.css +103 -0
- package/src/styles/globals.css +10 -22
- package/src/styles/legacy-tokens.css +184 -0
- package/src/styles/preflight.css +7 -0
- package/src/styles/styles.css +32 -0
- package/src/styles/tailwind.css +17 -0
- package/src/styles/tokens.css +561 -221
- package/src/styles/variants.css +29 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePresence.cjs","names":["useIsClient","usePrefersReducedMotion","useState","useRef","useCallback","useEventCallback","useMemo","require_useEventCallback","require_useIsClient","require_usePrefersReducedMotion","react","FALLBACK_GRACE_MS","parseTimes","value","time","entry","amount","parseList","at","list","fallback","i","isRunningFinite","animation","endTime","computedMotion","style","el","animations","transitions","names","durations","delays","counts","name","count","end","properties","transitionDurations","transitionDelays","duration","property","END_EVENTS","waitForMotion","running","waiting","onEnd","finish","cleanup","handleEnd","event","timer","type","usePresence","options","isClient","reducedMotion","phase","setPhase","visible","appear","previousVisible","setPreviousVisible","element","setElement","elementRef","ref","node","next","active","stopWaiting","current","handleEntered","onEntered","handleExited","onExited","committedPhaseRef","previous","keptExited","unmountOnExit","presenceProps","attributes"],"sources":["../../src/hooks/usePresence.ts"],"sourcesContent":["import { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport type * as React from 'react';\nimport { useEventCallback } from './useEventCallback';\nimport { useIsClient } from './useIsClient';\nimport { usePrefersReducedMotion } from './usePrefersReducedMotion';\n\n/**\n * Phase of an element that mounts and unmounts through the presence core: `entering` (its enter\n * motion runs), `entered`, `exiting` (its exit motion runs), `exited`.\n */\nexport type PresencePhase = 'entering' | 'entered' | 'exiting' | 'exited';\n\n/** Options of {@link usePresence}. */\nexport interface UsePresenceOptions {\n /**\n * Run the enter phase when the element mounts already visible. Never on the server or while\n * hydrating: the server HTML is the `entered` phase, and a hydrated element does not replay its\n * enter motion.\n * @default false\n */\n appear?: boolean;\n /**\n * Unmount the element once it has exited. `false` keeps it mounted while exited, `hidden` and\n * `inert`, so its state (form fields, scroll position) survives.\n * @default true\n */\n unmountOnExit?: boolean;\n /** Called when an enter phase ends (after its motion, or at once without one). */\n onEntered?: () => void;\n /**\n * Called when an exit phase ends (after its motion, or at once without one), from the commit\n * that unmounts the element (or, with `unmountOnExit: false`, hides it). Not called when the\n * parent unmounts the element while it exits, or when it is shown again first.\n */\n onExited?: () => void;\n}\n\n/** The attributes the animated element takes. */\nexport interface PresenceAttributes {\n /** The phase, always rendered: style motion with `data-[presence=entering]:…` and friends. */\n 'data-presence': PresencePhase;\n /** While exiting, and while exited when kept mounted: out of the tab order and the accessibility tree. */\n inert?: boolean;\n /** While exited when kept mounted (`unmountOnExit: false`). */\n hidden?: boolean;\n}\n\n/** Returned by {@link usePresence}. */\nexport interface UsePresenceResult {\n /** Whether to render the element. */\n isMounted: boolean;\n /** The current phase (Avatar's unrelated `PresenceStatus` is a user's availability). */\n phase: PresencePhase;\n /** Callback ref for the animated element (stable); the phases wait for its own animations. */\n ref: React.RefCallback<HTMLElement>;\n /** Spread onto the animated element. */\n presenceProps: PresenceAttributes;\n}\n\n/** Extra time the computed-style fallback waits past the longest motion before it ends a phase. */\nconst FALLBACK_GRACE_MS = 50;\n\n/** Milliseconds of each entry of a computed time list (`0.2s, 150ms`); unreadable entries are 0. */\nfunction parseTimes(value: string): number[] {\n return value.split(',').map((entry) => {\n const time = entry.trim();\n const amount = parseFloat(time);\n if (Number.isNaN(amount)) return 0;\n return time.endsWith('ms') ? amount : time.endsWith('s') ? amount * 1000 : 0;\n });\n}\n\n/** The entries of a computed list (`fade, spin`), without empty ones. */\nfunction parseList(value: string): string[] {\n return value\n .split(',')\n .map((entry) => entry.trim())\n .filter((entry) => entry !== '');\n}\n\n/** Entry `i` of a computed list that repeats to the length of its name list (CSS list rule). */\nfunction at<T>(list: T[], i: number, fallback: T): T {\n return list.length === 0 ? fallback : list[i % list.length];\n}\n\n/** Whether an animation of `el.getAnimations()` still has to end: running and finite. */\nfunction isRunningFinite(animation: Animation): boolean {\n if (animation.playState !== 'running') return false;\n const endTime = animation.effect?.getComputedTiming().endTime;\n return endTime === undefined || Number.isFinite(Number(endTime));\n}\n\n/**\n * The motion `el` itself runs now, read from its computed style (engines without\n * `getAnimations`): the animation names and transitioned properties that end, and the longest\n * time until they do (delay + duration × iterations for animations, delay + duration for\n * transitions). Infinite animations never end and are left out.\n */\nfunction computedMotion(el: HTMLElement): {\n time: number;\n animations: Set<string>;\n transitions: Set<string>;\n} {\n const style = el.ownerDocument.defaultView?.getComputedStyle(el);\n const animations = new Set<string>();\n const transitions = new Set<string>();\n let time = 0;\n if (!style) return { time, animations, transitions };\n\n const names = parseList(style.animationName);\n const durations = parseTimes(style.animationDuration);\n const delays = parseTimes(style.animationDelay);\n const counts = parseList(style.animationIterationCount);\n names.forEach((name, i) => {\n if (name === 'none') return;\n const count = Number(at(counts, i, '1'));\n if (!Number.isFinite(count)) return;\n const end = at(delays, i, 0) + at(durations, i, 0) * count;\n if (end <= 0) return;\n animations.add(name);\n time = Math.max(time, end);\n });\n\n const properties = parseList(style.transitionProperty);\n const transitionDurations = parseTimes(style.transitionDuration);\n const transitionDelays = parseTimes(style.transitionDelay);\n properties.forEach((property, i) => {\n const duration = at(transitionDurations, i, 0);\n if (property === 'none' || duration <= 0) return;\n const end = at(transitionDelays, i, 0) + duration;\n if (end <= 0) return;\n transitions.add(property);\n time = Math.max(time, end);\n });\n\n return { time, animations, transitions };\n}\n\nconst END_EVENTS = ['animationend', 'animationcancel', 'transitionend', 'transitioncancel'];\n\n/**\n * Waits for the motion `el` itself runs and calls `onEnd` once it has ended (never synchronously).\n * Returns `null` when nothing runs (the phase ends at once), else a cleanup that stops waiting.\n *\n * - With `getAnimations()`: every running finite animation of the element (CSS animations and\n * transitions alike) has finished; a cancelled one counts as finished.\n * - Without it: the computed style's longest motion plus {@link FALLBACK_GRACE_MS}, or earlier once\n * the element's own end and cancel events have accounted for every animation name and\n * transitioned property it lists.\n */\nfunction waitForMotion(el: HTMLElement, onEnd: () => void): (() => void) | null {\n if (typeof el.getAnimations === 'function') {\n const running = el.getAnimations().filter(isRunningFinite);\n if (running.length === 0) return null;\n let waiting = true;\n void Promise.allSettled(running.map((animation) => animation.finished)).then(() => {\n if (waiting) onEnd();\n });\n return () => {\n waiting = false;\n };\n }\n\n const { time, animations, transitions } = computedMotion(el);\n if (time <= 0) return null;\n const finish = () => {\n cleanup();\n onEnd();\n };\n const handleEnd = (event: Event) => {\n if (event.target !== el) return;\n if (event.type.startsWith('animation')) {\n animations.delete((event as AnimationEvent).animationName);\n } else {\n const property = (event as TransitionEvent).propertyName;\n if (!transitions.delete(property)) transitions.delete('all');\n }\n if (animations.size === 0 && transitions.size === 0) finish();\n };\n const timer = setTimeout(finish, time + FALLBACK_GRACE_MS);\n for (const type of END_EVENTS) el.addEventListener(type, handleEnd);\n function cleanup() {\n clearTimeout(timer);\n for (const type of END_EVENTS) el.removeEventListener(type, handleEnd);\n }\n return cleanup;\n}\n\n/**\n * Mounts and unmounts an element with CSS enter and exit motion. Style the phases with\n * `data-presence` variants, e.g. `transition-opacity duration-wave-normal\n * data-[presence=entering]:starting:opacity-0 data-[presence=exiting]:opacity-0\n * motion-reduce:transition-none`. Gate the enter's start style on the entering phase, as there: an\n * ungated `starting:` class (`@starting-style`) applies to every first style of the element, so it\n * also animates a mount the core treats as `entered` (without `appear`, and when hydrating).\n * Destructure the result (`const { isMounted, ref, presenceProps } = usePresence(open)`):\n * react-hooks/refs treats an object whose member is passed to `ref` as a ref, so reading `phase`\n * or `presenceProps` from the whole object during render is an error (the usePopupPosition rule).\n *\n * - **Phases.** On the server and while hydrating the element is `entered` when `visible`, else\n * `exited`; a client mount is `entering` with `appear`, else `entered` (or `exited`). `visible`\n * becoming `true` enters, becoming `false` exits a mounted element; showing it again while it\n * exits goes back to `entering` with the same element.\n * - **End of a phase.** `entering` and `exiting` end when every running finite animation of the\n * element itself (`getAnimations()`: CSS animations and transitions) has finished or was\n * cancelled; engines without `getAnimations` read the computed `animation-*`/`transition-*`\n * times and the element's end events. A phase ends at once under `prefers-reduced-motion:\n * reduce`, without an element and without running motion, from a layout effect: an element\n * without motion unmounts before the browser paints, in the same `act()`.\n * - **Attributes.** `data-presence` always; `inert` while exiting (the exiting element is out of\n * the tab order and the accessibility tree), and `inert` plus `hidden` while exited when kept\n * mounted (`unmountOnExit: false`). No inline style, no class, no JS animation.\n * - **Callbacks.** `onEntered` and `onExited` run once per phase change, StrictMode included,\n * from an effect after the commit of the new phase.\n * - Focus, dismiss layers and focus restore stay the component's: key them on the open state, not\n * on `isMounted`, so they run on close rather than after the exit motion.\n *\n * @example\n * const { isMounted, ref, presenceProps } = usePresence(open);\n * return isMounted ? (\n * <div\n * ref={ref}\n * {...presenceProps}\n * className=\"transition-opacity duration-wave-normal data-[presence=entering]:starting:opacity-0 data-[presence=exiting]:opacity-0 motion-reduce:transition-none\"\n * />\n * ) : null;\n *\n * @param visible - Whether the element is shown.\n * @param options - See {@link UsePresenceOptions}.\n */\nexport function usePresence(visible: boolean, options: UsePresenceOptions = {}): UsePresenceResult {\n const { appear = false, unmountOnExit = true, onEntered, onExited } = options;\n const isClient = useIsClient();\n const reducedMotion = usePrefersReducedMotion();\n\n const [phase, setPhase] = useState<PresencePhase>(() => {\n if (!visible) return 'exited';\n return isClient && appear ? 'entering' : 'entered';\n });\n\n // Changes of `visible`, derived during render (C-HOOKS: a previous-value state).\n const [previousVisible, setPreviousVisible] = useState(visible);\n if (visible !== previousVisible) {\n setPreviousVisible(visible);\n if (visible) setPhase('entering');\n else if (phase !== 'exited') setPhase('exiting');\n }\n\n // The element: in state, so the phase-end effect re-runs when it attaches, and in a ref, which\n // that effect reads (a DOM-derived update in a layout effect).\n const [element, setElement] = useState<HTMLElement | null>(null);\n const elementRef = useRef<HTMLElement | null>(null);\n const ref = useCallback((node: HTMLElement | null) => {\n elementRef.current = node;\n setElement(node);\n }, []);\n\n // End of the entering and exiting phases.\n useLayoutEffect(() => {\n if (phase !== 'entering' && phase !== 'exiting') return undefined;\n const next: PresencePhase = phase === 'entering' ? 'entered' : 'exited';\n const el = elementRef.current;\n // Guards the waiting phase: one that was replaced (or unmounted) never ends the new one.\n let active = true;\n const endLater = () => {\n if (active) setPhase((current) => (current === phase ? next : current));\n };\n const stopWaiting = el && !reducedMotion ? waitForMotion(el, endLater) : null;\n if (!stopWaiting) {\n setPhase(next);\n return undefined;\n }\n return () => {\n active = false;\n stopWaiting();\n };\n }, [phase, element, reducedMotion]);\n\n // The callbacks, once per committed phase change (never from the effect above, which StrictMode\n // runs twice on mount before the new phase renders).\n const handleEntered = useEventCallback(onEntered);\n const handleExited = useEventCallback(onExited);\n const committedPhaseRef = useRef<PresencePhase | null>(null);\n useLayoutEffect(() => {\n const previous = committedPhaseRef.current;\n committedPhaseRef.current = phase;\n if (previous === 'entering' && phase === 'entered') handleEntered();\n else if (previous === 'exiting' && phase === 'exited') handleExited();\n }, [phase, handleEntered, handleExited]);\n\n const keptExited = phase === 'exited' && !unmountOnExit;\n const presenceProps = useMemo<PresenceAttributes>(() => {\n const attributes: PresenceAttributes = { 'data-presence': phase };\n if (phase === 'exiting' || keptExited) attributes.inert = true;\n if (keptExited) attributes.hidden = true;\n return attributes;\n }, [phase, keptExited]);\n\n return { isMounted: phase !== 'exited' || !unmountOnExit, phase, ref, presenceProps };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEventCallback as e } from "./useEventCallback.mjs";
|
|
3
|
+
import { useIsClient as t } from "./useIsClient.mjs";
|
|
4
|
+
import { usePrefersReducedMotion as n } from "./usePrefersReducedMotion.mjs";
|
|
5
|
+
import { useCallback as r, useLayoutEffect as i, useMemo as a, useRef as o, useState as s } from "react";
|
|
6
|
+
//#region src/hooks/usePresence.ts
|
|
7
|
+
var c = 50;
|
|
8
|
+
function l(e) {
|
|
9
|
+
return e.split(",").map((e) => {
|
|
10
|
+
let t = e.trim(), n = parseFloat(t);
|
|
11
|
+
return Number.isNaN(n) ? 0 : t.endsWith("ms") ? n : t.endsWith("s") ? n * 1e3 : 0;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
function u(e) {
|
|
15
|
+
return e.split(",").map((e) => e.trim()).filter((e) => e !== "");
|
|
16
|
+
}
|
|
17
|
+
function d(e, t, n) {
|
|
18
|
+
return e.length === 0 ? n : e[t % e.length];
|
|
19
|
+
}
|
|
20
|
+
function f(e) {
|
|
21
|
+
if (e.playState !== "running") return !1;
|
|
22
|
+
let t = e.effect?.getComputedTiming().endTime;
|
|
23
|
+
return t === void 0 || Number.isFinite(Number(t));
|
|
24
|
+
}
|
|
25
|
+
function p(e) {
|
|
26
|
+
let t = e.ownerDocument.defaultView?.getComputedStyle(e), n = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set(), i = 0;
|
|
27
|
+
if (!t) return {
|
|
28
|
+
time: i,
|
|
29
|
+
animations: n,
|
|
30
|
+
transitions: r
|
|
31
|
+
};
|
|
32
|
+
let a = u(t.animationName), o = l(t.animationDuration), s = l(t.animationDelay), c = u(t.animationIterationCount);
|
|
33
|
+
a.forEach((e, t) => {
|
|
34
|
+
if (e === "none") return;
|
|
35
|
+
let r = Number(d(c, t, "1"));
|
|
36
|
+
if (!Number.isFinite(r)) return;
|
|
37
|
+
let a = d(s, t, 0) + d(o, t, 0) * r;
|
|
38
|
+
a <= 0 || (n.add(e), i = Math.max(i, a));
|
|
39
|
+
});
|
|
40
|
+
let f = u(t.transitionProperty), p = l(t.transitionDuration), m = l(t.transitionDelay);
|
|
41
|
+
return f.forEach((e, t) => {
|
|
42
|
+
let n = d(p, t, 0);
|
|
43
|
+
if (e === "none" || n <= 0) return;
|
|
44
|
+
let a = d(m, t, 0) + n;
|
|
45
|
+
a <= 0 || (r.add(e), i = Math.max(i, a));
|
|
46
|
+
}), {
|
|
47
|
+
time: i,
|
|
48
|
+
animations: n,
|
|
49
|
+
transitions: r
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
var m = [
|
|
53
|
+
"animationend",
|
|
54
|
+
"animationcancel",
|
|
55
|
+
"transitionend",
|
|
56
|
+
"transitioncancel"
|
|
57
|
+
];
|
|
58
|
+
function h(e, t) {
|
|
59
|
+
if (typeof e.getAnimations == "function") {
|
|
60
|
+
let n = e.getAnimations().filter(f);
|
|
61
|
+
if (n.length === 0) return null;
|
|
62
|
+
let r = !0;
|
|
63
|
+
return Promise.allSettled(n.map((e) => e.finished)).then(() => {
|
|
64
|
+
r && t();
|
|
65
|
+
}), () => {
|
|
66
|
+
r = !1;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
let { time: n, animations: r, transitions: i } = p(e);
|
|
70
|
+
if (n <= 0) return null;
|
|
71
|
+
let a = () => {
|
|
72
|
+
l(), t();
|
|
73
|
+
}, o = (t) => {
|
|
74
|
+
if (t.target === e) {
|
|
75
|
+
if (t.type.startsWith("animation")) r.delete(t.animationName);
|
|
76
|
+
else {
|
|
77
|
+
let e = t.propertyName;
|
|
78
|
+
i.delete(e) || i.delete("all");
|
|
79
|
+
}
|
|
80
|
+
r.size === 0 && i.size === 0 && a();
|
|
81
|
+
}
|
|
82
|
+
}, s = setTimeout(a, n + c);
|
|
83
|
+
for (let t of m) e.addEventListener(t, o);
|
|
84
|
+
function l() {
|
|
85
|
+
clearTimeout(s);
|
|
86
|
+
for (let t of m) e.removeEventListener(t, o);
|
|
87
|
+
}
|
|
88
|
+
return l;
|
|
89
|
+
}
|
|
90
|
+
function g(c, l = {}) {
|
|
91
|
+
let { appear: u = !1, unmountOnExit: d = !0, onEntered: f, onExited: p } = l, m = t(), g = n(), [_, v] = s(() => c ? m && u ? "entering" : "entered" : "exited"), [y, b] = s(c);
|
|
92
|
+
c !== y && (b(c), c ? v("entering") : _ !== "exited" && v("exiting"));
|
|
93
|
+
let [x, S] = s(null), C = o(null), w = r((e) => {
|
|
94
|
+
C.current = e, S(e);
|
|
95
|
+
}, []);
|
|
96
|
+
i(() => {
|
|
97
|
+
if (_ !== "entering" && _ !== "exiting") return;
|
|
98
|
+
let e = _ === "entering" ? "entered" : "exited", t = C.current, n = !0, r = t && !g ? h(t, () => {
|
|
99
|
+
n && v((t) => t === _ ? e : t);
|
|
100
|
+
}) : null;
|
|
101
|
+
if (!r) {
|
|
102
|
+
v(e);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
return () => {
|
|
106
|
+
n = !1, r();
|
|
107
|
+
};
|
|
108
|
+
}, [
|
|
109
|
+
_,
|
|
110
|
+
x,
|
|
111
|
+
g
|
|
112
|
+
]);
|
|
113
|
+
let T = e(f), E = e(p), D = o(null);
|
|
114
|
+
i(() => {
|
|
115
|
+
let e = D.current;
|
|
116
|
+
D.current = _, e === "entering" && _ === "entered" ? T() : e === "exiting" && _ === "exited" && E();
|
|
117
|
+
}, [
|
|
118
|
+
_,
|
|
119
|
+
T,
|
|
120
|
+
E
|
|
121
|
+
]);
|
|
122
|
+
let O = _ === "exited" && !d, k = a(() => {
|
|
123
|
+
let e = { "data-presence": _ };
|
|
124
|
+
return (_ === "exiting" || O) && (e.inert = !0), O && (e.hidden = !0), e;
|
|
125
|
+
}, [_, O]);
|
|
126
|
+
return {
|
|
127
|
+
isMounted: _ !== "exited" || !d,
|
|
128
|
+
phase: _,
|
|
129
|
+
ref: w,
|
|
130
|
+
presenceProps: k
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
//#endregion
|
|
134
|
+
export { g as usePresence };
|
|
135
|
+
|
|
136
|
+
//# sourceMappingURL=usePresence.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePresence.mjs","names":["FALLBACK_GRACE_MS","parseTimes","value","time","entry","amount","parseList","at","list","fallback","i","isRunningFinite","animation","endTime","computedMotion","style","el","animations","transitions","names","durations","delays","counts","name","count","end","properties","transitionDurations","transitionDelays","duration","property","END_EVENTS","waitForMotion","running","waiting","onEnd","finish","cleanup","handleEnd","event","timer","type","usePresence","options","isClient","useIsClient","reducedMotion","usePrefersReducedMotion","phase","setPhase","useState","visible","appear","previousVisible","setPreviousVisible","element","setElement","elementRef","useRef","ref","useCallback","node","next","active","stopWaiting","current","handleEntered","useEventCallback","onEntered","handleExited","onExited","committedPhaseRef","previous","keptExited","unmountOnExit","presenceProps","useMemo","attributes"],"sources":["../../src/hooks/usePresence.ts"],"sourcesContent":["import { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport type * as React from 'react';\nimport { useEventCallback } from './useEventCallback';\nimport { useIsClient } from './useIsClient';\nimport { usePrefersReducedMotion } from './usePrefersReducedMotion';\n\n/**\n * Phase of an element that mounts and unmounts through the presence core: `entering` (its enter\n * motion runs), `entered`, `exiting` (its exit motion runs), `exited`.\n */\nexport type PresencePhase = 'entering' | 'entered' | 'exiting' | 'exited';\n\n/** Options of {@link usePresence}. */\nexport interface UsePresenceOptions {\n /**\n * Run the enter phase when the element mounts already visible. Never on the server or while\n * hydrating: the server HTML is the `entered` phase, and a hydrated element does not replay its\n * enter motion.\n * @default false\n */\n appear?: boolean;\n /**\n * Unmount the element once it has exited. `false` keeps it mounted while exited, `hidden` and\n * `inert`, so its state (form fields, scroll position) survives.\n * @default true\n */\n unmountOnExit?: boolean;\n /** Called when an enter phase ends (after its motion, or at once without one). */\n onEntered?: () => void;\n /**\n * Called when an exit phase ends (after its motion, or at once without one), from the commit\n * that unmounts the element (or, with `unmountOnExit: false`, hides it). Not called when the\n * parent unmounts the element while it exits, or when it is shown again first.\n */\n onExited?: () => void;\n}\n\n/** The attributes the animated element takes. */\nexport interface PresenceAttributes {\n /** The phase, always rendered: style motion with `data-[presence=entering]:…` and friends. */\n 'data-presence': PresencePhase;\n /** While exiting, and while exited when kept mounted: out of the tab order and the accessibility tree. */\n inert?: boolean;\n /** While exited when kept mounted (`unmountOnExit: false`). */\n hidden?: boolean;\n}\n\n/** Returned by {@link usePresence}. */\nexport interface UsePresenceResult {\n /** Whether to render the element. */\n isMounted: boolean;\n /** The current phase (Avatar's unrelated `PresenceStatus` is a user's availability). */\n phase: PresencePhase;\n /** Callback ref for the animated element (stable); the phases wait for its own animations. */\n ref: React.RefCallback<HTMLElement>;\n /** Spread onto the animated element. */\n presenceProps: PresenceAttributes;\n}\n\n/** Extra time the computed-style fallback waits past the longest motion before it ends a phase. */\nconst FALLBACK_GRACE_MS = 50;\n\n/** Milliseconds of each entry of a computed time list (`0.2s, 150ms`); unreadable entries are 0. */\nfunction parseTimes(value: string): number[] {\n return value.split(',').map((entry) => {\n const time = entry.trim();\n const amount = parseFloat(time);\n if (Number.isNaN(amount)) return 0;\n return time.endsWith('ms') ? amount : time.endsWith('s') ? amount * 1000 : 0;\n });\n}\n\n/** The entries of a computed list (`fade, spin`), without empty ones. */\nfunction parseList(value: string): string[] {\n return value\n .split(',')\n .map((entry) => entry.trim())\n .filter((entry) => entry !== '');\n}\n\n/** Entry `i` of a computed list that repeats to the length of its name list (CSS list rule). */\nfunction at<T>(list: T[], i: number, fallback: T): T {\n return list.length === 0 ? fallback : list[i % list.length];\n}\n\n/** Whether an animation of `el.getAnimations()` still has to end: running and finite. */\nfunction isRunningFinite(animation: Animation): boolean {\n if (animation.playState !== 'running') return false;\n const endTime = animation.effect?.getComputedTiming().endTime;\n return endTime === undefined || Number.isFinite(Number(endTime));\n}\n\n/**\n * The motion `el` itself runs now, read from its computed style (engines without\n * `getAnimations`): the animation names and transitioned properties that end, and the longest\n * time until they do (delay + duration × iterations for animations, delay + duration for\n * transitions). Infinite animations never end and are left out.\n */\nfunction computedMotion(el: HTMLElement): {\n time: number;\n animations: Set<string>;\n transitions: Set<string>;\n} {\n const style = el.ownerDocument.defaultView?.getComputedStyle(el);\n const animations = new Set<string>();\n const transitions = new Set<string>();\n let time = 0;\n if (!style) return { time, animations, transitions };\n\n const names = parseList(style.animationName);\n const durations = parseTimes(style.animationDuration);\n const delays = parseTimes(style.animationDelay);\n const counts = parseList(style.animationIterationCount);\n names.forEach((name, i) => {\n if (name === 'none') return;\n const count = Number(at(counts, i, '1'));\n if (!Number.isFinite(count)) return;\n const end = at(delays, i, 0) + at(durations, i, 0) * count;\n if (end <= 0) return;\n animations.add(name);\n time = Math.max(time, end);\n });\n\n const properties = parseList(style.transitionProperty);\n const transitionDurations = parseTimes(style.transitionDuration);\n const transitionDelays = parseTimes(style.transitionDelay);\n properties.forEach((property, i) => {\n const duration = at(transitionDurations, i, 0);\n if (property === 'none' || duration <= 0) return;\n const end = at(transitionDelays, i, 0) + duration;\n if (end <= 0) return;\n transitions.add(property);\n time = Math.max(time, end);\n });\n\n return { time, animations, transitions };\n}\n\nconst END_EVENTS = ['animationend', 'animationcancel', 'transitionend', 'transitioncancel'];\n\n/**\n * Waits for the motion `el` itself runs and calls `onEnd` once it has ended (never synchronously).\n * Returns `null` when nothing runs (the phase ends at once), else a cleanup that stops waiting.\n *\n * - With `getAnimations()`: every running finite animation of the element (CSS animations and\n * transitions alike) has finished; a cancelled one counts as finished.\n * - Without it: the computed style's longest motion plus {@link FALLBACK_GRACE_MS}, or earlier once\n * the element's own end and cancel events have accounted for every animation name and\n * transitioned property it lists.\n */\nfunction waitForMotion(el: HTMLElement, onEnd: () => void): (() => void) | null {\n if (typeof el.getAnimations === 'function') {\n const running = el.getAnimations().filter(isRunningFinite);\n if (running.length === 0) return null;\n let waiting = true;\n void Promise.allSettled(running.map((animation) => animation.finished)).then(() => {\n if (waiting) onEnd();\n });\n return () => {\n waiting = false;\n };\n }\n\n const { time, animations, transitions } = computedMotion(el);\n if (time <= 0) return null;\n const finish = () => {\n cleanup();\n onEnd();\n };\n const handleEnd = (event: Event) => {\n if (event.target !== el) return;\n if (event.type.startsWith('animation')) {\n animations.delete((event as AnimationEvent).animationName);\n } else {\n const property = (event as TransitionEvent).propertyName;\n if (!transitions.delete(property)) transitions.delete('all');\n }\n if (animations.size === 0 && transitions.size === 0) finish();\n };\n const timer = setTimeout(finish, time + FALLBACK_GRACE_MS);\n for (const type of END_EVENTS) el.addEventListener(type, handleEnd);\n function cleanup() {\n clearTimeout(timer);\n for (const type of END_EVENTS) el.removeEventListener(type, handleEnd);\n }\n return cleanup;\n}\n\n/**\n * Mounts and unmounts an element with CSS enter and exit motion. Style the phases with\n * `data-presence` variants, e.g. `transition-opacity duration-wave-normal\n * data-[presence=entering]:starting:opacity-0 data-[presence=exiting]:opacity-0\n * motion-reduce:transition-none`. Gate the enter's start style on the entering phase, as there: an\n * ungated `starting:` class (`@starting-style`) applies to every first style of the element, so it\n * also animates a mount the core treats as `entered` (without `appear`, and when hydrating).\n * Destructure the result (`const { isMounted, ref, presenceProps } = usePresence(open)`):\n * react-hooks/refs treats an object whose member is passed to `ref` as a ref, so reading `phase`\n * or `presenceProps` from the whole object during render is an error (the usePopupPosition rule).\n *\n * - **Phases.** On the server and while hydrating the element is `entered` when `visible`, else\n * `exited`; a client mount is `entering` with `appear`, else `entered` (or `exited`). `visible`\n * becoming `true` enters, becoming `false` exits a mounted element; showing it again while it\n * exits goes back to `entering` with the same element.\n * - **End of a phase.** `entering` and `exiting` end when every running finite animation of the\n * element itself (`getAnimations()`: CSS animations and transitions) has finished or was\n * cancelled; engines without `getAnimations` read the computed `animation-*`/`transition-*`\n * times and the element's end events. A phase ends at once under `prefers-reduced-motion:\n * reduce`, without an element and without running motion, from a layout effect: an element\n * without motion unmounts before the browser paints, in the same `act()`.\n * - **Attributes.** `data-presence` always; `inert` while exiting (the exiting element is out of\n * the tab order and the accessibility tree), and `inert` plus `hidden` while exited when kept\n * mounted (`unmountOnExit: false`). No inline style, no class, no JS animation.\n * - **Callbacks.** `onEntered` and `onExited` run once per phase change, StrictMode included,\n * from an effect after the commit of the new phase.\n * - Focus, dismiss layers and focus restore stay the component's: key them on the open state, not\n * on `isMounted`, so they run on close rather than after the exit motion.\n *\n * @example\n * const { isMounted, ref, presenceProps } = usePresence(open);\n * return isMounted ? (\n * <div\n * ref={ref}\n * {...presenceProps}\n * className=\"transition-opacity duration-wave-normal data-[presence=entering]:starting:opacity-0 data-[presence=exiting]:opacity-0 motion-reduce:transition-none\"\n * />\n * ) : null;\n *\n * @param visible - Whether the element is shown.\n * @param options - See {@link UsePresenceOptions}.\n */\nexport function usePresence(visible: boolean, options: UsePresenceOptions = {}): UsePresenceResult {\n const { appear = false, unmountOnExit = true, onEntered, onExited } = options;\n const isClient = useIsClient();\n const reducedMotion = usePrefersReducedMotion();\n\n const [phase, setPhase] = useState<PresencePhase>(() => {\n if (!visible) return 'exited';\n return isClient && appear ? 'entering' : 'entered';\n });\n\n // Changes of `visible`, derived during render (C-HOOKS: a previous-value state).\n const [previousVisible, setPreviousVisible] = useState(visible);\n if (visible !== previousVisible) {\n setPreviousVisible(visible);\n if (visible) setPhase('entering');\n else if (phase !== 'exited') setPhase('exiting');\n }\n\n // The element: in state, so the phase-end effect re-runs when it attaches, and in a ref, which\n // that effect reads (a DOM-derived update in a layout effect).\n const [element, setElement] = useState<HTMLElement | null>(null);\n const elementRef = useRef<HTMLElement | null>(null);\n const ref = useCallback((node: HTMLElement | null) => {\n elementRef.current = node;\n setElement(node);\n }, []);\n\n // End of the entering and exiting phases.\n useLayoutEffect(() => {\n if (phase !== 'entering' && phase !== 'exiting') return undefined;\n const next: PresencePhase = phase === 'entering' ? 'entered' : 'exited';\n const el = elementRef.current;\n // Guards the waiting phase: one that was replaced (or unmounted) never ends the new one.\n let active = true;\n const endLater = () => {\n if (active) setPhase((current) => (current === phase ? next : current));\n };\n const stopWaiting = el && !reducedMotion ? waitForMotion(el, endLater) : null;\n if (!stopWaiting) {\n setPhase(next);\n return undefined;\n }\n return () => {\n active = false;\n stopWaiting();\n };\n }, [phase, element, reducedMotion]);\n\n // The callbacks, once per committed phase change (never from the effect above, which StrictMode\n // runs twice on mount before the new phase renders).\n const handleEntered = useEventCallback(onEntered);\n const handleExited = useEventCallback(onExited);\n const committedPhaseRef = useRef<PresencePhase | null>(null);\n useLayoutEffect(() => {\n const previous = committedPhaseRef.current;\n committedPhaseRef.current = phase;\n if (previous === 'entering' && phase === 'entered') handleEntered();\n else if (previous === 'exiting' && phase === 'exited') handleExited();\n }, [phase, handleEntered, handleExited]);\n\n const keptExited = phase === 'exited' && !unmountOnExit;\n const presenceProps = useMemo<PresenceAttributes>(() => {\n const attributes: PresenceAttributes = { 'data-presence': phase };\n if (phase === 'exiting' || keptExited) attributes.inert = true;\n if (keptExited) attributes.hidden = true;\n return attributes;\n }, [phase, keptExited]);\n\n return { isMounted: phase !== 'exited' || !unmountOnExit, phase, ref, presenceProps };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";const e=require("./useEventCallback.cjs");let t=require("react");function n(e,t){let n=e?.ownerDocument.activeElement;if(!e||!n||!e.contains(n))return;let r=t();r&&!e.contains(r)&&r.focus({preventScroll:!0})}function r(r,i,a){let o=a?.enabled??!0,s=e.useEventCallback(i),c=(0,t.useRef)({node:null,enabled:o}),l=(0,t.useRef)(o),u=(0,t.useRef)(null);(0,t.useLayoutEffect)(()=>{c.current={node:r.current,enabled:o}}),(0,t.useLayoutEffect)(()=>{let e=l.current;l.current=o,e&&!o&&n(r.current,s)},[o,r,s]),(0,t.useLayoutEffect)(()=>{let e=c,t=u;return t.current=null,()=>{let{node:n,enabled:r}=e.current;if(!r||!n)return;let i=n.ownerDocument,a=i.activeElement;if(!a||!n.contains(a))return;let o={};t.current=o,queueMicrotask(()=>{if(t.current!==o)return;t.current=null;let e=i.activeElement;if(e&&e!==i.body&&!n.contains(e))return;let r=s();r&&r.isConnected&&!n.contains(r)&&r.focus({preventScroll:!0})})}},[s])}exports.usePreserveFocus=r;
|
|
2
|
+
//# sourceMappingURL=usePreserveFocus.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePreserveFocus.cjs","names":["useEventCallback","useRef","require_useEventCallback","react","moveFocusOut","active","node","fallback","getFallback","usePreserveFocus","enabled","options","resolveFallback","stateRef","previousEnabledRef","scheduledMoveRef","ref","wasEnabled","state","scheduled","isEnabled","doc","token","now"],"sources":["../../src/hooks/usePreserveFocus.ts"],"sourcesContent":["import { useLayoutEffect, useRef } from 'react';\nimport type * as React from 'react';\nimport { useEventCallback } from './useEventCallback';\n\n/** Options of {@link usePreserveFocus}. */\nexport interface UsePreserveFocusOptions {\n /** While `false` nothing is done; flipping to `false` while focus is inside moves it. @default true */\n enabled?: boolean;\n}\n\nfunction moveFocusOut(\n node: HTMLElement | null,\n getFallback: () => HTMLElement | null | undefined,\n): void {\n const active = node?.ownerDocument.activeElement;\n if (!node || !active || !node.contains(active)) return;\n const fallback = getFallback();\n if (fallback && !node.contains(fallback)) {\n fallback.focus({ preventScroll: true });\n }\n}\n\n/**\n * Keeps focus from falling to `<body>` when an element that contains it goes away: if\n * `ref.current` contains the focused element when the component unmounts or when `enabled` flips\n * to `false`, focus moves to `getFallback()`.\n *\n * - **`enabled` → `false`**: focus moves in the layout phase, while the element is still there.\n * - **Unmount**: the layout-effect cleanup notes (before the node is removed) that it contains\n * focus, and the move runs in a **microtask** after the commit. It is cancelled when the same\n * instance mounts again, so React 19 StrictMode's simulated unmount right after mount (an\n * `autoFocus` inside the element) does not move focus in development. Tests assert the move\n * after awaiting a microtask (`await act(async () => {})`, or `userEvent`).\n * - **Other focus owners.** The unmount move is skipped when focus was already placed outside the\n * element before the microtask runs: in the same commit's layout phase (an `autoFocus`, a\n * layout-effect restore-focus hook), or in passive effects React flushes synchronously with the\n * commit (renders caused by a discrete event such as a click or a key press). Focus placed later\n * — for example by a passive effect of a render caused by a timer, which React runs in a later\n * task — is placed after the move and simply replaces it.\n *\n * Used for elements removed as a result of their own activation or a timer (a toast whose Dismiss\n * button has focus, a clear button that hides itself).\n *\n * @param ref The element that may contain focus.\n * @param getFallback Returns the element to focus instead. It is read when needed, which for an\n * unmount is after the element (and possibly the whole React tree) has been removed: it must\n * return `null`/`undefined` rather than throw when the fallback no longer exists (e.g. use\n * `querySelector`, not a throwing lookup). A fallback that is not connected is ignored.\n * @param options See {@link UsePreserveFocusOptions}.\n */\nexport function usePreserveFocus(\n ref: React.RefObject<HTMLElement | null>,\n getFallback: () => HTMLElement | null | undefined,\n options?: UsePreserveFocusOptions,\n): void {\n const enabled = options?.enabled ?? true;\n const resolveFallback = useEventCallback(getFallback);\n // Element and `enabled` of the last commit, read by the unmount cleanup.\n const stateRef = useRef<{ node: HTMLElement | null; enabled: boolean }>({\n node: null,\n enabled,\n });\n const previousEnabledRef = useRef(enabled);\n // Token of the unmount move scheduled by the cleanup; a remount of this instance clears it.\n const scheduledMoveRef = useRef<object | null>(null);\n\n useLayoutEffect(() => {\n stateRef.current = { node: ref.current, enabled };\n });\n\n // `enabled` true -> false: move focus in the layout phase. (A move inside a cleanup would be\n // undone: React refocuses the previously focused element after the mutation phase when it is\n // still in the document.)\n useLayoutEffect(() => {\n const wasEnabled = previousEnabledRef.current;\n previousEnabledRef.current = enabled;\n if (wasEnabled && !enabled) moveFocusOut(ref.current, resolveFallback);\n }, [enabled, ref, resolveFallback]);\n\n // Unmount: the cleanup runs before the node is removed, while it still contains focus; the move\n // is deferred to a microtask and cancelled by a remount of this instance (StrictMode).\n useLayoutEffect(() => {\n const state = stateRef;\n const scheduled = scheduledMoveRef;\n scheduled.current = null;\n return () => {\n const { node, enabled: isEnabled } = state.current;\n if (!isEnabled || !node) return;\n const doc = node.ownerDocument;\n const active = doc.activeElement;\n if (!active || !node.contains(active)) return;\n const token = {};\n scheduled.current = token;\n queueMicrotask(() => {\n if (scheduled.current !== token) return;\n scheduled.current = null;\n const now = doc.activeElement;\n // Focus placed elsewhere before this microtask (same commit) wins.\n if (now && now !== doc.body && !node.contains(now)) return;\n const fallback = resolveFallback();\n if (fallback && fallback.isConnected && !node.contains(fallback)) {\n fallback.focus({ preventScroll: true });\n }\n });\n };\n }, [resolveFallback]);\n}\n"],"mappings":"8EAUA,SAASI,EACP,EACA,EACM,CACN,IAAMC,EAASC,GAAM,cAAc,cACnC,GAAI,CAACA,GAAQ,CAACD,GAAU,CAACC,EAAK,SAASD,CAAM,EAAG,OAChD,IAAME,EAAWC,EAAY,EACzBD,GAAY,CAACD,EAAK,SAASC,CAAQ,GACrCA,EAAS,MAAM,CAAE,cAAe,EAAK,CAAC,CAE1C,CA8BA,SAAgBE,EACd,EACA,EACA,EACM,CACN,IAAMC,EAAUC,GAAS,SAAW,GAC9BC,EAAkBZ,EAAAA,iBAAiBQ,CAAW,EAE9CK,GAAA,EAAWZ,EAAAA,OAAAA,CAAuD,CACtE,KAAM,KACN,SACF,CAAC,EACKa,GAAA,EAAqBb,EAAAA,OAAAA,CAAOS,CAAO,EAEnCK,GAAA,EAAmBd,EAAAA,OAAAA,CAAsB,IAAI,GAEnD,EAAAE,EAAA,gBAAA,KAAsB,CACpB,EAAS,QAAU,CAAE,KAAMa,EAAI,QAAS,SAAQ,CAClD,CAAC,GAKD,EAAAb,EAAA,gBAAA,KAAsB,CACpB,IAAMc,EAAaH,EAAmB,QACtC,EAAmB,QAAUJ,EACzBO,GAAc,CAACP,GAASN,EAAaY,EAAI,QAASJ,CAAe,CACvE,EAAG,CAACF,EAASM,EAAKJ,CAAe,CAAC,GAIlC,EAAAT,EAAA,gBAAA,KAAsB,CACpB,IAAMe,EAAQL,EACRM,EAAYJ,EAElB,MADA,GAAU,QAAU,SACP,CACX,GAAM,CAAE,OAAM,QAASK,GAAcF,EAAM,QAC3C,GAAI,CAACE,GAAa,CAACd,EAAM,OACzB,IAAMe,EAAMf,EAAK,cACXD,EAASgB,EAAI,cACnB,GAAI,CAAChB,GAAU,CAACC,EAAK,SAASD,CAAM,EAAG,OACvC,IAAMiB,EAAQ,CAAC,EACf,EAAU,QAAUA,EACpB,mBAAqB,CACnB,GAAIH,EAAU,UAAYG,EAAO,OACjC,EAAU,QAAU,KACpB,IAAMC,EAAMF,EAAI,cAEhB,GAAIE,GAAOA,IAAQF,EAAI,MAAQ,CAACf,EAAK,SAASiB,CAAG,EAAG,OACpD,IAAMhB,EAAWK,EAAgB,EAC7BL,GAAYA,EAAS,aAAe,CAACD,EAAK,SAASC,CAAQ,GAC7DA,EAAS,MAAM,CAAE,cAAe,EAAK,CAAC,CAE1C,CAAC,CACH,CACF,EAAG,CAACK,CAAe,CAAC,CACtB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEventCallback as e } from "./useEventCallback.mjs";
|
|
3
|
+
import { useLayoutEffect as t, useRef as n } from "react";
|
|
4
|
+
//#region src/hooks/usePreserveFocus.ts
|
|
5
|
+
function r(e, t) {
|
|
6
|
+
let n = e?.ownerDocument.activeElement;
|
|
7
|
+
if (!e || !n || !e.contains(n)) return;
|
|
8
|
+
let r = t();
|
|
9
|
+
r && !e.contains(r) && r.focus({ preventScroll: !0 });
|
|
10
|
+
}
|
|
11
|
+
function i(i, a, o) {
|
|
12
|
+
let s = o?.enabled ?? !0, c = e(a), l = n({
|
|
13
|
+
node: null,
|
|
14
|
+
enabled: s
|
|
15
|
+
}), u = n(s), d = n(null);
|
|
16
|
+
t(() => {
|
|
17
|
+
l.current = {
|
|
18
|
+
node: i.current,
|
|
19
|
+
enabled: s
|
|
20
|
+
};
|
|
21
|
+
}), t(() => {
|
|
22
|
+
let e = u.current;
|
|
23
|
+
u.current = s, e && !s && r(i.current, c);
|
|
24
|
+
}, [
|
|
25
|
+
s,
|
|
26
|
+
i,
|
|
27
|
+
c
|
|
28
|
+
]), t(() => {
|
|
29
|
+
let e = l, t = d;
|
|
30
|
+
return t.current = null, () => {
|
|
31
|
+
let { node: n, enabled: r } = e.current;
|
|
32
|
+
if (!r || !n) return;
|
|
33
|
+
let i = n.ownerDocument, a = i.activeElement;
|
|
34
|
+
if (!a || !n.contains(a)) return;
|
|
35
|
+
let o = {};
|
|
36
|
+
t.current = o, queueMicrotask(() => {
|
|
37
|
+
if (t.current !== o) return;
|
|
38
|
+
t.current = null;
|
|
39
|
+
let e = i.activeElement;
|
|
40
|
+
if (e && e !== i.body && !n.contains(e)) return;
|
|
41
|
+
let r = c();
|
|
42
|
+
r && r.isConnected && !n.contains(r) && r.focus({ preventScroll: !0 });
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
}, [c]);
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
export { i as usePreserveFocus };
|
|
49
|
+
|
|
50
|
+
//# sourceMappingURL=usePreserveFocus.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePreserveFocus.mjs","names":["moveFocusOut","active","node","fallback","getFallback","usePreserveFocus","enabled","options","resolveFallback","useEventCallback","stateRef","useRef","previousEnabledRef","scheduledMoveRef","useLayoutEffect","ref","wasEnabled","state","scheduled","isEnabled","doc","token","now"],"sources":["../../src/hooks/usePreserveFocus.ts"],"sourcesContent":["import { useLayoutEffect, useRef } from 'react';\nimport type * as React from 'react';\nimport { useEventCallback } from './useEventCallback';\n\n/** Options of {@link usePreserveFocus}. */\nexport interface UsePreserveFocusOptions {\n /** While `false` nothing is done; flipping to `false` while focus is inside moves it. @default true */\n enabled?: boolean;\n}\n\nfunction moveFocusOut(\n node: HTMLElement | null,\n getFallback: () => HTMLElement | null | undefined,\n): void {\n const active = node?.ownerDocument.activeElement;\n if (!node || !active || !node.contains(active)) return;\n const fallback = getFallback();\n if (fallback && !node.contains(fallback)) {\n fallback.focus({ preventScroll: true });\n }\n}\n\n/**\n * Keeps focus from falling to `<body>` when an element that contains it goes away: if\n * `ref.current` contains the focused element when the component unmounts or when `enabled` flips\n * to `false`, focus moves to `getFallback()`.\n *\n * - **`enabled` → `false`**: focus moves in the layout phase, while the element is still there.\n * - **Unmount**: the layout-effect cleanup notes (before the node is removed) that it contains\n * focus, and the move runs in a **microtask** after the commit. It is cancelled when the same\n * instance mounts again, so React 19 StrictMode's simulated unmount right after mount (an\n * `autoFocus` inside the element) does not move focus in development. Tests assert the move\n * after awaiting a microtask (`await act(async () => {})`, or `userEvent`).\n * - **Other focus owners.** The unmount move is skipped when focus was already placed outside the\n * element before the microtask runs: in the same commit's layout phase (an `autoFocus`, a\n * layout-effect restore-focus hook), or in passive effects React flushes synchronously with the\n * commit (renders caused by a discrete event such as a click or a key press). Focus placed later\n * — for example by a passive effect of a render caused by a timer, which React runs in a later\n * task — is placed after the move and simply replaces it.\n *\n * Used for elements removed as a result of their own activation or a timer (a toast whose Dismiss\n * button has focus, a clear button that hides itself).\n *\n * @param ref The element that may contain focus.\n * @param getFallback Returns the element to focus instead. It is read when needed, which for an\n * unmount is after the element (and possibly the whole React tree) has been removed: it must\n * return `null`/`undefined` rather than throw when the fallback no longer exists (e.g. use\n * `querySelector`, not a throwing lookup). A fallback that is not connected is ignored.\n * @param options See {@link UsePreserveFocusOptions}.\n */\nexport function usePreserveFocus(\n ref: React.RefObject<HTMLElement | null>,\n getFallback: () => HTMLElement | null | undefined,\n options?: UsePreserveFocusOptions,\n): void {\n const enabled = options?.enabled ?? true;\n const resolveFallback = useEventCallback(getFallback);\n // Element and `enabled` of the last commit, read by the unmount cleanup.\n const stateRef = useRef<{ node: HTMLElement | null; enabled: boolean }>({\n node: null,\n enabled,\n });\n const previousEnabledRef = useRef(enabled);\n // Token of the unmount move scheduled by the cleanup; a remount of this instance clears it.\n const scheduledMoveRef = useRef<object | null>(null);\n\n useLayoutEffect(() => {\n stateRef.current = { node: ref.current, enabled };\n });\n\n // `enabled` true -> false: move focus in the layout phase. (A move inside a cleanup would be\n // undone: React refocuses the previously focused element after the mutation phase when it is\n // still in the document.)\n useLayoutEffect(() => {\n const wasEnabled = previousEnabledRef.current;\n previousEnabledRef.current = enabled;\n if (wasEnabled && !enabled) moveFocusOut(ref.current, resolveFallback);\n }, [enabled, ref, resolveFallback]);\n\n // Unmount: the cleanup runs before the node is removed, while it still contains focus; the move\n // is deferred to a microtask and cancelled by a remount of this instance (StrictMode).\n useLayoutEffect(() => {\n const state = stateRef;\n const scheduled = scheduledMoveRef;\n scheduled.current = null;\n return () => {\n const { node, enabled: isEnabled } = state.current;\n if (!isEnabled || !node) return;\n const doc = node.ownerDocument;\n const active = doc.activeElement;\n if (!active || !node.contains(active)) return;\n const token = {};\n scheduled.current = token;\n queueMicrotask(() => {\n if (scheduled.current !== token) return;\n scheduled.current = null;\n const now = doc.activeElement;\n // Focus placed elsewhere before this microtask (same commit) wins.\n if (now && now !== doc.body && !node.contains(now)) return;\n const fallback = resolveFallback();\n if (fallback && fallback.isConnected && !node.contains(fallback)) {\n fallback.focus({ preventScroll: true });\n }\n });\n };\n }, [resolveFallback]);\n}\n"],"mappings":";;;;AAUA,SAASA,EACP,GACA,GACM;CACN,IAAMC,IAASC,GAAM,cAAc;CACnC,IAAI,CAACA,KAAQ,CAACD,KAAU,CAACC,EAAK,SAASD,CAAM,GAAG;CAChD,IAAME,IAAWC,EAAY;CAC7B,AAAID,KAAY,CAACD,EAAK,SAASC,CAAQ,KACrCA,EAAS,MAAM,EAAE,eAAe,GAAK,CAAC;AAE1C;AA8BA,SAAgBE,EACd,GACA,GACA,GACM;CACN,IAAMC,IAAUC,GAAS,WAAW,IAC9BC,IAAkBC,EAAiBL,CAAW,GAE9CM,IAAWC,EAAuD;EACtE,MAAM;EACN;CACF,CAAC,GACKC,IAAqBD,EAAOL,CAAO,GAEnCO,IAAmBF,EAAsB,IAAI;CAiBnD,AAfAG,QAAsB;EACpB,EAAS,UAAU;GAAE,MAAMC,EAAI;GAAS;EAAQ;CAClD,CAAC,GAKDD,QAAsB;EACpB,IAAME,IAAaJ,EAAmB;EAEtC,AADA,EAAmB,UAAUN,GACzBU,KAAc,CAACV,KAASN,EAAae,EAAI,SAASP,CAAe;CACvE,GAAG;EAACF;EAASS;EAAKP;CAAe,CAAC,GAIlCM,QAAsB;EACpB,IAAMG,IAAQP,GACRQ,IAAYL;EAElB,OADA,EAAU,UAAU,YACP;GACX,IAAM,EAAE,SAAM,SAASM,MAAcF,EAAM;GAC3C,IAAI,CAACE,KAAa,CAACjB,GAAM;GACzB,IAAMkB,IAAMlB,EAAK,eACXD,IAASmB,EAAI;GACnB,IAAI,CAACnB,KAAU,CAACC,EAAK,SAASD,CAAM,GAAG;GACvC,IAAMoB,IAAQ,CAAC;GAEf,AADA,EAAU,UAAUA,GACpB,qBAAqB;IACnB,IAAIH,EAAU,YAAYG,GAAO;IACjC,EAAU,UAAU;IACpB,IAAMC,IAAMF,EAAI;IAEhB,IAAIE,KAAOA,MAAQF,EAAI,QAAQ,CAAClB,EAAK,SAASoB,CAAG,GAAG;IACpD,IAAMnB,IAAWK,EAAgB;IACjC,AAAIL,KAAYA,EAAS,eAAe,CAACD,EAAK,SAASC,CAAQ,KAC7DA,EAAS,MAAM,EAAE,eAAe,GAAK,CAAC;GAE1C,CAAC;EACH;CACF,GAAG,CAACK,CAAe,CAAC;AACtB"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("../lib/globalRegistry.cjs"),n=require("../lib/focus.cjs"),r=require("../lib/layers.cjs"),i=require("./useDismiss.cjs");let a=require("react");a=e.__toESM(a,1);var o=4,s=`[data-wave-portal]`;function c(e){return!e||!e.isConnected||!n.isFocusable(e)||e.closest(`[aria-hidden="true"]`)?!1:!r.isInsideOtherOpenModal(e)}function l(e){let t={path:[],next:[],previous:[]},n=e.ownerDocument.body;for(let r=e;r&&(t.path.push(r),t.next.push(r.nextElementSibling),t.previous.push(r.previousElementSibling),r!==n);r=r.parentElement);return t}function u(e,t){if(e.closest(`[data-wave-focus-trap-allow]`))return[];let n=r.getOpenLayers().filter(t=>r.isInsideLayerTree(t.id,e)).sort((e,t)=>r.compareLayers(t,e)),i=[];for(let r of n){let n=r.getAnchor();!n||n===e||t&&t.contains(n)||i.some(e=>e.element===n)||i.push({element:n,position:l(n)})}return i}function d(){let e=m();return e.surfaces??=new Set,e.surfaces}function f(e,t=new Set){if(t.has(e))return!1;if(t.add(e),e.isHoverClose())return!0;let n=e.getOpener();if(!n)return!1;for(let r of d()){let i=r===e?null:r.getContainer();if(i&&i.contains(n)&&f(r,t))return!0}return!1}function p(e,t){return e?f(e):t.isHoverClose?.()===!0}function m(){return t.getGlobalRegistry(`restoreFocusTracker`,()=>({users:0,last:null,uninstall:null}))}var h=1;function g(e){return!!e&&e.nodeType===h}function _(e,t){let n=t.ownerDocument;if(t===n.body||t===n.documentElement){e.last=null;return}e.last={element:t,position:l(t),anchors:u(t,null)}}function v(e){let t=e.last;if(!t||!t.element.isConnected)return;let n=u(t.element,null);for(let e of t.anchors)n.some(t=>t.element===e.element)||n.push(e);e.last={element:t.element,position:l(t.element),anchors:n}}function y(){if(typeof document>`u`)return()=>{};let e=m();if(e.users+=1,!e.uninstall){let t=document,i=t=>{g(t.target)&&_(e,t.target)},a=t=>{let r=t.target;!t.relatedTarget&&g(r)&&queueMicrotask(()=>{e.last?.element===r&&r.isConnected&&n.isFocusable(r)&&r.ownerDocument.activeElement!==r&&(e.last=null)})};t.addEventListener(`focusin`,i,!0),t.addEventListener(`focusout`,a,!0);let o=r.subscribeLayers(()=>v(e));g(t.activeElement)&&_(e,t.activeElement),e.uninstall=()=>{t.removeEventListener(`focusin`,i,!0),t.removeEventListener(`focusout`,a,!0),o(),e.last=null}}let t=!0;return()=>{t&&(t=!1,e.users=Math.max(0,e.users-1),!(e.users>0)&&(e.uninstall?.(),e.uninstall=null))}}function b(){let e=m().last;if(!e)return null;let{element:t}=e;return t.ownerDocument.activeElement===t||t.isConnected&&n.isFocusable(t)?null:e}function x(e){if(typeof document>`u`)return null;let{container:t,triggerRef:n}=e,r=e=>!!e&&e!==e.ownerDocument.body&&e!==e.ownerDocument.documentElement&&!(t&&t.contains(e)),i=n?.current,a=document.activeElement,o=null;if(r(i)?o=i:r(a)&&(o=a),o)return{element:o,position:l(o),anchors:u(o,t)};let s=b();return!s||!r(s.element)?null:{element:s.element,position:s.position,anchors:s.anchors.filter(e=>!(t&&t.contains(e.element)))}}function S(e){if(!e)return[];let t=[];for(let r of e.getElements()){if(!r)continue;t.push(r);let e=n.getFirstTabbable(r);e&&t.push(e)}return t}function C(e,t){let{ref:n,placement:r}=t;if(e===n)return r===`before`;let i=(n.compareDocumentPosition(e)&o)!==0;return r===`before`?i:i&&!n.contains(e)}function w(e){let{path:t}=e,n=t.findIndex(e=>e.isConnected);if(n===-1)return null;if(n===0){let e=t[0].parentElement;return e?{root:e,point:{ref:t[0],placement:`after`}}:null}if(t.slice(0,n).some(e=>e.matches(s)))return null;let r=t[n],i=e.next[n-1];if(i&&i.parentElement===r)return{root:r,point:{ref:i,placement:`before`}};let a=e.previous[n-1];return a&&a.parentElement===r?{root:r,point:{ref:a,placement:`after`}}:{root:r,point:{ref:r,placement:`before`}}}function T(e,t){let i=w(e);if(!i)return[];let{root:a,point:l}=i,u=a.ownerDocument.body,d=[];for(let e=a;e&&!(r.isInsideOtherOpenModal(e)||(d.push(e),e===u||e.matches(s)));e=e.parentElement);if(d.length===0)return[];let f=n.getTabbableElements(d[d.length-1]).filter(e=>!(t&&t.contains(e))&&c(e)).sort((e,t)=>(e.compareDocumentPosition(t)&o)===0?1:-1),p=[];for(let e of d){let t=f.filter(t=>e.contains(t)&&!p.includes(t)),n=t.find(e=>C(e,l)),r=t.filter(e=>!C(e,l)).pop();n&&p.push(n),r&&p.push(r)}return p}function E(e,t){if(typeof document>`u`)return!1;let n=document.activeElement,r=!n||n===document.body||n===document.documentElement;return!r&&e.container?.contains(n)?!0:!r&&e.onlyIfFocusInside?!1:!t()}function*D(e,t){yield*T(e.position,t);for(let t of e.anchors)yield t.element;for(let n of e.anchors)yield*T(n.position,t)}function*O(e,t){let{options:n,parentLayerId:i}=e;yield n.finalFocusRef?.current,yield t?.element,yield n.triggerRef?.current,yield n.fallback?.();let a=t?D(t,n.container):null,o=i===null?null:r.getLayer(i),s=[];if(o){for(let e of a??[])r.isInsideLayerTree(o.id,e)?yield e:s.push(e);yield*S(o),yield*s}else a&&(yield*a);yield*S(r.getTopmostLayer(e=>e.kind===`modal`))}function k(e,t){let r=e.options.container;for(let i of O(e,t))if(!(r&&i&&r.contains(i))&&c(i)&&n.focusElement(i,{preventScroll:!0}))return}function A(e){let t=a.useContext(i.DismissLayerContext),n=(0,a.useRef)({options:e,parentLayerId:t}),r=(0,a.useRef)(null),o=(0,a.useRef)(!1),s=(0,a.useRef)(!1),c=(0,a.useRef)(null),l=(0,a.useRef)(null),{enabled:u}=e;(0,a.useLayoutEffect)(()=>{let e=y(),t={isHoverClose:()=>n.current.options.isHoverClose?.()===!0,getContainer:()=>n.current.options.container??null,getOpener:()=>r.current?.element??n.current.options.triggerRef?.current??null};l.current=t;let i=d();return i.add(t),()=>{e(),queueMicrotask(()=>i.delete(t))}},[]),(0,a.useInsertionEffect)(()=>{n.current={options:e,parentLayerId:t};let i=o.current;o.current=e.enabled,e.enabled&&!i&&(r.current=x(e))}),(0,a.useLayoutEffect)(()=>{let e=s.current;if(s.current=u,!e||u)return;let t=n.current,i=r.current,a=l.current,o=E(t.options,()=>p(a,t.options));r.current=null,o&&k(t,i)},[u]),(0,a.useLayoutEffect)(()=>{let e=n,t=r,i=c,a=l;return i.current=null,()=>{let n=e.current;if(!n.options.enabled)return;let r=a.current;if(!E(n.options,()=>p(r,n.options)))return;let o={};i.current=o;let s=t.current;queueMicrotask(()=>{if(i.current!==o)return;i.current=null;let e=typeof document>`u`?null:document.activeElement,t=n.options.container;(!e||e===document.body||e===document.documentElement||t&&t.contains(e))&&k(n,s)})}},[])}exports.useRestoreFocus=A;
|
|
2
|
+
//# sourceMappingURL=useRestoreFocus.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRestoreFocus.cjs","names":["isFocusable","isInsideOtherOpenModal","getOpenLayers","isInsideLayerTree","compareLayers","getGlobalRegistry","subscribeLayers","getFirstTabbable","getTabbableElements","getLayer","getTopmostLayer","focusElement","React","DismissLayerContext","useRef","require_runtime","require_globalRegistry","require_focus","require_layers","require_useDismiss","react","FOLLOWING","PORTAL_SELECTOR","isValidTarget","el","recordPosition","position","body","node","captureAnchors","opener","layers","layer","b","a","anchors","anchor","container","entry","getSurfaceEntries","tracker","getFocusTracker","isClosingByHover","seen","other","isHoverCloseOf","options","ELEMENT_NODE","isElementTarget","target","recordFocus","doc","refreshFocusRecord","last","retainFocusTracker","onFocusIn","event","onFocusOut","unsubscribe","retained","getLostFocus","element","captureOpener","isCandidate","trigger","triggerRef","active","lost","getLayerTargets","targets","first","isAfterPoint","point","ref","placement","follows","resolvePoint","index","path","root","next","previous","getNearbyTargets","resolved","levels","level","candidates","inLevel","after","before","shouldRestore","onBody","isHoverClose","getReplacementTargets","restoreCandidates","latest","replacements","parentLayer","parentLayerId","outsideParent","restore","candidate","useRestoreFocus","latestRef","capturedRef","insertionEnabledRef","layoutEnabledRef","scheduledRef","entryRef","release","surfaces","wasEnabled","enabled","captured","acts","scheduled","entryHolder","snapshot","token"],"sources":["../../src/hooks/useRestoreFocus.ts"],"sourcesContent":["import * as React from 'react';\nimport { useInsertionEffect, useLayoutEffect, useRef } from 'react';\nimport { focusElement, getFirstTabbable, getTabbableElements, isFocusable } from '../lib/focus';\nimport { getGlobalRegistry } from '../lib/globalRegistry';\nimport {\n ALLOW_OUTSIDE_SELECTOR,\n compareLayers,\n getLayer,\n getOpenLayers,\n getTopmostLayer,\n isInsideLayerTree,\n isInsideOtherOpenModal,\n subscribeLayers,\n type LayerRecord,\n} from '../lib/layers';\nimport { DismissLayerContext } from './useDismiss';\n\n/** Options of {@link useRestoreFocus}. */\nexport interface UseRestoreFocusOptions {\n /** `true` while the surface is open. */\n enabled: boolean;\n /** The layer surface: opener candidates inside it are ignored. */\n container?: HTMLElement | null;\n /** The trigger: preferred restore target. */\n triggerRef?: React.RefObject<HTMLElement | null>;\n /** Consumer override: focused first when valid. */\n finalFocusRef?: React.RefObject<HTMLElement | null>;\n /** Used when neither the override, the opener nor the trigger can take focus. */\n fallback?: () => HTMLElement | null;\n /**\n * Popovers: restore only when focus was inside the surface (or lost to `<body>`) at close, so a\n * click that moved focus elsewhere is respected. @default false\n */\n onlyIfFocusInside?: boolean;\n /**\n * Read when the surface closes, or unmounts while open: `true` when the hover intent closed it\n * (Popover and Menu `openOnHover`, a submenu closing by hover). A hover close never moves focus:\n * it restores only while focus is inside the surface, so focus on `<body>` (where a hover-opened\n * surface leaves it) or elsewhere stays where it is. A surface opened from inside one that closes\n * by hover (its opener, else its trigger, lies in that surface: a submenu, a hover card in a\n * hover card, at any depth) is taken along, and its close counts as a hover close too. Every\n * other close keeps the rules above.\n */\n isHoverClose?: () => boolean;\n}\n\ninterface Latest {\n options: UseRestoreFocusOptions;\n parentLayerId: string | null;\n}\n\n/** Where an element sat in the document, recorded so a spot near it can be found once it is gone. */\ninterface DomPosition {\n /** The element and its ancestors up to `<body>`, innermost first. */\n path: Element[];\n /** The next element sibling of each `path` entry when it was recorded. */\n next: Array<Element | null>;\n /** The previous element sibling of each `path` entry when it was recorded. */\n previous: Array<Element | null>;\n}\n\n/** What is captured about the opener when the surface opens. */\ninterface OpenerRecord {\n element: HTMLElement;\n /** Its place in the document, used when it is removed or can no longer take focus. */\n position: DomPosition;\n /** The anchors (triggers) of the open layers whose tree held it, innermost layer first. */\n anchors: Array<{ element: HTMLElement; position: DomPosition }>;\n}\n\n/** A point in document order: just before `ref`, or just after `ref` and its subtree. */\ninterface DomPoint {\n ref: Element;\n placement: 'before' | 'after';\n}\n\nconst FOLLOWING = 4; // Node.DOCUMENT_POSITION_FOLLOWING\nconst PORTAL_SELECTOR = '[data-wave-portal]';\n\nfunction isValidTarget(el: HTMLElement | null | undefined): el is HTMLElement {\n if (!el || !el.isConnected) return false;\n if (!isFocusable(el)) return false; // also rejects [inert] ancestors, hidden and disabled\n if (el.closest('[aria-hidden=\"true\"]')) return false;\n return !isInsideOtherOpenModal(el);\n}\n\nfunction recordPosition(el: Element): DomPosition {\n const position: DomPosition = { path: [], next: [], previous: [] };\n const body = el.ownerDocument.body;\n for (let node: Element | null = el; node; node = node.parentElement) {\n position.path.push(node);\n position.next.push(node.nextElementSibling);\n position.previous.push(node.previousElementSibling);\n if (node === body) break;\n }\n return position;\n}\n\n/**\n * The anchors of the open layers whose tree contains `opener` (a menu item's menu button),\n * innermost layer first. An opener in an allow-listed region (a toast) belongs to no layer.\n */\nfunction captureAnchors(\n opener: HTMLElement,\n container: HTMLElement | null | undefined,\n): OpenerRecord['anchors'] {\n if (opener.closest(ALLOW_OUTSIDE_SELECTOR)) return [];\n const layers = getOpenLayers()\n .filter((layer) => isInsideLayerTree(layer.id, opener))\n .sort((a, b) => compareLayers(b, a));\n const anchors: OpenerRecord['anchors'] = [];\n for (const layer of layers) {\n const anchor = layer.getAnchor();\n if (!anchor || anchor === opener || (container && container.contains(anchor))) continue;\n if (anchors.some((entry) => entry.element === anchor)) continue;\n anchors.push({ element: anchor, position: recordPosition(anchor) });\n }\n return anchors;\n}\n\n// ---------------------------------------------------------------------------\n// Focus tracker\n// ---------------------------------------------------------------------------\n\n/**\n * Remembers the last focused element, with its place in the document and the anchors of the\n * overlays that held it, recorded while it is still in the document. A surface captures its opener\n * in the mutation phase, and by then React has already deleted anything earlier in the tree that\n * the same commit removes. A popover rendered before a dialog, whose menu item closes the popover\n * and opens the dialog, has lost its menu item (and focus is on `<body>`) when the dialog captures.\n * The record still leads the restore to the popover's trigger. It lives in\n * `getGlobalRegistry('restoreFocusTracker')`, so two copies of the library share one set of\n * listeners.\n */\ninterface FocusTracker {\n /** Mounted `useRestoreFocus` instances: the listeners are installed while there is one. */\n users: number;\n /** The last focused element; `null` once focus was moved away from it on purpose. */\n last: OpenerRecord | null;\n /** Removes the listeners; `null` while none are installed. */\n uninstall: (() => void) | null;\n /**\n * The mounted surfaces, as the other instances see them (see {@link isClosingByHover}). Created\n * on first use: a tracker made by another copy of the library does not have it.\n */\n surfaces?: Set<SurfaceEntry>;\n}\n\n/** A mounted `useRestoreFocus`, as the other instances see it. */\ninterface SurfaceEntry {\n /** Whether the surface is closing by hover (its `isHoverClose`). */\n isHoverClose(): boolean;\n /** The surface element, while there is one. */\n getContainer(): HTMLElement | null;\n /** The element the surface was opened from: its captured opener, else its trigger. */\n getOpener(): HTMLElement | null;\n}\n\nfunction getSurfaceEntries(): Set<SurfaceEntry> {\n const tracker = getFocusTracker();\n tracker.surfaces ??= new Set();\n return tracker.surfaces;\n}\n\n/**\n * Whether the close of `entry` is a hover close: its own, or that of a surface holding the element\n * it was opened from (a submenu in a menu that closes by hover, a hover card inside a hover card,\n * at any depth), which takes it along.\n */\nfunction isClosingByHover(entry: SurfaceEntry, seen = new Set<SurfaceEntry>()): boolean {\n if (seen.has(entry)) return false;\n seen.add(entry);\n if (entry.isHoverClose()) return true;\n const opener = entry.getOpener();\n if (!opener) return false;\n for (const other of getSurfaceEntries()) {\n const container = other === entry ? null : other.getContainer();\n if (container && container.contains(opener) && isClosingByHover(other, seen)) return true;\n }\n return false;\n}\n\n/** Whether this close is a hover close: the surface's own, or that of a surface it was opened from. */\nfunction isHoverCloseOf(entry: SurfaceEntry | null, options: UseRestoreFocusOptions): boolean {\n return entry ? isClosingByHover(entry) : options.isHoverClose?.() === true;\n}\n\nfunction getFocusTracker(): FocusTracker {\n return getGlobalRegistry<FocusTracker>('restoreFocusTracker', () => ({\n users: 0,\n last: null,\n uninstall: null,\n }));\n}\n\nconst ELEMENT_NODE = 1;\n\nfunction isElementTarget(target: EventTarget | null): target is HTMLElement {\n return !!target && (target as Partial<Node>).nodeType === ELEMENT_NODE;\n}\n\nfunction recordFocus(tracker: FocusTracker, el: HTMLElement): void {\n const doc = el.ownerDocument;\n if (el === doc.body || el === doc.documentElement) {\n tracker.last = null;\n return;\n }\n tracker.last = { element: el, position: recordPosition(el), anchors: captureAnchors(el, null) };\n}\n\n/**\n * A layer opened or closed: re-record the focused element's place and overlays while it is still in\n * the document. An element focused as its popover opens (autoFocus) gets focus before the\n * popover's layer registers. Anchors found earlier are kept (a layer unregistering as its content\n * is deleted no longer reports it).\n */\nfunction refreshFocusRecord(tracker: FocusTracker): void {\n const last = tracker.last;\n if (!last || !last.element.isConnected) return;\n const anchors = captureAnchors(last.element, null);\n for (const anchor of last.anchors) {\n if (!anchors.some((entry) => entry.element === anchor.element)) anchors.push(anchor);\n }\n tracker.last = { element: last.element, position: recordPosition(last.element), anchors };\n}\n\n/** Installs the tracker's listeners while at least one `useRestoreFocus` is mounted. */\nfunction retainFocusTracker(): () => void {\n if (typeof document === 'undefined') return () => {};\n const tracker = getFocusTracker();\n tracker.users += 1;\n if (!tracker.uninstall) {\n const doc = document;\n const onFocusIn = (event: FocusEvent) => {\n if (isElementTarget(event.target)) recordFocus(tracker, event.target);\n };\n // Focus leaves for nowhere when the element is removed (some browsers fire focusout then) or\n // when the user presses a non-focusable spot. Decide once the current task has run: an element\n // still in the document that can take focus was left on purpose and is no opener to return to.\n const onFocusOut = (event: FocusEvent) => {\n const target = event.target;\n if (event.relatedTarget || !isElementTarget(target)) return;\n queueMicrotask(() => {\n if (tracker.last?.element !== target) return;\n if (!target.isConnected || !isFocusable(target)) return;\n if (target.ownerDocument.activeElement !== target) tracker.last = null;\n });\n };\n doc.addEventListener('focusin', onFocusIn, true);\n doc.addEventListener('focusout', onFocusOut, true);\n const unsubscribe = subscribeLayers(() => refreshFocusRecord(tracker));\n if (isElementTarget(doc.activeElement)) recordFocus(tracker, doc.activeElement);\n tracker.uninstall = () => {\n doc.removeEventListener('focusin', onFocusIn, true);\n doc.removeEventListener('focusout', onFocusOut, true);\n unsubscribe();\n tracker.last = null;\n };\n }\n let retained = true;\n return () => {\n if (!retained) return;\n retained = false;\n tracker.users = Math.max(0, tracker.users - 1);\n if (tracker.users > 0) return;\n tracker.uninstall?.();\n tracker.uninstall = null;\n };\n}\n\n/**\n * The tracker's record of the element focus was lost from: it no longer has focus and was removed,\n * or can no longer take focus (disabled, hidden, made inert). `null` when focus was moved away from\n * it on purpose, or it still has focus.\n */\nfunction getLostFocus(): OpenerRecord | null {\n const last = getFocusTracker().last;\n if (!last) return null;\n const { element } = last;\n if (element.ownerDocument.activeElement === element) return null;\n if (element.isConnected && isFocusable(element)) return null;\n return last;\n}\n\n/**\n * The element to restore to when the surface opens: the trigger, else the focused element, else —\n * focus already lost to `<body>` — the element the focus tracker saw lose it.\n */\nfunction captureOpener(options: UseRestoreFocusOptions): OpenerRecord | null {\n if (typeof document === 'undefined') return null;\n const { container, triggerRef } = options;\n const isCandidate = (el: Element | null | undefined): el is HTMLElement =>\n !!el &&\n el !== el.ownerDocument.body &&\n el !== el.ownerDocument.documentElement &&\n !(container && container.contains(el));\n const trigger = triggerRef?.current;\n const active = document.activeElement;\n let element: HTMLElement | null = null;\n if (isCandidate(trigger)) element = trigger;\n else if (isCandidate(active)) element = active;\n if (element) {\n return {\n element,\n position: recordPosition(element),\n anchors: captureAnchors(element, container),\n };\n }\n // The opener was removed earlier in this commit (a menu item in a popover that closed as this\n // surface opened), or can no longer take focus: use what the tracker recorded while it could.\n const lost = getLostFocus();\n if (!lost || !isCandidate(lost.element)) return null;\n return {\n element: lost.element,\n position: lost.position,\n anchors: lost.anchors.filter((anchor) => !(container && container.contains(anchor.element))),\n };\n}\n\n/** A layer's surface (or its first tabbable element), for the last-resort fallbacks. */\nfunction getLayerTargets(layer: LayerRecord | null): HTMLElement[] {\n if (!layer) return [];\n const targets: HTMLElement[] = [];\n for (const el of layer.getElements()) {\n if (!el) continue;\n targets.push(el);\n const first = getFirstTabbable(el);\n if (first) targets.push(first);\n }\n return targets;\n}\n\nfunction isAfterPoint(el: Element, point: DomPoint): boolean {\n const { ref, placement } = point;\n if (el === ref) return placement === 'before';\n const follows = (ref.compareDocumentPosition(el) & FOLLOWING) !== 0;\n return placement === 'before' ? follows : follows && !ref.contains(el);\n}\n\n/**\n * Where to look once the recorded element is gone (or cannot take focus): its nearest ancestor\n * still in the document, and the point where the element used to be. `null` when its whole overlay\n * (the portal wrapper) was removed: that spot means nothing on the page.\n */\nfunction resolvePoint(position: DomPosition): { root: Element; point: DomPoint } | null {\n const { path } = position;\n const index = path.findIndex((el) => el.isConnected);\n if (index === -1) return null;\n if (index === 0) {\n const root = path[0].parentElement;\n return root ? { root, point: { ref: path[0], placement: 'after' } } : null;\n }\n if (path.slice(0, index).some((el) => el.matches(PORTAL_SELECTOR))) return null;\n const root = path[index];\n const next = position.next[index - 1];\n if (next && next.parentElement === root) {\n return { root, point: { ref: next, placement: 'before' } };\n }\n const previous = position.previous[index - 1];\n if (previous && previous.parentElement === root) {\n return { root, point: { ref: previous, placement: 'after' } };\n }\n return { root, point: { ref: root, placement: 'before' } };\n}\n\n/**\n * Tabbable elements near a recorded position, nearest first. In the innermost surviving ancestor\n * that holds a valid one: the first after the old spot (where Tab would have gone from there),\n * else the last before it; then the same one level up. The search stops at the element's overlay\n * (its portal wrapper) and never reaches behind an open modal.\n */\nfunction getNearbyTargets(\n position: DomPosition,\n container: HTMLElement | null | undefined,\n): HTMLElement[] {\n const resolved = resolvePoint(position);\n if (!resolved) return [];\n const { root, point } = resolved;\n const body = root.ownerDocument.body;\n const levels: Element[] = [];\n for (let level: Element | null = root; level; level = level.parentElement) {\n if (isInsideOtherOpenModal(level)) break;\n levels.push(level);\n if (level === body || level.matches(PORTAL_SELECTOR)) break;\n }\n if (levels.length === 0) return [];\n const candidates = getTabbableElements(levels[levels.length - 1])\n .filter((el) => !(container && container.contains(el)) && isValidTarget(el))\n .sort((a, b) => ((a.compareDocumentPosition(b) & FOLLOWING) !== 0 ? -1 : 1));\n const targets: HTMLElement[] = [];\n for (const level of levels) {\n const inLevel = candidates.filter((el) => level.contains(el) && !targets.includes(el));\n const after = inLevel.find((el) => isAfterPoint(el, point));\n const before = inLevel.filter((el) => !isAfterPoint(el, point)).pop();\n if (after) targets.push(after);\n if (before) targets.push(before);\n }\n return targets;\n}\n\n/**\n * Whether the restore acts for this close: always while focus is inside the surface; otherwise\n * never for a hover close (`isClosingByHover`, asked only then), and with `onlyIfFocusInside` only\n * when focus was lost to `<body>`.\n */\nfunction shouldRestore(options: UseRestoreFocusOptions, isHoverClose: () => boolean): boolean {\n if (typeof document === 'undefined') return false;\n const active = document.activeElement;\n const onBody = !active || active === document.body || active === document.documentElement;\n if (!onBody && options.container?.contains(active)) return true;\n if (!onBody && options.onlyIfFocusInside) return false;\n return !isHoverClose();\n}\n\n/**\n * Where to go when the opener was removed or can no longer take focus, nearest first: the tabbable\n * element next to where it was, else the trigger of the overlay it was in (a menu item's menu\n * button), else the element next to that trigger.\n */\nfunction* getReplacementTargets(\n opener: OpenerRecord,\n container: HTMLElement | null | undefined,\n): Generator<HTMLElement> {\n yield* getNearbyTargets(opener.position, container);\n for (const anchor of opener.anchors) yield anchor.element;\n for (const anchor of opener.anchors) yield* getNearbyTargets(anchor.position, container);\n}\n\n/** Restore targets in order of preference, computed lazily (the later ones cost more). */\nfunction* restoreCandidates(\n latest: Latest,\n opener: OpenerRecord | null,\n): Generator<HTMLElement | null | undefined> {\n const { options, parentLayerId } = latest;\n yield options.finalFocusRef?.current;\n yield opener?.element;\n yield options.triggerRef?.current;\n yield options.fallback?.();\n const replacements = opener ? getReplacementTargets(opener, options.container) : null;\n const parentLayer = parentLayerId === null ? null : getLayer(parentLayerId);\n const outsideParent: HTMLElement[] = [];\n if (parentLayer) {\n // The surface was rendered inside a layer that stays open (a confirm Dialog in a Drawer): the\n // opener's replacement inside that layer (the next row after a delete) comes before the\n // layer's surface, so where the surface sits in the React tree does not change the result.\n for (const target of replacements ?? []) {\n if (isInsideLayerTree(parentLayer.id, target)) yield target;\n else outsideParent.push(target);\n }\n yield* getLayerTargets(parentLayer);\n yield* outsideParent;\n } else if (replacements) {\n yield* replacements;\n }\n // Still nothing: into the modal that stays open, never onto the inert page behind it.\n yield* getLayerTargets(getTopmostLayer((layer) => layer.kind === 'modal'));\n}\n\nfunction restore(latest: Latest, opener: OpenerRecord | null): void {\n const container = latest.options.container;\n for (const candidate of restoreCandidates(latest, opener)) {\n if (container && candidate && container.contains(candidate)) continue;\n if (isValidTarget(candidate) && focusElement(candidate, { preventScroll: true })) return;\n }\n}\n\n/**\n * Returns focus to where it came from when a surface closes (dialogs, drawers, popovers, menus,\n * the DatePicker calendar, TeachingPopover).\n *\n * - **Capture**: when `enabled` flips to `true`, the opener is captured in an insertion effect —\n * before React applies `autoFocus` inside the new surface — preferring `triggerRef.current` and\n * ignoring `<body>` and elements inside `container`. Its place in the document and the triggers\n * of the overlays it sits in are recorded with it. When focus is already on `<body>` because\n * the focused element was removed earlier in the same commit (a menu item in a popover that\n * closes as the dialog it opens appears, the popover coming first in the tree), a document\n * focus tracker supplies that element with its recorded place and overlay triggers. The tracker\n * runs while any instance of the hook is mounted, and it forgets an element the user moved focus\n * away from on purpose.\n * - **Restore** when `enabled` flips to `false` (layout phase) and when the component unmounts\n * while enabled. The unmount restore runs in a microtask and is cancelled if the same instance\n * mounts again, so React StrictMode's simulated unmount does not pull focus out of a surface\n * that just opened.\n * - **Targets**, first valid wins:\n * 1. `finalFocusRef` → the captured opener → `triggerRef` → `fallback()`.\n * 2. When the opener was removed or cannot take focus, its replacement, nearest first: the\n * tabbable element next to where it was (in the innermost surviving ancestor that holds one,\n * the next one — the next row's action after a delete — else the previous one; then the same\n * one level up), else the trigger of the overlay it was in (a menu item's menu button), else\n * the element next to that trigger. When the surface is rendered inside another open layer\n * (its parent layer, from `DismissLayerContext`: a confirm Dialog in a Drawer's content),\n * only the replacements inside that layer's tree are tried here.\n * 3. The parent layer's surface, then the replacements outside the parent layer.\n * 4. The surface of the modal layer that stays open.\n *\n * So a confirm Dialog rendered in a Drawer's content and one rendered next to the Drawer both\n * return focus to the adjacent row, not to the Drawer's panel. A target is valid when it is\n * connected, focusable, not inside `[inert]` or `[aria-hidden=\"true\"]`, and not cut off behind\n * another open modal layer — so focus never lands on the inert page behind a Drawer that stays\n * open, and is not dropped on `<body>` while a valid target exists. Focus uses `preventScroll`.\n * - `onlyIfFocusInside` (popovers): restores only when focus is inside the surface or was lost to\n * `<body>`.\n * - `isHoverClose`: a close by the hover intent restores only when focus is inside the surface, so\n * a hover close never moves focus from `<body>` or from where the user put it. The same holds for\n * a surface opened from inside one that closes by hover (a submenu, a hover card in a hover\n * card): every mounted instance is known to the others through the focus tracker's record.\n */\nexport function useRestoreFocus(options: UseRestoreFocusOptions): void {\n const parentLayerId = React.useContext(DismissLayerContext);\n const latestRef = useRef<Latest>({ options, parentLayerId });\n const capturedRef = useRef<OpenerRecord | null>(null);\n const insertionEnabledRef = useRef(false);\n const layoutEnabledRef = useRef(false);\n const scheduledRef = useRef<object | null>(null);\n const entryRef = useRef<SurfaceEntry | null>(null);\n const { enabled } = options;\n\n // Track focus while mounted, so an opener removed in the commit that opens the surface is known.\n // And be known to the other instances: a surface closing by hover takes along the surfaces opened\n // from inside it, whose closes are then hover closes too.\n useLayoutEffect(() => {\n const release = retainFocusTracker();\n const entry: SurfaceEntry = {\n isHoverClose: () => latestRef.current.options.isHoverClose?.() === true,\n getContainer: () => latestRef.current.options.container ?? null,\n getOpener: () =>\n capturedRef.current?.element ?? latestRef.current.options.triggerRef?.current ?? null,\n };\n entryRef.current = entry;\n const surfaces = getSurfaceEntries();\n surfaces.add(entry);\n return () => {\n release();\n // Kept to the end of the commit: a surface opened from inside this one, closing along with\n // it, still asks about it.\n queueMicrotask(() => surfaces.delete(entry));\n };\n }, []);\n\n // Mutation phase: record the latest options and capture the opener when `enabled` turns on,\n // before autoFocus (layout phase) or a focus trap's initial focus moves focus into the surface.\n useInsertionEffect(() => {\n latestRef.current = { options, parentLayerId };\n const wasEnabled = insertionEnabledRef.current;\n insertionEnabledRef.current = options.enabled;\n if (options.enabled && !wasEnabled) capturedRef.current = captureOpener(options);\n });\n\n // `enabled` true → false: restore in the layout phase (after every cleanup of this commit, so a\n // modal's isolation is already gone).\n useLayoutEffect(() => {\n const wasEnabled = layoutEnabledRef.current;\n layoutEnabledRef.current = enabled;\n if (!wasEnabled || enabled) return;\n const latest = latestRef.current;\n const captured = capturedRef.current;\n const entry = entryRef.current;\n // Decided before the opener is dropped: a hover close is also recognised through it.\n const acts = shouldRestore(latest.options, () => isHoverCloseOf(entry, latest.options));\n capturedRef.current = null;\n if (acts) restore(latest, captured);\n }, [enabled]);\n\n // Unmount while enabled: restore in a microtask, cancelled by a remount of this instance.\n useLayoutEffect(() => {\n const latest = latestRef;\n const captured = capturedRef;\n const scheduled = scheduledRef;\n const entryHolder = entryRef;\n scheduled.current = null;\n return () => {\n const snapshot = latest.current;\n if (!snapshot.options.enabled) return;\n // Decide now, while the surface is still in the document.\n const entry = entryHolder.current;\n if (!shouldRestore(snapshot.options, () => isHoverCloseOf(entry, snapshot.options))) return;\n const token = {};\n scheduled.current = token;\n const opener = captured.current;\n queueMicrotask(() => {\n if (scheduled.current !== token) return;\n scheduled.current = null;\n const active = typeof document === 'undefined' ? null : document.activeElement;\n const container = snapshot.options.container;\n // Focus placed elsewhere in the meantime (another surface opened) wins.\n if (\n active &&\n active !== document.body &&\n active !== document.documentElement &&\n !(container && container.contains(active))\n ) {\n return;\n }\n restore(snapshot, opener);\n });\n };\n }, []);\n}\n"],"mappings":"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"}
|