@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,271 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { getGlobalRegistry as e } from "../lib/globalRegistry.mjs";
|
|
3
|
+
import { focusElement as t, getFirstTabbable as n, getTabbableElements as r, isFocusable as i } from "../lib/focus.mjs";
|
|
4
|
+
import { compareLayers as a, getLayer as o, getOpenLayers as s, getTopmostLayer as c, isInsideLayerTree as l, isInsideOtherOpenModal as u, subscribeLayers as d } from "../lib/layers.mjs";
|
|
5
|
+
import { DismissLayerContext as f } from "./useDismiss.mjs";
|
|
6
|
+
import * as p from "react";
|
|
7
|
+
import { useInsertionEffect as m, useLayoutEffect as h, useRef as g } from "react";
|
|
8
|
+
//#region src/hooks/useRestoreFocus.ts
|
|
9
|
+
var _ = 4, v = "[data-wave-portal]";
|
|
10
|
+
function y(e) {
|
|
11
|
+
return !e || !e.isConnected || !i(e) || e.closest("[aria-hidden=\"true\"]") ? !1 : !u(e);
|
|
12
|
+
}
|
|
13
|
+
function b(e) {
|
|
14
|
+
let t = {
|
|
15
|
+
path: [],
|
|
16
|
+
next: [],
|
|
17
|
+
previous: []
|
|
18
|
+
}, n = e.ownerDocument.body;
|
|
19
|
+
for (let r = e; r && (t.path.push(r), t.next.push(r.nextElementSibling), t.previous.push(r.previousElementSibling), r !== n); r = r.parentElement);
|
|
20
|
+
return t;
|
|
21
|
+
}
|
|
22
|
+
function x(e, t) {
|
|
23
|
+
if (e.closest("[data-wave-focus-trap-allow]")) return [];
|
|
24
|
+
let n = s().filter((t) => l(t.id, e)).sort((e, t) => a(t, e)), r = [];
|
|
25
|
+
for (let i of n) {
|
|
26
|
+
let n = i.getAnchor();
|
|
27
|
+
!n || n === e || t && t.contains(n) || r.some((e) => e.element === n) || r.push({
|
|
28
|
+
element: n,
|
|
29
|
+
position: b(n)
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return r;
|
|
33
|
+
}
|
|
34
|
+
function S() {
|
|
35
|
+
let e = T();
|
|
36
|
+
return e.surfaces ??= /* @__PURE__ */ new Set(), e.surfaces;
|
|
37
|
+
}
|
|
38
|
+
function C(e, t = /* @__PURE__ */ new Set()) {
|
|
39
|
+
if (t.has(e)) return !1;
|
|
40
|
+
if (t.add(e), e.isHoverClose()) return !0;
|
|
41
|
+
let n = e.getOpener();
|
|
42
|
+
if (!n) return !1;
|
|
43
|
+
for (let r of S()) {
|
|
44
|
+
let i = r === e ? null : r.getContainer();
|
|
45
|
+
if (i && i.contains(n) && C(r, t)) return !0;
|
|
46
|
+
}
|
|
47
|
+
return !1;
|
|
48
|
+
}
|
|
49
|
+
function w(e, t) {
|
|
50
|
+
return e ? C(e) : t.isHoverClose?.() === !0;
|
|
51
|
+
}
|
|
52
|
+
function T() {
|
|
53
|
+
return e("restoreFocusTracker", () => ({
|
|
54
|
+
users: 0,
|
|
55
|
+
last: null,
|
|
56
|
+
uninstall: null
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
var E = 1;
|
|
60
|
+
function D(e) {
|
|
61
|
+
return !!e && e.nodeType === E;
|
|
62
|
+
}
|
|
63
|
+
function O(e, t) {
|
|
64
|
+
let n = t.ownerDocument;
|
|
65
|
+
if (t === n.body || t === n.documentElement) {
|
|
66
|
+
e.last = null;
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
e.last = {
|
|
70
|
+
element: t,
|
|
71
|
+
position: b(t),
|
|
72
|
+
anchors: x(t, null)
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function k(e) {
|
|
76
|
+
let t = e.last;
|
|
77
|
+
if (!t || !t.element.isConnected) return;
|
|
78
|
+
let n = x(t.element, null);
|
|
79
|
+
for (let e of t.anchors) n.some((t) => t.element === e.element) || n.push(e);
|
|
80
|
+
e.last = {
|
|
81
|
+
element: t.element,
|
|
82
|
+
position: b(t.element),
|
|
83
|
+
anchors: n
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function A() {
|
|
87
|
+
if (typeof document > "u") return () => {};
|
|
88
|
+
let e = T();
|
|
89
|
+
if (e.users += 1, !e.uninstall) {
|
|
90
|
+
let t = document, n = (t) => {
|
|
91
|
+
D(t.target) && O(e, t.target);
|
|
92
|
+
}, r = (t) => {
|
|
93
|
+
let n = t.target;
|
|
94
|
+
!t.relatedTarget && D(n) && queueMicrotask(() => {
|
|
95
|
+
e.last?.element === n && n.isConnected && i(n) && n.ownerDocument.activeElement !== n && (e.last = null);
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
t.addEventListener("focusin", n, !0), t.addEventListener("focusout", r, !0);
|
|
99
|
+
let a = d(() => k(e));
|
|
100
|
+
D(t.activeElement) && O(e, t.activeElement), e.uninstall = () => {
|
|
101
|
+
t.removeEventListener("focusin", n, !0), t.removeEventListener("focusout", r, !0), a(), e.last = null;
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
let t = !0;
|
|
105
|
+
return () => {
|
|
106
|
+
t && (t = !1, e.users = Math.max(0, e.users - 1), !(e.users > 0) && (e.uninstall?.(), e.uninstall = null));
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function j() {
|
|
110
|
+
let e = T().last;
|
|
111
|
+
if (!e) return null;
|
|
112
|
+
let { element: t } = e;
|
|
113
|
+
return t.ownerDocument.activeElement === t || t.isConnected && i(t) ? null : e;
|
|
114
|
+
}
|
|
115
|
+
function M(e) {
|
|
116
|
+
if (typeof document > "u") return null;
|
|
117
|
+
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;
|
|
118
|
+
if (r(i) ? o = i : r(a) && (o = a), o) return {
|
|
119
|
+
element: o,
|
|
120
|
+
position: b(o),
|
|
121
|
+
anchors: x(o, t)
|
|
122
|
+
};
|
|
123
|
+
let s = j();
|
|
124
|
+
return !s || !r(s.element) ? null : {
|
|
125
|
+
element: s.element,
|
|
126
|
+
position: s.position,
|
|
127
|
+
anchors: s.anchors.filter((e) => !(t && t.contains(e.element)))
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function N(e) {
|
|
131
|
+
if (!e) return [];
|
|
132
|
+
let t = [];
|
|
133
|
+
for (let r of e.getElements()) {
|
|
134
|
+
if (!r) continue;
|
|
135
|
+
t.push(r);
|
|
136
|
+
let e = n(r);
|
|
137
|
+
e && t.push(e);
|
|
138
|
+
}
|
|
139
|
+
return t;
|
|
140
|
+
}
|
|
141
|
+
function P(e, t) {
|
|
142
|
+
let { ref: n, placement: r } = t;
|
|
143
|
+
if (e === n) return r === "before";
|
|
144
|
+
let i = (n.compareDocumentPosition(e) & _) !== 0;
|
|
145
|
+
return r === "before" ? i : i && !n.contains(e);
|
|
146
|
+
}
|
|
147
|
+
function F(e) {
|
|
148
|
+
let { path: t } = e, n = t.findIndex((e) => e.isConnected);
|
|
149
|
+
if (n === -1) return null;
|
|
150
|
+
if (n === 0) {
|
|
151
|
+
let e = t[0].parentElement;
|
|
152
|
+
return e ? {
|
|
153
|
+
root: e,
|
|
154
|
+
point: {
|
|
155
|
+
ref: t[0],
|
|
156
|
+
placement: "after"
|
|
157
|
+
}
|
|
158
|
+
} : null;
|
|
159
|
+
}
|
|
160
|
+
if (t.slice(0, n).some((e) => e.matches(v))) return null;
|
|
161
|
+
let r = t[n], i = e.next[n - 1];
|
|
162
|
+
if (i && i.parentElement === r) return {
|
|
163
|
+
root: r,
|
|
164
|
+
point: {
|
|
165
|
+
ref: i,
|
|
166
|
+
placement: "before"
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
let a = e.previous[n - 1];
|
|
170
|
+
return a && a.parentElement === r ? {
|
|
171
|
+
root: r,
|
|
172
|
+
point: {
|
|
173
|
+
ref: a,
|
|
174
|
+
placement: "after"
|
|
175
|
+
}
|
|
176
|
+
} : {
|
|
177
|
+
root: r,
|
|
178
|
+
point: {
|
|
179
|
+
ref: r,
|
|
180
|
+
placement: "before"
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function I(e, t) {
|
|
185
|
+
let n = F(e);
|
|
186
|
+
if (!n) return [];
|
|
187
|
+
let { root: i, point: a } = n, o = i.ownerDocument.body, s = [];
|
|
188
|
+
for (let e = i; e && !(u(e) || (s.push(e), e === o || e.matches(v))); e = e.parentElement);
|
|
189
|
+
if (s.length === 0) return [];
|
|
190
|
+
let c = r(s[s.length - 1]).filter((e) => !(t && t.contains(e)) && y(e)).sort((e, t) => (e.compareDocumentPosition(t) & _) === 0 ? 1 : -1), l = [];
|
|
191
|
+
for (let e of s) {
|
|
192
|
+
let t = c.filter((t) => e.contains(t) && !l.includes(t)), n = t.find((e) => P(e, a)), r = t.filter((e) => !P(e, a)).pop();
|
|
193
|
+
n && l.push(n), r && l.push(r);
|
|
194
|
+
}
|
|
195
|
+
return l;
|
|
196
|
+
}
|
|
197
|
+
function L(e, t) {
|
|
198
|
+
if (typeof document > "u") return !1;
|
|
199
|
+
let n = document.activeElement, r = !n || n === document.body || n === document.documentElement;
|
|
200
|
+
return !r && e.container?.contains(n) ? !0 : !r && e.onlyIfFocusInside ? !1 : !t();
|
|
201
|
+
}
|
|
202
|
+
function* R(e, t) {
|
|
203
|
+
yield* I(e.position, t);
|
|
204
|
+
for (let t of e.anchors) yield t.element;
|
|
205
|
+
for (let n of e.anchors) yield* I(n.position, t);
|
|
206
|
+
}
|
|
207
|
+
function* z(e, t) {
|
|
208
|
+
let { options: n, parentLayerId: r } = e;
|
|
209
|
+
yield n.finalFocusRef?.current, yield t?.element, yield n.triggerRef?.current, yield n.fallback?.();
|
|
210
|
+
let i = t ? R(t, n.container) : null, a = r === null ? null : o(r), s = [];
|
|
211
|
+
if (a) {
|
|
212
|
+
for (let e of i ?? []) l(a.id, e) ? yield e : s.push(e);
|
|
213
|
+
yield* N(a), yield* s;
|
|
214
|
+
} else i && (yield* i);
|
|
215
|
+
yield* N(c((e) => e.kind === "modal"));
|
|
216
|
+
}
|
|
217
|
+
function B(e, n) {
|
|
218
|
+
let r = e.options.container;
|
|
219
|
+
for (let i of z(e, n)) if (!(r && i && r.contains(i)) && y(i) && t(i, { preventScroll: !0 })) return;
|
|
220
|
+
}
|
|
221
|
+
function V(e) {
|
|
222
|
+
let t = p.useContext(f), n = g({
|
|
223
|
+
options: e,
|
|
224
|
+
parentLayerId: t
|
|
225
|
+
}), r = g(null), i = g(!1), a = g(!1), o = g(null), s = g(null), { enabled: c } = e;
|
|
226
|
+
h(() => {
|
|
227
|
+
let e = A(), t = {
|
|
228
|
+
isHoverClose: () => n.current.options.isHoverClose?.() === !0,
|
|
229
|
+
getContainer: () => n.current.options.container ?? null,
|
|
230
|
+
getOpener: () => r.current?.element ?? n.current.options.triggerRef?.current ?? null
|
|
231
|
+
};
|
|
232
|
+
s.current = t;
|
|
233
|
+
let i = S();
|
|
234
|
+
return i.add(t), () => {
|
|
235
|
+
e(), queueMicrotask(() => i.delete(t));
|
|
236
|
+
};
|
|
237
|
+
}, []), m(() => {
|
|
238
|
+
n.current = {
|
|
239
|
+
options: e,
|
|
240
|
+
parentLayerId: t
|
|
241
|
+
};
|
|
242
|
+
let a = i.current;
|
|
243
|
+
i.current = e.enabled, e.enabled && !a && (r.current = M(e));
|
|
244
|
+
}), h(() => {
|
|
245
|
+
let e = a.current;
|
|
246
|
+
if (a.current = c, !e || c) return;
|
|
247
|
+
let t = n.current, i = r.current, o = s.current, l = L(t.options, () => w(o, t.options));
|
|
248
|
+
r.current = null, l && B(t, i);
|
|
249
|
+
}, [c]), h(() => {
|
|
250
|
+
let e = n, t = r, i = o, a = s;
|
|
251
|
+
return i.current = null, () => {
|
|
252
|
+
let n = e.current;
|
|
253
|
+
if (!n.options.enabled) return;
|
|
254
|
+
let r = a.current;
|
|
255
|
+
if (!L(n.options, () => w(r, n.options))) return;
|
|
256
|
+
let o = {};
|
|
257
|
+
i.current = o;
|
|
258
|
+
let s = t.current;
|
|
259
|
+
queueMicrotask(() => {
|
|
260
|
+
if (i.current !== o) return;
|
|
261
|
+
i.current = null;
|
|
262
|
+
let e = typeof document > "u" ? null : document.activeElement, t = n.options.container;
|
|
263
|
+
(!e || e === document.body || e === document.documentElement || t && t.contains(e)) && B(n, s);
|
|
264
|
+
});
|
|
265
|
+
};
|
|
266
|
+
}, []);
|
|
267
|
+
}
|
|
268
|
+
//#endregion
|
|
269
|
+
export { V as useRestoreFocus };
|
|
270
|
+
|
|
271
|
+
//# sourceMappingURL=useRestoreFocus.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRestoreFocus.mjs","names":["React","FOLLOWING","PORTAL_SELECTOR","isValidTarget","el","isFocusable","isInsideOtherOpenModal","recordPosition","position","body","node","captureAnchors","opener","layers","getOpenLayers","isInsideLayerTree","layer","compareLayers","b","a","anchors","anchor","container","entry","getSurfaceEntries","tracker","getFocusTracker","isClosingByHover","seen","other","isHoverCloseOf","options","getGlobalRegistry","ELEMENT_NODE","isElementTarget","target","recordFocus","doc","refreshFocusRecord","last","retainFocusTracker","onFocusIn","event","onFocusOut","unsubscribe","subscribeLayers","retained","getLostFocus","element","captureOpener","isCandidate","trigger","triggerRef","active","lost","getLayerTargets","targets","first","getFirstTabbable","isAfterPoint","point","ref","placement","follows","resolvePoint","index","path","root","next","previous","getNearbyTargets","resolved","levels","level","candidates","getTabbableElements","inLevel","after","before","shouldRestore","onBody","isHoverClose","getReplacementTargets","restoreCandidates","latest","replacements","parentLayer","parentLayerId","getLayer","outsideParent","getTopmostLayer","restore","candidate","focusElement","useRestoreFocus","DismissLayerContext","latestRef","useRef","capturedRef","insertionEnabledRef","layoutEnabledRef","scheduledRef","entryRef","useLayoutEffect","release","surfaces","useInsertionEffect","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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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("../lib/dev.cjs"),n=require("../lib/mergeRefs.cjs"),r=require("./useEventCallback.cjs"),i=require("../lib/direction.cjs"),a=require("../lib/focus.cjs"),o=require("./useTypeahead.cjs");let s=require("react");s=e.__toESM(s,1);var c=`[data-roving-value]`,l=new Set([`radiogroup`,`listbox`,`grid`,`treegrid`,`tablist`,`menu`,`menubar`,`tree`,`spinbutton`]),u=new Set([`slider`,`spinbutton`,`textbox`,`searchbox`]),d=new Set([`button`,`checkbox`,`color`,`file`,`hidden`,`image`,`radio`,`reset`,`submit`]),f=[`disabled`,`aria-disabled`,`data-disabled-focusable`,`data-roving-disabled`,`data-roving-value`,`data-roving-container`,`data-roving-transparent`,`tabindex`,`hidden`,`inert`,`role`,`type`,`contenteditable`];function p(e,t){if(e.hasAttribute(`data-roving-container`))return!0;if(!t||e.hasAttribute(`data-roving-transparent`))return!1;let n=e.getAttribute(`role`);return n!==null&&l.has(n)}function m(e,t,n){for(let r=e;r&&r!==t;r=r.parentElement)if(p(r,n))return!0;return!1}function h(e){return e.tabIndex>=0&&!e.hasAttribute(`disabled`)}function g(e){let{element:t}=e;if(!e.nested||h(t))return t;let n=t.querySelector(`[tabindex="0"]`);if(n)return n;let r=a.getFirstTabbable(t);return r instanceof HTMLElement?r:null}function _(e){let t=e.getAttribute(`data-roving-disabled`);return t!==null&&t!==`false`||v(e)?!0:!e.hasAttribute(`data-disabled-focusable`)&&e.getAttribute(`aria-disabled`)===`true`}function v(e){if(e.disabled===!0)return!0;try{return e.matches(`:disabled`)}catch{return!1}}function y(e){if(!e||e.nodeType!==1)return!1;let t=e,n=t.getAttribute(`role`);if(n!==null&&u.has(n))return!0;let r=t.localName;if(r===`textarea`||r===`select`)return!0;if(r===`input`)return!d.has(t.type);let i=t.closest(`[contenteditable]`);return i!==null&&i.getAttribute(`contenteditable`)!==`false`}function b(e){return!e.nested&&!y(e.element)}function x(e,t,n){let r=e.ownerDocument.defaultView;if(!r)return!1;for(let i=e;i&&i!==t;i=i.parentElement){let e=n.get(i);if(e===void 0){let t=i.parentElement;e=r.getComputedStyle(i).display===`none`||t!==null&&t.localName===`details`&&!t.hasAttribute(`open`)&&Array.from(t.children).find(e=>e.localName===`summary`)!==i,n.set(i,e)}if(e)return!0}let{visibility:i}=r.getComputedStyle(e);return i!==`hidden`&&i!==`collapse`?!1:r.getComputedStyle(t).visibility===`visible`}function S(e){let t=e.getRootNode().activeElement;return!!t&&e.contains(t)}function C(e){try{return document.createDocumentFragment().querySelector(e),!0}catch{return!1}}function w(e){return[e.value,e.disabled?0:b(e)?1:2]}function T(e,t,n,r){let i=e.some(([,e])=>e===1)?1:2,a=e.filter(([,e])=>e===i).map(([e])=>e);return n===`last-focused`&&r!==null&&a.includes(r)?r:t!==null&&t!==``&&a.includes(t)?t:a[0]??null}function E(e,t){if(!t)return e;let n=new Map(e.map(e=>[e.value,e])),r=[];for(let e of t){let t=n.get(e);t&&r.push(t)}return r}var ee=class{container=null;lastFocused=null;options={itemSelector:c,manageTabIndex:!1,items:void 0,activeValue:null,tabStop:`active`,roleComposites:!0};stamped=new WeakMap;autoValues=new WeakMap;autoCounter=0;notify=null;observer=null;dirty=!0;snapshot=``;subscribe=e=>(this.notify=e,this.observe(),()=>{this.notify=null,this.disconnect()});getSnapshot=()=>this.container?(this.dirty&&(this.dirty=!1,this.snapshot=JSON.stringify(this.resolveOwn().map(w))),this.snapshot):``;getServerSnapshot=()=>``;setContainer(e){e!==this.container&&(this.disconnect(),this.container=e,this.dirty=!0,this.notify&&(this.observe(),this.notify()))}recordFocus(e){b(e)&&(this.lastFocused=e.value)}setOptions(e){let t=this.options;this.options=e,(t.itemSelector!==e.itemSelector||t.manageTabIndex!==e.manageTabIndex||t.roleComposites!==e.roleComposites)&&(this.dirty=!0,this.notify?.())}resolve(e=this.container){return E(this.resolveOwn(e),this.options.items)}resolveOwn(e=this.container){if(!e)return[];let{itemSelector:t,manageTabIndex:n,roleComposites:r}=this.options,i;try{i=Array.from(e.querySelectorAll(t))}catch{return[]}let o=[],s=new Set,c=new Map;for(let t of i){let i=null,l=!1;for(let n=t;n&&n!==e;n=n.parentElement)p(n,r)&&(i=n),(n.hidden||n.hasAttribute(`inert`))&&(l=!0);if(l)continue;let u=i??t;if(s.has(u))continue;let d=i!==null;if(!d&&n&&(t.getAttribute(`tabindex`)===`-1`&&!this.stamped.has(t)||a.isHiddenInput(t)))continue;s.add(u);let f={value:this.valueOf(u,d),element:u,nested:d,disabled:_(u)};d&&!f.disabled&&!g(f)&&(f.disabled=!0),n&&!f.disabled&&x(u,e,c)&&(f.disabled=!0),o.push(f)}return o}stamp(){if(!this.options.manageTabIndex||!this.container)return;this.release(this.container);let e=this.resolve(),t=T(e.map(w),this.options.activeValue,this.options.tabStop,this.lastFocused);for(let n of e){if(n.nested)continue;let{element:e}=n,r=this.stamped.get(e);r||(r={tabIndex:e.getAttribute(`tabindex`),addedValue:!e.hasAttribute(`data-roving-value`)},this.stamped.set(e,r));let i=n.value===t?`0`:`-1`;e.getAttribute(`tabindex`)!==i&&e.setAttribute(`tabindex`,i),e.hasAttribute(`data-roving-value`)||e.setAttribute(`data-roving-value`,n.value)}}release(e){let t;try{t=Array.from(e.querySelectorAll(this.options.itemSelector))}catch{return}for(let n of t){let t=this.stamped.get(n);t&&m(n,e,this.options.roleComposites)&&(this.stamped.delete(n),t.tabIndex===null?n.removeAttribute(`tabindex`):n.setAttribute(`tabindex`,t.tabIndex),t.addedValue&&n.removeAttribute(`data-roving-value`))}}valueOf(e,t){let n=t?null:e.getAttribute(`data-roving-value`);if(n!==null)return n;let r=this.autoValues.get(e);return r===void 0&&(this.autoCounter+=1,r=`auto-${this.autoCounter}`,this.autoValues.set(e,r)),r}observe(){this.container&&!this.observer&&typeof MutationObserver<`u`&&(this.observer=new MutationObserver(()=>{this.stamp(),this.dirty=!0,this.notify?.()}),this.observer.observe(this.container,{subtree:!0,childList:!0,attributes:!0,attributeFilter:f}),this.dirty=!0)}disconnect(){this.observer?.disconnect(),this.observer=null}};function D(e){if(e===``)return null;try{return JSON.parse(e)}catch{return null}}function O(e){return e.getAttribute(`data-roving-text`)??e.textContent??``}function k(e,t){return!t||typeof t.nodeType!=`number`?!1:t===e||e.contains(t)}function A(e,t,n){if(e.length===0||!t||typeof t.nodeType!=`number`)return null;let r=new Map(e.map(e=>[e.element,e]));for(let e=t;e&&e!==n;e=e.parentNode){let t=r.get(e);if(t)return t}return null}function j(e,t,n){return e?t===g(e):t===n}function M(e,a){let l=a===void 0?void 0:e,{activeValue:u=null,items:d,orientation:f=`horizontal`,loop:p=!0,dir:m,itemSelector:h=c,typeahead:_=!1,homeEndKeys:v=!0,tabStop:x=`active`,manageTabIndex:w=!1,onFocusMove:E}=a??e,[M]=s.useState(()=>new ee),N=s.useSyncExternalStore(M.subscribe,M.getSnapshot,M.getServerSnapshot),[P,F]=s.useState(null),[I,L]=s.useState(null),R=l===void 0&&d===void 0;s.useLayoutEffect(()=>{M.setOptions({itemSelector:h,manageTabIndex:w,items:d,activeValue:u,tabStop:x,roleComposites:R}),l&&M.setContainer(l.current),M.stamp()}),s.useEffect(()=>{t.isDev&&!C(h)&&t.warnOnce(`useRovingTabIndex:itemSelector:${h}`,`useRovingTabIndex: itemSelector "${h}" is not a valid CSS selector in this browser; no item is navigable or tabbable.`)},[h]);let z=s.useMemo(()=>D(N),[N]),B=s.useMemo(()=>{if(!d)return z;if(z){let e=new Map(z),t=d.flatMap(t=>{let n=e.get(t);return n===void 0?[]:[[t,n]]});if(t.length>0)return t}return d.map(e=>[e,1])},[d,z]),V=B?T(B,u,x,I):u||null,H=s.useCallback(e=>e===V?0:-1,[V]),U=s.useCallback(e=>{M.setContainer(e),l&&n.setRef(l,e)},[M,l]),W=s.useRef([]),G=s.useRef([]),{onTypeahead:K,isSearching:q}=o.useTypeahead({getItems:()=>W.current,onMatch:(e,t)=>{G.current=t}}),J=e=>{if(!e||e.disabled)return!1;let t=g(e);return!t||(t.focus(),!S(t))?!1:(M.recordFocus(e),!0)},Y=e=>{for(let t of e)if(J(t))return},X=r.useEventCallback((e,t)=>{let n=e.metaKey||(e.altKey||e.ctrlKey)&&!o.isAltGraphCharacter(e);if(e.defaultPrevented||n||y(e.target))return;let r=M.container??e.currentTarget;if(!k(r,e.target))return;let a=M.resolve(r),s=a.filter(e=>!e.disabled);if(s.length===0)return;let c=A(a,e.target,r),l=!1,u=[],d=t?null:i.getArrowIntent(e.key,{orientation:f,dir:m??i.getDirection(e.currentTarget)});if(d){if(l=!0,!c)u=d===`next`?s:[...s].reverse();else{let e=d===`next`?1:-1,t=a.length,n=a.indexOf(c);for(let r=1;r<t;r++){if(n+=e,n<0||n>=t){if(!p)break;n=(n+t)%t}a[n].disabled||u.push(a[n])}}}else!t&&v&&(e.key===`Home`||e.key===`End`)?(l=!0,u=e.key===`Home`?s:[...s].reverse()):_&&j(c,e.target,r)&&(W.current=a.map(e=>({value:e.value,text:O(e.element),disabled:e.disabled})),G.current=[],K(e,c?.value??null)&&(l=!0,u=G.current.flatMap(e=>s.filter(t=>t.value===e))));if(l){e.preventDefault();for(let t of u){if(t===c)return;if(J(t)){E?.(t.value,e);return}}}}),Z=r.useEventCallback(e=>X(e,!1)),Q=r.useEventCallback(e=>{_&&e.key===` `&&q()&&X(e,!0)}),$=r.useEventCallback(e=>{let t=M.container??e.currentTarget;if(!k(t,e.target))return;let n=A(M.resolve(t),e.target,t);n&&(M.recordFocus(n),F(n.value),b(n)&&L(n.value),M.stamp())}),te=r.useEventCallback(e=>{J(M.resolve().find(t=>t.value===e))}),ne=r.useEventCallback(()=>{Y(M.resolve().filter(e=>!e.disabled))}),re=r.useEventCallback(()=>{Y(M.resolve().filter(e=>!e.disabled).reverse())});return{containerProps:s.useMemo(()=>({ref:U,"data-roving-container":``,onKeyDown:Z,onKeyDownCapture:Q,onFocus:$}),[U,Z,Q,$]),handleKeyDown:Z,handleKeyDownCapture:Q,handleFocus:$,getTabIndex:H,focusedValue:P,focusValue:te,focusFirst:ne,focusLast:re}}exports.useRovingTabIndex=M;
|
|
2
|
+
//# sourceMappingURL=useRovingTabIndex.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRovingTabIndex.cjs","names":["getFirstTabbable","isHiddenInput","React","isDev","useTypeahead","useEventCallback","isAltGraphCharacter","getArrowIntent","getDirection","require_runtime","require_dev","require_mergeRefs","require_useEventCallback","require_direction","require_focus","require_useTypeahead","react","DEFAULT_ITEM_SELECTOR","COMPOSITE_ROLES","ARROW_KEY_OWNER_ROLES","NON_TEXT_INPUT_TYPES","OBSERVED_ATTRIBUTES","isNestedComposite","el","roleComposites","role","isInNestedComposite","node","container","isFocusableSelf","getFocusTarget","item","element","ownStop","tabbable","isDisabledElement","marker","isNativelyDisabled","ownsArrowKeys","target","tag","editable","canHoldTabStop","isHiddenByCss","view","hidden","cache","parent","child","visibility","hasFocus","active","isValidSelector","selector","toEntry","resolveTabStop","rank","entries","r","values","value","tabStop","lastFocused","activeValue","orderByItems","items","resolved","byValue","ordered","RovingStore","notify","previous","options","candidates","itemSelector","result","seen","cssHidden","candidate","composite","nested","manageTabIndex","stop","original","tabIndex","own","generated","parseSnapshot","snapshot","textOf","isInContainer","findOwningItem","byElement","startsOnItem","useRovingTabIndex","legacyRef","maybeOptions","refOrOptions","store","focusedValue","setFocusedValue","focusedStop","setFocusedStop","domItems","stopEntries","ranks","present","tabStopValue","getTabIndex","containerRef","typeaheadItemsRef","typeaheadMatchesRef","matches","focusItem","focusFirstOf","handleKeys","shortcut","enabled","current","handled","targets","intent","spaceOnly","dir","step","count","index","i","loop","homeEndKeys","typeahead","onTypeahead","next","onFocusMove","handleKeyDown","handleKeyDownCapture","isSearching","handleFocus","focusValue","focusFirst","focusLast"],"sources":["../../src/hooks/useRovingTabIndex.ts"],"sourcesContent":["import * as React from 'react';\nimport type { WaveDir } from '../components/provider/WaveProvider';\nimport { isDev, warnOnce } from '../lib/dev';\nimport { getArrowIntent, getDirection } from '../lib/direction';\nimport { getFirstTabbable, isHiddenInput } from '../lib/focus';\nimport { setRef } from '../lib/mergeRefs';\nimport { useEventCallback } from './useEventCallback';\nimport { isAltGraphCharacter, useTypeahead, type TypeaheadItem } from './useTypeahead';\n\n/**\n * Configuration options for the {@link useRovingTabIndex} hook. Disabled items are skipped; items\n * marked `data-disabled-focusable` (the `disabledFocusable` prop of WaveUI buttons, links and\n * choice controls) stay reachable and may hold the tab stop: APG allows focusable disabled items.\n */\nexport interface UseRovingTabIndexOptions {\n /**\n * The selected value. It may be absent, `''` or `null` (nothing selected) and does not have to be\n * one of the items.\n */\n activeValue?: string | null;\n /**\n * Explicit item order (0.4 call shape). Omitted ⇒ the DOM order of the elements matching\n * `itemSelector`. Disabled items are skipped either way, and so are listed values with no\n * element in the container (not rendered, or `hidden`/`inert`): they never hold the tab stop.\n */\n items?: readonly string[];\n /**\n * Arrow key axis: `'horizontal'` uses Left/Right (mirrored in RTL), `'vertical'` uses Up/Down,\n * `'both'` uses all four.\n * @default 'horizontal'\n */\n orientation?: 'horizontal' | 'vertical' | 'both';\n /**\n * Whether arrow keys wrap around at the ends.\n * @default true\n */\n loop?: boolean;\n /** Text direction. Defaults to the direction of the container at key time (`getDirection`). */\n dir?: WaveDir;\n /**\n * Selector for the item elements inside the container. A selector the browser rejects matches\n * nothing (no item is navigable or tabbable) and logs a development warning.\n * @default '[data-roving-value]'\n */\n itemSelector?: string;\n /**\n * Printable characters move focus to the next item whose text (`data-roving-text`, else its\n * text content) starts with them. A Space typed within 500 ms of another character continues\n * the search instead of activating the focused item: `containerProps.onKeyDownCapture` calls\n * `preventDefault()` on it before an item's own keydown handler runs, so that handler must skip\n * default-prevented events (`composeEventHandlers` does). Keys typed in content nested inside an\n * item (a row's action button) are not typeahead. A character typed with AltGr (which Windows\n * reports as Ctrl+Alt, e.g. Polish `ł`) is typeahead text; other Ctrl, Alt or Meta\n * combinations, Ctrl+Alt+Space included, are shortcuts and ignored. A match whose `focus()`\n * leaves focus where it was is passed over for the next item that matches.\n * @default false\n */\n typeahead?: boolean;\n /**\n * Whether Home/End move to the first/last enabled item.\n * @default true\n */\n homeEndKeys?: boolean;\n /** Which item holds the tab stop. 'active' (default): the enabled activeValue item, else the first\n * enabled item — APG Tabs/Radio/Listbox/Tree. 'last-focused': the last focused enabled item, else\n * 'active' — APG Toolbar (and the static Menu). Either way a nested composite or a control that\n * uses the arrow keys itself (text field, select, slider, spin button, editable combobox) holds\n * it only when no other item can: arrows pressed there never lead back to the other items, so\n * focusing one keeps the tab stop on the last focused other item. */\n tabStop?: 'active' | 'last-focused';\n /** true ⇒ the hook writes tabIndex 0/-1 onto item elements itself and assigns\n * data-roving-value=\"auto-<n>\" to items that lack one. For containers that do not render their\n * items (Toolbar children, Menu items, Tree rows). Default false (items call getTabIndex).\n * Matches that cannot take focus are no items: `input[type=hidden]` is skipped, and a control\n * hidden by CSS inside the container (`display: none` or `visibility: hidden` on it or on an\n * ancestor inside the container) is treated as disabled (skipped, never the tab stop, stamped\n * -1). A container hidden as a whole from outside keeps its items and tab stop. */\n manageTabIndex?: boolean;\n /** Called after an arrow, Home/End or typeahead key moved focus to `value`. */\n onFocusMove?: (value: string, event: React.KeyboardEvent) => void;\n}\n\n/** Props to spread onto the container element. */\nexport interface RovingContainerProps {\n ref: React.RefCallback<HTMLElement>;\n 'data-roving-container': '';\n onKeyDown: React.KeyboardEventHandler;\n /** With `typeahead`: default-prevents a Space that continues a search, before item handlers. */\n onKeyDownCapture: React.KeyboardEventHandler;\n onFocus: React.FocusEventHandler;\n}\n\n/** Result of {@link useRovingTabIndex}. */\nexport interface UseRovingTabIndexResult {\n /** Spread onto the container: ref, `data-roving-container` marker and the key/focus handlers. */\n containerProps: RovingContainerProps;\n /** The container's keydown handler (same function as `containerProps.onKeyDown`). */\n handleKeyDown: (e: React.KeyboardEvent) => void;\n /**\n * The container's capture-phase keydown handler (same function as\n * `containerProps.onKeyDownCapture`). With `typeahead`, it extends the search with a Space that\n * continues one and calls `preventDefault()`, before an item's own keydown handler runs: an item\n * that activates on Space must skip default-prevented events (`composeEventHandlers` does).\n */\n handleKeyDownCapture: (e: React.KeyboardEvent) => void;\n /** The container's focus handler (same function as `containerProps.onFocus`). */\n handleFocus: (e: React.FocusEvent) => void;\n /** `0` for the item that holds the tab stop, `-1` for every other item. */\n getTabIndex: (value: string) => 0 | -1;\n /** The value of the item that last received focus, or `null`. */\n focusedValue: string | null;\n /** Focuses the item with this value (ignored when it is disabled or unknown). */\n focusValue: (value: string) => void;\n /** Focuses the first enabled item. */\n focusFirst: () => void;\n /** Focuses the last enabled item. */\n focusLast: () => void;\n}\n\ninterface ResolvedItem {\n value: string;\n /** The item element (for a nested composite: its root). */\n element: HTMLElement;\n /** A nested composite (own roving container or composite role) counts as one item. */\n nested: boolean;\n /**\n * Skipped by the keys and never the tab stop: disabled, a nested composite with nothing to\n * focus, or (`manageTabIndex`) hidden by CSS.\n */\n disabled: boolean;\n}\n\ninterface StoreOptions {\n itemSelector: string;\n manageTabIndex: boolean;\n items: readonly string[] | undefined;\n activeValue: string | null;\n tabStop: 'active' | 'last-focused';\n /**\n * Whether an element with a composite role but no roving container of its own is a nested\n * composite (one item). Off in the 0.4 call shape and with explicit `items`, where such an element\n * is usually the widget's own root inside a wrapper that carries the container ref.\n */\n roleComposites: boolean;\n}\n\nconst DEFAULT_ITEM_SELECTOR = '[data-roving-value]';\n\n/** Roles of widgets that manage their own children: an element with one of them is one item. */\nconst COMPOSITE_ROLES = new Set([\n 'radiogroup',\n 'listbox',\n 'grid',\n 'treegrid',\n 'tablist',\n 'menu',\n 'menubar',\n 'tree',\n 'spinbutton',\n]);\n\n/**\n * Roles whose widgets use the arrow keys themselves. A combobox does only when it is editable (an\n * `<input>` or contenteditable, caught by the native checks): a select-only combobox such as\n * Dropdown's `<button role=\"combobox\">` uses Up/Down, Home and End, never Left/Right.\n */\nconst ARROW_KEY_OWNER_ROLES = new Set(['slider', 'spinbutton', 'textbox', 'searchbox']);\n\n/** `<input>` types that do not use the arrow keys for text editing. */\nconst NON_TEXT_INPUT_TYPES = new Set([\n 'button',\n 'checkbox',\n 'color',\n 'file',\n 'hidden',\n 'image',\n 'radio',\n 'reset',\n 'submit',\n]);\n\nconst OBSERVED_ATTRIBUTES = [\n 'disabled',\n 'aria-disabled',\n 'data-disabled-focusable',\n 'data-roving-disabled',\n 'data-roving-value',\n 'data-roving-container',\n 'data-roving-transparent',\n 'tabindex',\n 'hidden',\n 'inert',\n 'role',\n // Whether an item uses the arrow keys itself (text input types, contenteditable).\n 'type',\n 'contenteditable',\n];\n\n/**\n * Whether `el` is a nested composite: it has its own roving container, or (with `roleComposites`)\n * a composite role. An element marked `data-roving-transparent` is never one by its role (a\n * `role=\"radiogroup\"` whose radios are items of the enclosing container, `Toolbar.RadioGroup`);\n * its own `data-roving-container` still makes it one.\n */\nfunction isNestedComposite(el: Element, roleComposites: boolean): boolean {\n if (el.hasAttribute('data-roving-container')) return true;\n if (!roleComposites || el.hasAttribute('data-roving-transparent')) return false;\n const role = el.getAttribute('role');\n return role !== null && COMPOSITE_ROLES.has(role);\n}\n\n/** Whether `el` is a nested composite or inside one, below `container`. */\nfunction isInNestedComposite(el: Element, container: Element, roleComposites: boolean): boolean {\n for (let node: Element | null = el; node && node !== container; node = node.parentElement) {\n if (isNestedComposite(node, roleComposites)) return true;\n }\n return false;\n}\n\n/** What an element looked like before the hook stamped it, to hand it back unchanged. */\ninterface StampedOriginal {\n /**\n * The author's own `tabindex` attribute, or `null`, read at the first stamp. A `tabIndex` the\n * author renders differently while the element is stamped is not seen (the stamps overwrite it),\n * so the hand-back restores the first value.\n */\n tabIndex: string | null;\n /** Whether the hook added the element's `data-roving-value`. */\n addedValue: boolean;\n}\n\nfunction isFocusableSelf(el: HTMLElement): boolean {\n return el.tabIndex >= 0 && !el.hasAttribute('disabled');\n}\n\n/** The element to focus for an item: the item itself, or a nested composite's own tab stop. */\nfunction getFocusTarget(item: ResolvedItem): HTMLElement | null {\n const { element } = item;\n if (!item.nested || isFocusableSelf(element)) return element;\n const ownStop = element.querySelector<HTMLElement>('[tabindex=\"0\"]');\n if (ownStop) return ownStop;\n const tabbable = getFirstTabbable(element);\n return tabbable instanceof HTMLElement ? tabbable : null;\n}\n\n/**\n * Whether the keys skip an item, in this order: the composite's own `data-roving-disabled` marker\n * (not `\"false\"`) and native `disabled` skip it; `data-disabled-focusable` keeps it (a\n * `disabledFocusable` control: APG allows focusable disabled items); `aria-disabled=\"true\"` skips\n * it.\n */\nfunction isDisabledElement(el: HTMLElement): boolean {\n const marker = el.getAttribute('data-roving-disabled');\n if (marker !== null && marker !== 'false') return true;\n if (isNativelyDisabled(el)) return true;\n if (el.hasAttribute('data-disabled-focusable')) return false;\n return el.getAttribute('aria-disabled') === 'true';\n}\n\nfunction isNativelyDisabled(el: HTMLElement): boolean {\n if ((el as { disabled?: unknown }).disabled === true) return true;\n try {\n return el.matches(':disabled');\n } catch {\n return false;\n }\n}\n\n/** Text-entry fields and widgets that use the arrow keys themselves (APG Toolbar). */\nfunction ownsArrowKeys(target: EventTarget | null): boolean {\n if (!target || (target as Node).nodeType !== 1) return false;\n const el = target as HTMLElement;\n const role = el.getAttribute('role');\n if (role !== null && ARROW_KEY_OWNER_ROLES.has(role)) return true;\n const tag = el.localName;\n if (tag === 'textarea' || tag === 'select') return true;\n if (tag === 'input') return !NON_TEXT_INPUT_TYPES.has((el as HTMLInputElement).type);\n const editable = el.closest('[contenteditable]');\n return editable !== null && editable.getAttribute('contenteditable') !== 'false';\n}\n\n/**\n * Whether an item can hold the container's tab stop: not a nested composite (it keeps a tab stop\n * of its own) and not a control that uses the arrow keys itself. From either, the arrow keys never\n * lead to the other items, so a tab stop there would leave them reachable by keyboard only through\n * it (or not at all).\n */\nfunction canHoldTabStop(item: ResolvedItem): boolean {\n return !item.nested && !ownsArrowKeys(item.element);\n}\n\n/**\n * Whether CSS inside `container` keeps `el` from taking focus (browsers ignore `focus()` on it):\n * `display: none` on it or on an ancestor inside `container`, `visibility: hidden`/`collapse` set\n * inside `container`, or a place inside a closed `<details>` other than its summary. Hiding from\n * outside the container (a surface that stays invisible until it is positioned, a consumer panel)\n * hides the whole item set and does not count: showing it again changes nothing the hook observes,\n * so nothing would re-stamp. `cache` holds, for one resolution, whether an element hides its whole\n * subtree (the `display` and `<details>` checks).\n */\nfunction isHiddenByCss(el: Element, container: Element, cache: Map<Element, boolean>): boolean {\n const view = el.ownerDocument.defaultView;\n if (!view) return false;\n for (let node: Element | null = el; node && node !== container; node = node.parentElement) {\n let hidden = cache.get(node);\n if (hidden === undefined) {\n const parent = node.parentElement;\n hidden =\n view.getComputedStyle(node).display === 'none' ||\n (parent !== null &&\n parent.localName === 'details' &&\n !parent.hasAttribute('open') &&\n Array.from(parent.children).find((child) => child.localName === 'summary') !== node);\n cache.set(node, hidden);\n }\n if (hidden) return true;\n }\n const { visibility } = view.getComputedStyle(el);\n if (visibility !== 'hidden' && visibility !== 'collapse') return false;\n // Visibility is inherited, so `el` also reads hidden when an ancestor of the container hides the\n // whole container. It counts only when the container itself is visible, i.e. when the hiding is\n // set inside it (on `el` or on a wrapper between them).\n return view.getComputedStyle(container).visibility === 'visible';\n}\n\n/** Whether focus is on `el` or inside it (in its document or shadow root). */\nfunction hasFocus(el: HTMLElement): boolean {\n const active = (el.getRootNode() as Node & { activeElement?: Element | null }).activeElement;\n return !!active && el.contains(active);\n}\n\nfunction isValidSelector(selector: string): boolean {\n try {\n document.createDocumentFragment().querySelector(selector);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * How an item takes part in the tab stop: `0` never (disabled), `1` can hold it, `2` holds it only\n * when no item can (a nested composite, or a control that uses the arrow keys itself).\n */\ntype TabStopRank = 0 | 1 | 2;\n\n/** One item of the published DOM snapshot, and the input of {@link resolveTabStop}. */\ntype SnapshotEntry = [value: string, rank: TabStopRank];\n\nfunction toEntry(item: ResolvedItem): SnapshotEntry {\n return [item.value, item.disabled ? 0 : canHoldTabStop(item) ? 1 : 2];\n}\n\n/**\n * The value that holds the tab stop, among the items of the best rank present (`1`, else `2`):\n * with 'last-focused' the last focused one, else the `activeValue` item, else the first one.\n */\nfunction resolveTabStop(\n entries: readonly SnapshotEntry[],\n activeValue: string | null,\n tabStop: 'active' | 'last-focused',\n lastFocused: string | null,\n): string | null {\n const rank = entries.some(([, r]) => r === 1) ? 1 : 2;\n const values = entries.filter(([, r]) => r === rank).map(([value]) => value);\n if (tabStop === 'last-focused' && lastFocused !== null && values.includes(lastFocused)) {\n return lastFocused;\n }\n if (activeValue !== null && activeValue !== '' && values.includes(activeValue)) {\n return activeValue;\n }\n return values[0] ?? null;\n}\n\nfunction orderByItems(\n resolved: ResolvedItem[],\n items: readonly string[] | undefined,\n): ResolvedItem[] {\n if (!items) return resolved;\n const byValue = new Map(resolved.map((item) => [item.value, item]));\n const ordered: ResolvedItem[] = [];\n for (const value of items) {\n const item = byValue.get(value);\n if (item) ordered.push(item);\n }\n return ordered;\n}\n\n/**\n * Per-hook store: resolves items from the DOM, publishes the enabled set to React through\n * `useSyncExternalStore` (a MutationObserver on the container notifies it), and stamps tabIndex in\n * `manageTabIndex` mode.\n */\nclass RovingStore {\n container: HTMLElement | null = null;\n lastFocused: string | null = null;\n options: StoreOptions = {\n itemSelector: DEFAULT_ITEM_SELECTOR,\n manageTabIndex: false,\n items: undefined,\n activeValue: null,\n tabStop: 'active',\n roleComposites: true,\n };\n\n private readonly stamped = new WeakMap<Element, StampedOriginal>();\n private readonly autoValues = new WeakMap<Element, string>();\n private autoCounter = 0;\n private notify: (() => void) | null = null;\n private observer: MutationObserver | null = null;\n private dirty = true;\n private snapshot = '';\n\n subscribe = (notify: () => void): (() => void) => {\n this.notify = notify;\n this.observe();\n return () => {\n this.notify = null;\n this.disconnect();\n };\n };\n\n getSnapshot = (): string => {\n if (!this.container) return '';\n if (this.dirty) {\n this.dirty = false;\n // DOM facts only (order and tab stop rank); `items` is applied during render.\n this.snapshot = JSON.stringify(this.resolveOwn().map(toEntry));\n }\n return this.snapshot;\n };\n\n getServerSnapshot = (): string => '';\n\n setContainer(container: HTMLElement | null): void {\n if (container === this.container) return;\n this.disconnect();\n this.container = container;\n this.dirty = true;\n if (this.notify) {\n this.observe();\n this.notify();\n }\n }\n\n /**\n * Records a focused item for the 'last-focused' tab stop. An item that cannot hold the tab stop\n * (a nested composite, a control that uses the arrow keys itself) leaves the last one in place.\n */\n recordFocus(item: ResolvedItem): void {\n if (canHoldTabStop(item)) this.lastFocused = item.value;\n }\n\n setOptions(options: StoreOptions): void {\n const previous = this.options;\n this.options = options;\n if (\n previous.itemSelector !== options.itemSelector ||\n previous.manageTabIndex !== options.manageTabIndex ||\n previous.roleComposites !== options.roleComposites\n ) {\n this.dirty = true;\n this.notify?.();\n }\n }\n\n /** Own items in navigation order: the explicit `items` order when given, else DOM order. */\n resolve(container: HTMLElement | null = this.container): ResolvedItem[] {\n return orderByItems(this.resolveOwn(container), this.options.items);\n }\n\n /** Own items of the container in DOM order (items of nested composites excluded). */\n resolveOwn(container: HTMLElement | null = this.container): ResolvedItem[] {\n if (!container) return [];\n const { itemSelector, manageTabIndex, roleComposites } = this.options;\n let candidates: HTMLElement[];\n try {\n candidates = Array.from(container.querySelectorAll<HTMLElement>(itemSelector));\n } catch {\n // An invalid selector (warned from an effect in development): this runs during render\n // (getSnapshot), where throwing would take the whole tree down.\n return [];\n }\n\n const result: ResolvedItem[] = [];\n const seen = new Set<Element>();\n const cssHidden = new Map<Element, boolean>();\n for (const candidate of candidates) {\n let composite: HTMLElement | null = null;\n let hidden = false;\n for (\n let node: HTMLElement | null = candidate;\n node && node !== container;\n node = node.parentElement\n ) {\n if (isNestedComposite(node, roleComposites)) composite = node;\n if (node.hidden || node.hasAttribute('inert')) hidden = true;\n }\n if (hidden) continue;\n\n const element = composite ?? candidate;\n if (seen.has(element)) continue;\n const nested = composite !== null;\n if (!nested && manageTabIndex) {\n // An author tabindex=\"-1\" (a SpinButton stepper, SplitButton internals) opts out.\n if (candidate.getAttribute('tabindex') === '-1' && !this.stamped.has(candidate)) continue;\n // A hidden form input (HiddenInput's `type=\"hidden\"`) is never focusable.\n if (isHiddenInput(candidate)) continue;\n }\n seen.add(element);\n\n const item: ResolvedItem = {\n value: this.valueOf(element, nested),\n element,\n nested,\n disabled: isDisabledElement(element),\n };\n if (nested && !item.disabled && !getFocusTarget(item)) item.disabled = true;\n // Consumer children hidden by CSS (a responsive `hidden md:inline-flex` control). Treated as\n // disabled rather than dropped, so it is stamped -1 and is no extra Tab stop once the CSS\n // shows it again (a CSS change triggers no mutation, hence no re-stamp).\n if (manageTabIndex && !item.disabled && isHiddenByCss(element, container, cssHidden)) {\n item.disabled = true;\n }\n result.push(item);\n }\n return result;\n }\n\n /**\n * manageTabIndex: writes tabIndex 0 on the tab stop and -1 on every other own item. An element\n * it stamped that now belongs to a nested composite (a `data-roving-transparent` marker removed)\n * gets its own `tabindex` back, and loses the `data-roving-value` the hook added.\n */\n stamp(): void {\n if (!this.options.manageTabIndex || !this.container) return;\n this.release(this.container);\n const resolved = this.resolve();\n const stop = resolveTabStop(\n resolved.map(toEntry),\n this.options.activeValue,\n this.options.tabStop,\n this.lastFocused,\n );\n for (const item of resolved) {\n if (item.nested) continue;\n const { element } = item;\n let original = this.stamped.get(element);\n if (!original) {\n original = {\n tabIndex: element.getAttribute('tabindex'),\n addedValue: !element.hasAttribute('data-roving-value'),\n };\n this.stamped.set(element, original);\n }\n const tabIndex = item.value === stop ? '0' : '-1';\n if (element.getAttribute('tabindex') !== tabIndex) element.setAttribute('tabindex', tabIndex);\n if (!element.hasAttribute('data-roving-value')) {\n element.setAttribute('data-roving-value', item.value);\n }\n }\n }\n\n /** Hands the elements it stamped that now belong to a nested composite back to their author. */\n private release(container: HTMLElement): void {\n let candidates: HTMLElement[];\n try {\n candidates = Array.from(container.querySelectorAll<HTMLElement>(this.options.itemSelector));\n } catch {\n return;\n }\n for (const candidate of candidates) {\n const original = this.stamped.get(candidate);\n if (!original) continue;\n if (!isInNestedComposite(candidate, container, this.options.roleComposites)) continue;\n this.stamped.delete(candidate);\n if (original.tabIndex === null) candidate.removeAttribute('tabindex');\n else candidate.setAttribute('tabindex', original.tabIndex);\n if (original.addedValue) candidate.removeAttribute('data-roving-value');\n }\n }\n\n private valueOf(element: HTMLElement, nested: boolean): string {\n const own = nested ? null : element.getAttribute('data-roving-value');\n if (own !== null) return own;\n let generated = this.autoValues.get(element);\n if (generated === undefined) {\n this.autoCounter += 1;\n generated = `auto-${this.autoCounter}`;\n this.autoValues.set(element, generated);\n }\n return generated;\n }\n\n private observe(): void {\n if (!this.container || this.observer || typeof MutationObserver === 'undefined') return;\n this.observer = new MutationObserver(() => {\n this.stamp();\n this.dirty = true;\n this.notify?.();\n });\n this.observer.observe(this.container, {\n subtree: true,\n childList: true,\n attributes: true,\n attributeFilter: OBSERVED_ATTRIBUTES,\n });\n this.dirty = true;\n }\n\n private disconnect(): void {\n this.observer?.disconnect();\n this.observer = null;\n }\n}\n\nfunction parseSnapshot(snapshot: string): SnapshotEntry[] | null {\n if (snapshot === '') return null;\n try {\n return JSON.parse(snapshot) as SnapshotEntry[];\n } catch {\n return null;\n }\n}\n\nfunction textOf(element: HTMLElement): string {\n return element.getAttribute('data-roving-text') ?? element.textContent ?? '';\n}\n\n/**\n * Whether an event target is the container or inside its DOM. React bubbles events from a portal\n * (a Menu.Popover or Popover.Content a Toolbar item renders) through the container although their\n * target is elsewhere in the document; those events are not the container's to handle.\n */\nfunction isInContainer(container: Node, target: EventTarget | null): boolean {\n if (!target || typeof (target as Node).nodeType !== 'number') return false;\n return target === container || container.contains(target as Node);\n}\n\n/**\n * The item an event started in: the innermost item element that is the target or one of its\n * ancestors (up to the container). Items can nest (an APG treeitem contains the group of its child\n * treeitems), so the first containing item in DOM order would be the outermost ancestor.\n */\nfunction findOwningItem(\n items: readonly ResolvedItem[],\n target: EventTarget | null,\n container: Node,\n): ResolvedItem | null {\n if (items.length === 0 || !target || typeof (target as Node).nodeType !== 'number') return null;\n const byElement = new Map<Node, ResolvedItem>(items.map((item) => [item.element, item]));\n for (let node: Node | null = target as Node; node && node !== container; node = node.parentNode) {\n const item = byElement.get(node);\n if (item) return item;\n }\n return null;\n}\n\n/**\n * Whether a key started on the item itself (on the container when it started on no item), not on\n * content nested inside the item, such as a row's action button.\n */\nfunction startsOnItem(item: ResolvedItem | null, target: EventTarget | null, container: Node) {\n return item ? target === getFocusTarget(item) : target === container;\n}\n\n/**\n * Implements the WAI-ARIA roving tabindex pattern for composite widgets: one item holds the tab\n * stop (`tabIndex=0`, all others `-1`), arrow keys move focus between items, Home/End jump to the\n * ends, and (optionally) typeahead jumps by text. Used by RadioGroup, Rating, SwatchPicker, List,\n * TabList, Tree, Menu and Toolbar.\n *\n * - **Items** come from the DOM at event time: elements matching `itemSelector` (default\n * `[data-roving-value]`) whose nearest roving container is this one. A nested composite (an\n * element with its own `data-roving-container`, or a radiogroup/listbox/grid/tablist/menu/tree/\n * spinbutton role) counts as one item whose focus target is its own tab stop; the hook never\n * writes tabindex inside it, so it keeps its own Tab stop. An element marked\n * `data-roving-transparent` is never a nested composite by its role: its items are items of this\n * container (the radios of `Toolbar.RadioGroup`); it must not carry a `data-roving-container`.\n * Pass `items` to fix the order instead.\n * In the 0.4 call shape and with explicit `items`, only elements with their own roving container\n * are nested composites: a role-only `radiogroup`/`tablist`/… element between the container and\n * the items (the widget's root inside a wrapper that holds the ref) does not swallow them.\n * - **Disabled items** (`data-roving-disabled`, `disabled`, `aria-disabled=\"true\"`) are skipped and\n * never hold the tab stop. Items marked `data-disabled-focusable` (the `disabledFocusable` prop\n * of WaveUI buttons, links and choice controls) stay reachable and may hold the tab stop: APG\n * allows focusable disabled items. The attribute only overrides `aria-disabled`: an item that is\n * natively disabled or marked `data-roving-disabled` is still skipped. The enabled set is\n * tracked with a MutationObserver, so an item that disables itself moves the tab stop without\n * the owner re-rendering. With `manageTabIndex`, a control hidden by CSS counts as disabled and\n * `input[type=hidden]` is no item.\n * - **Tab stop** (`tabStop`): `'active'` — the enabled `activeValue` item, else the first enabled\n * item; `'last-focused'` — the last focused enabled item, else the `'active'` rule. A nested\n * composite or a control that uses the arrow keys itself holds it only when no other item can.\n * - **Keys** are ignored when another handler already called `preventDefault()`; with Meta; with\n * Alt or Ctrl, except a single character typed with AltGr (Ctrl+Alt on Windows), which is\n * typeahead text (arrows, Home, End and Space with Ctrl+Alt stay ignored); and when they start\n * in a text field, select, contenteditable, slider, spinbutton or editable combobox (Left/Right\n * keep moving the caret; a select-only combobox such as Dropdown's button does not keep them).\n * Left/Right are mirrored in RTL (`dir`, else the direction of the container at key time).\n * Arrows and typeahead move from the item the key started in — the innermost one when items\n * nest, as treeitems do inside their parent's group; when it started on no item (focus on the\n * container itself) next goes to the first enabled item and prev to the last.\n * An item whose `focus()` leaves focus where it was (the browser ignores it on an element CSS\n * hides) is passed over for the next one, and is never recorded or reported to `onFocusMove`.\n * Handled keys call `preventDefault()`. Keys and focus from outside the container's DOM — a\n * popup an item renders through a portal, whose events React bubbles through the container —\n * are ignored, so focus never leaves an open menu or popover for the container's items.\n *\n * @example\n * const { containerProps, getTabIndex } = useRovingTabIndex({ activeValue: value, orientation: 'both' });\n * <div role=\"radiogroup\" {...containerProps}>\n * <button role=\"radio\" data-roving-value=\"a\" tabIndex={getTabIndex('a')} />\n * </div>\n *\n * The 0.4 call shape `useRovingTabIndex(containerRef, options)` still works: pass the container's\n * ref object and attach `handleKeyDown` (and ideally `handleFocus`, and with `typeahead`\n * `handleKeyDownCapture` as `onKeyDownCapture`) yourself.\n *\n * @param options - See {@link UseRovingTabIndexOptions}.\n * @returns See {@link UseRovingTabIndexResult}.\n */\nexport function useRovingTabIndex(options: UseRovingTabIndexOptions): UseRovingTabIndexResult;\nexport function useRovingTabIndex(\n containerRef: React.RefObject<HTMLElement | null>,\n options: UseRovingTabIndexOptions,\n): UseRovingTabIndexResult;\nexport function useRovingTabIndex(\n refOrOptions: React.RefObject<HTMLElement | null> | UseRovingTabIndexOptions,\n maybeOptions?: UseRovingTabIndexOptions,\n): UseRovingTabIndexResult {\n const legacyRef =\n maybeOptions !== undefined ? (refOrOptions as React.RefObject<HTMLElement | null>) : undefined;\n const options = (maybeOptions ?? refOrOptions) as UseRovingTabIndexOptions;\n const {\n activeValue = null,\n items,\n orientation = 'horizontal',\n loop = true,\n dir,\n itemSelector = DEFAULT_ITEM_SELECTOR,\n typeahead = false,\n homeEndKeys = true,\n tabStop = 'active',\n manageTabIndex = false,\n onFocusMove,\n } = options;\n\n const [store] = React.useState(() => new RovingStore());\n const snapshot = React.useSyncExternalStore(\n store.subscribe,\n store.getSnapshot,\n store.getServerSnapshot,\n );\n const [focusedValue, setFocusedValue] = React.useState<string | null>(null);\n // The last focused item that can hold the tab stop ('last-focused' during render).\n const [focusedStop, setFocusedStop] = React.useState<string | null>(null);\n\n // 0.4 call shape or explicit `items`: only elements with their own roving container are nested\n // composites (a role=radiogroup/tablist/… around the items is the widget's own root).\n const roleComposites = legacyRef === undefined && items === undefined;\n\n React.useLayoutEffect(() => {\n store.setOptions({ itemSelector, manageTabIndex, items, activeValue, tabStop, roleComposites });\n if (legacyRef) store.setContainer(legacyRef.current);\n store.stamp();\n });\n\n // C-DEV: `resolveOwn` treats a selector the browser rejects as \"no items\" (it runs during render,\n // where it must not throw), so the developer hears about it here.\n React.useEffect(() => {\n if (isDev && !isValidSelector(itemSelector)) {\n warnOnce(\n `useRovingTabIndex:itemSelector:${itemSelector}`,\n `useRovingTabIndex: itemSelector \"${itemSelector}\" is not a valid CSS selector in this browser; no item is navigable or tabbable.`,\n );\n }\n }, [itemSelector]);\n\n // Tab stop during render, from the DOM snapshot (null before the container is known).\n const domItems = React.useMemo(() => parseSnapshot(snapshot), [snapshot]);\n const stopEntries = React.useMemo<readonly SnapshotEntry[] | null>(() => {\n if (!items) return domItems;\n // Explicit `items`: the listed values the DOM has, in the listed order. Every listed value\n // before the container is known, or while the DOM has none of them yet (items rendered in the\n // commit the snapshot has not caught up with).\n if (domItems) {\n const ranks = new Map(domItems);\n const present = items.flatMap((value): SnapshotEntry[] => {\n const rank = ranks.get(value);\n return rank === undefined ? [] : [[value, rank]];\n });\n if (present.length > 0) return present;\n }\n return items.map((value): SnapshotEntry => [value, 1]);\n }, [items, domItems]);\n const tabStopValue = stopEntries\n ? resolveTabStop(stopEntries, activeValue, tabStop, focusedStop)\n : activeValue || null;\n\n const getTabIndex = React.useCallback(\n (value: string): 0 | -1 => (value === tabStopValue ? 0 : -1),\n [tabStopValue],\n );\n\n const containerRef = React.useCallback(\n (node: HTMLElement | null) => {\n store.setContainer(node);\n if (legacyRef) setRef(legacyRef, node);\n },\n [store, legacyRef],\n );\n\n const typeaheadItemsRef = React.useRef<TypeaheadItem[]>([]);\n // Every item matching the typed characters, in search order (the first is the match).\n const typeaheadMatchesRef = React.useRef<readonly string[]>([]);\n const { onTypeahead, isSearching } = useTypeahead({\n getItems: () => typeaheadItemsRef.current,\n onMatch: (_value, matches) => {\n typeaheadMatchesRef.current = matches;\n },\n });\n\n /** Focuses an item; `true` only when focus actually moved there (then it is recorded). */\n const focusItem = (item: ResolvedItem | undefined): boolean => {\n if (!item || item.disabled) return false;\n const target = getFocusTarget(item);\n if (!target) return false;\n target.focus();\n // Browsers ignore focus() on an element CSS hides (display: none, visibility: hidden).\n if (!hasFocus(target)) return false;\n store.recordFocus(item);\n return true;\n };\n\n /** Focuses the first item of `candidates` that takes focus. */\n const focusFirstOf = (candidates: readonly ResolvedItem[]): void => {\n for (const item of candidates) {\n if (focusItem(item)) return;\n }\n };\n\n // `spaceOnly` (the capture phase) handles nothing but a Space that continues a typeahead search.\n const handleKeys = useEventCallback((e: React.KeyboardEvent, spaceOnly: boolean) => {\n // Ctrl, Alt and Meta combinations are shortcuts, except a single character typed with AltGr\n // (Ctrl+Alt on Windows), which is typeahead text: arrows, Home, End and Space with it stay\n // shortcuts.\n const shortcut = e.metaKey || ((e.altKey || e.ctrlKey) && !isAltGraphCharacter(e));\n if (e.defaultPrevented || shortcut) return;\n if (ownsArrowKeys(e.target)) return;\n const container = store.container ?? (e.currentTarget as HTMLElement);\n // A key from a portaled popup is the popup's: never pull focus back out of it.\n if (!isInContainer(container, e.target)) return;\n const ordered = store.resolve(container);\n const enabled = ordered.filter((item) => !item.disabled);\n if (enabled.length === 0) return;\n\n // The (innermost) item the key started in. None (the container itself has focus): next → first,\n // prev → last.\n const current = findOwningItem(ordered, e.target, container);\n\n let handled = false;\n // Where focus goes, in order of preference: an item whose focus() does not move focus (hidden\n // by CSS) passes the key on to the next one.\n let targets: ResolvedItem[] = [];\n const intent = spaceOnly\n ? null\n : getArrowIntent(e.key, {\n orientation,\n dir: dir ?? getDirection(e.currentTarget as Element),\n });\n if (intent) {\n handled = true;\n if (!current) {\n targets = intent === 'next' ? enabled : [...enabled].reverse();\n } else {\n const step = intent === 'next' ? 1 : -1;\n const count = ordered.length;\n let index = ordered.indexOf(current);\n for (let i = 1; i < count; i++) {\n index += step;\n if (index < 0 || index >= count) {\n if (!loop) break;\n index = (index + count) % count;\n }\n if (!ordered[index].disabled) targets.push(ordered[index]);\n }\n }\n } else if (!spaceOnly && homeEndKeys && (e.key === 'Home' || e.key === 'End')) {\n handled = true;\n targets = e.key === 'Home' ? enabled : [...enabled].reverse();\n } else if (typeahead && startsOnItem(current, e.target, container)) {\n typeaheadItemsRef.current = ordered.map((item) => ({\n value: item.value,\n text: textOf(item.element),\n disabled: item.disabled,\n }));\n typeaheadMatchesRef.current = [];\n if (onTypeahead(e, current?.value ?? null)) {\n handled = true;\n // The match first, then the next ones, for a match that does not take focus.\n targets = typeaheadMatchesRef.current.flatMap((value) =>\n enabled.filter((item) => item.value === value),\n );\n }\n }\n\n if (!handled) return;\n e.preventDefault();\n for (const next of targets) {\n // Back at the item the key started on (Home on the first item): focus stays.\n if (next === current) return;\n if (focusItem(next)) {\n onFocusMove?.(next.value, e);\n return;\n }\n }\n });\n\n const handleKeyDown = useEventCallback((e: React.KeyboardEvent) => handleKeys(e, false));\n\n // A Space that continues a typeahead search belongs to the search, not to the focused item: it is\n // handled and default-prevented in the capture phase, so the item's own keydown handler, which\n // skips default-prevented events, does not activate the item.\n const handleKeyDownCapture = useEventCallback((e: React.KeyboardEvent) => {\n if (typeahead && e.key === ' ' && isSearching()) handleKeys(e, true);\n });\n\n const handleFocus = useEventCallback((e: React.FocusEvent) => {\n const container = store.container ?? (e.currentTarget as HTMLElement);\n if (!isInContainer(container, e.target)) return;\n const item = findOwningItem(store.resolve(container), e.target, container);\n if (!item) return;\n store.recordFocus(item);\n setFocusedValue(item.value);\n if (canHoldTabStop(item)) setFocusedStop(item.value);\n store.stamp();\n });\n\n const focusValue = useEventCallback((value: string) => {\n focusItem(store.resolve().find((item) => item.value === value));\n });\n const focusFirst = useEventCallback(() => {\n focusFirstOf(store.resolve().filter((item) => !item.disabled));\n });\n const focusLast = useEventCallback(() => {\n focusFirstOf(\n store\n .resolve()\n .filter((item) => !item.disabled)\n .reverse(),\n );\n });\n\n const containerProps = React.useMemo<RovingContainerProps>(\n () => ({\n ref: containerRef,\n 'data-roving-container': '',\n onKeyDown: handleKeyDown,\n onKeyDownCapture: handleKeyDownCapture,\n onFocus: handleFocus,\n }),\n [containerRef, handleKeyDown, handleKeyDownCapture, handleFocus],\n );\n\n return {\n containerProps,\n handleKeyDown,\n handleKeyDownCapture,\n handleFocus,\n getTabIndex,\n focusedValue,\n focusValue,\n focusFirst,\n focusLast,\n };\n}\n"],"mappings":"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"}
|