@digdir/designsystemet-react 1.0.0-next.15 → 1.0.0-next.16
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/dist/cjs/components/Accordion/index.js +2 -2
- package/dist/cjs/components/Breadcrumbs/BreadcrumbsItem.js +11 -0
- package/dist/cjs/components/Breadcrumbs/BreadcrumbsLink.js +12 -0
- package/dist/cjs/components/Breadcrumbs/BreadcrumbsList.js +23 -0
- package/dist/cjs/components/Breadcrumbs/BreadcrumbsNav.js +11 -0
- package/dist/cjs/components/Breadcrumbs/BreadcrumbsRoot.js +11 -0
- package/dist/cjs/components/Breadcrumbs/index.js +43 -0
- package/dist/cjs/components/Divider/Divider.js +3 -4
- package/dist/cjs/components/DropdownMenu/DropdownMenuContent.js +2 -2
- package/dist/cjs/components/Modal/ModalDialog.js +1 -2
- package/dist/cjs/components/Modal/ModalHeader.js +2 -2
- package/dist/cjs/components/Modal/index.js +1 -0
- package/dist/cjs/components/Popover/PopoverContent.js +3 -4
- package/dist/cjs/components/Tabs/TabList.js +1 -1
- package/dist/cjs/components/ToggleGroup/ToggleGroupRoot.js +1 -1
- package/dist/cjs/components/Tooltip/Tooltip.js +3 -4
- package/dist/cjs/components/form/Checkbox/{Group/Group.js → CheckboxGroup.js} +3 -2
- package/dist/cjs/components/form/Checkbox/index.js +3 -3
- package/dist/cjs/components/form/Checkbox/useCheckbox.js +2 -2
- package/dist/cjs/components/form/Combobox/Combobox.js +2 -2
- package/dist/cjs/components/form/Combobox/Option/Description.js +1 -2
- package/dist/cjs/components/form/Combobox/internal/ComboboxChips.js +1 -2
- package/dist/cjs/components/form/Combobox/internal/ComboboxClearButton.js +1 -2
- package/dist/cjs/components/form/Combobox/internal/ComboboxError.js +1 -2
- package/dist/cjs/components/form/Combobox/internal/ComboboxInput.js +5 -6
- package/dist/cjs/components/form/Combobox/internal/ComboboxLabel.js +1 -2
- package/dist/cjs/components/form/Combobox/internal/ComboboxNative.js +1 -2
- package/dist/cjs/components/form/Combobox/useCombobox.js +5 -0
- package/dist/cjs/components/form/Combobox/useFloatingCombobox.js +4 -4
- package/dist/cjs/components/form/NativeSelect/NativeSelect.js +2 -2
- package/dist/cjs/components/form/NativeSelect/useNativeSelect.js +19 -1
- package/dist/cjs/components/form/Radio/{Group/Group.js → RadioGroup.js} +3 -3
- package/dist/cjs/components/form/Radio/index.js +3 -3
- package/dist/cjs/components/form/Radio/useRadio.js +2 -2
- package/dist/cjs/components/form/Switch/useSwitch.js +2 -2
- package/dist/cjs/index.js +50 -36
- package/dist/cjs/node_modules/@floating-ui/core/dist/floating-ui.core.js +23 -9
- package/dist/cjs/node_modules/@floating-ui/dom/dist/floating-ui.dom.js +39 -24
- package/dist/cjs/node_modules/@floating-ui/react/dist/floating-ui.react.js +848 -729
- package/dist/cjs/node_modules/@floating-ui/react/dist/floating-ui.react.utils.js +1 -1
- package/dist/cjs/node_modules/@floating-ui/react/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js +68 -0
- package/dist/cjs/node_modules/@floating-ui/react/node_modules/@floating-ui/utils/dist/floating-ui.utils.js +11 -0
- package/dist/cjs/node_modules/@floating-ui/react-dom/dist/floating-ui.react-dom.js +97 -45
- package/dist/cjs/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js +17 -6
- package/dist/cjs/node_modules/@floating-ui/utils/dist/floating-ui.utils.js +14 -5
- package/dist/cjs/node_modules/@radix-ui/react-compose-refs/dist/index.js +10 -14
- package/dist/cjs/node_modules/@radix-ui/react-slot/dist/index.js +88 -69
- package/dist/cjs/node_modules/@tanstack/virtual-core/dist/esm/index.js +134 -62
- package/dist/cjs/node_modules/@tanstack/virtual-core/dist/esm/utils.js +3 -5
- package/dist/cjs/utilities/AnimateHeight/AnimateHeight.js +4 -1
- package/dist/cjs/utilities/RovingFocus/RovingFocusItem.js +34 -6
- package/dist/cjs/utilities/RovingFocus/RovingFocusRoot.js +3 -1
- package/dist/cjs/utilities/RovingFocus/useRovingFocus.js +2 -1
- package/dist/esm/components/Accordion/index.js +2 -2
- package/dist/esm/components/Box/Box.js +2 -2
- package/dist/esm/components/Breadcrumbs/BreadcrumbsItem.js +9 -0
- package/dist/esm/components/Breadcrumbs/BreadcrumbsLink.js +10 -0
- package/dist/esm/components/Breadcrumbs/BreadcrumbsList.js +21 -0
- package/dist/esm/components/Breadcrumbs/BreadcrumbsNav.js +9 -0
- package/dist/esm/components/Breadcrumbs/BreadcrumbsRoot.js +9 -0
- package/dist/esm/components/Breadcrumbs/index.js +36 -0
- package/dist/esm/components/Button/Button.js +2 -2
- package/dist/esm/components/Card/Card.js +2 -2
- package/dist/esm/components/Card/CardContent.js +2 -2
- package/dist/esm/components/Card/CardFooter.js +2 -2
- package/dist/esm/components/Card/CardHeader.js +2 -2
- package/dist/esm/components/Card/CardMedia.js +2 -2
- package/dist/esm/components/Divider/Divider.js +3 -4
- package/dist/esm/components/DropdownMenu/DropdownMenuContent.js +2 -2
- package/dist/esm/components/DropdownMenu/DropdownMenuTrigger.js +2 -2
- package/dist/esm/components/ErrorSummary/ErrorSummaryRoot.js +2 -2
- package/dist/esm/components/Link/Link.js +2 -2
- package/dist/esm/components/List/ListItem.js +2 -2
- package/dist/esm/components/List/ListRoot.js +2 -2
- package/dist/esm/components/List/Lists.js +3 -3
- package/dist/esm/components/Modal/ModaContent.js +2 -2
- package/dist/esm/components/Modal/ModalDialog.js +5 -6
- package/dist/esm/components/Modal/ModalFooter.js +2 -2
- package/dist/esm/components/Modal/ModalHeader.js +4 -4
- package/dist/esm/components/Modal/ModalTrigger.js +2 -2
- package/dist/esm/components/Modal/index.js +1 -1
- package/dist/esm/components/Pagination/PaginationContent.js +2 -2
- package/dist/esm/components/Pagination/PaginationItem.js +2 -2
- package/dist/esm/components/Pagination/PaginationRoot.js +2 -2
- package/dist/esm/components/Popover/PopoverContent.js +2 -3
- package/dist/esm/components/Popover/PopoverTrigger.js +2 -2
- package/dist/esm/components/Tabs/TabList.js +1 -1
- package/dist/esm/components/ToggleGroup/ToggleGroupRoot.js +1 -1
- package/dist/esm/components/Tooltip/Tooltip.js +2 -3
- package/dist/esm/components/Typography/ErrorMessage/ErrorMessage.js +2 -2
- package/dist/esm/components/Typography/Heading/Heading.js +2 -2
- package/dist/esm/components/Typography/Ingress/Ingress.js +2 -2
- package/dist/esm/components/Typography/Label/Label.js +2 -2
- package/dist/esm/components/Typography/Paragraph/Paragraph.js +2 -2
- package/dist/esm/components/form/Checkbox/{Group/Group.js → CheckboxGroup.js} +3 -2
- package/dist/esm/components/form/Checkbox/index.js +1 -1
- package/dist/esm/components/form/Checkbox/useCheckbox.js +1 -1
- package/dist/esm/components/form/Combobox/Combobox.js +2 -2
- package/dist/esm/components/form/Combobox/Custom.js +2 -2
- package/dist/esm/components/form/Combobox/Option/Description.js +1 -2
- package/dist/esm/components/form/Combobox/internal/ComboboxChips.js +1 -2
- package/dist/esm/components/form/Combobox/internal/ComboboxClearButton.js +1 -2
- package/dist/esm/components/form/Combobox/internal/ComboboxError.js +1 -2
- package/dist/esm/components/form/Combobox/internal/ComboboxInput.js +5 -6
- package/dist/esm/components/form/Combobox/internal/ComboboxLabel.js +1 -2
- package/dist/esm/components/form/Combobox/internal/ComboboxNative.js +1 -2
- package/dist/esm/components/form/Combobox/useCombobox.js +5 -0
- package/dist/esm/components/form/Combobox/useFloatingCombobox.js +2 -2
- package/dist/esm/components/form/NativeSelect/NativeSelect.js +2 -2
- package/dist/esm/components/form/NativeSelect/useNativeSelect.js +19 -1
- package/dist/esm/components/form/Radio/{Group/Group.js → RadioGroup.js} +3 -3
- package/dist/esm/components/form/Radio/index.js +1 -1
- package/dist/esm/components/form/Radio/useRadio.js +1 -1
- package/dist/esm/components/form/Switch/useSwitch.js +1 -1
- package/dist/esm/index.js +9 -2
- package/dist/esm/node_modules/@floating-ui/core/dist/floating-ui.core.js +24 -10
- package/dist/esm/node_modules/@floating-ui/dom/dist/floating-ui.dom.js +41 -26
- package/dist/esm/node_modules/@floating-ui/react/dist/floating-ui.react.js +830 -712
- package/dist/esm/node_modules/@floating-ui/react/dist/floating-ui.react.utils.js +1 -1
- package/dist/esm/node_modules/@floating-ui/react/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js +57 -0
- package/dist/esm/node_modules/@floating-ui/react/node_modules/@floating-ui/utils/dist/floating-ui.utils.js +9 -0
- package/dist/esm/node_modules/@floating-ui/react-dom/dist/floating-ui.react-dom.js +96 -45
- package/dist/esm/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js +17 -7
- package/dist/esm/node_modules/@floating-ui/utils/dist/floating-ui.utils.js +14 -5
- package/dist/esm/node_modules/@radix-ui/react-compose-refs/dist/index.js +10 -14
- package/dist/esm/node_modules/@radix-ui/react-slot/dist/index.js +71 -71
- package/dist/esm/node_modules/@tanstack/virtual-core/dist/esm/index.js +134 -62
- package/dist/esm/node_modules/@tanstack/virtual-core/dist/esm/utils.js +3 -5
- package/dist/esm/utilities/AnimateHeight/AnimateHeight.js +4 -1
- package/dist/esm/utilities/RovingFocus/RovingFocusItem.js +36 -8
- package/dist/esm/utilities/RovingFocus/RovingFocusRoot.js +5 -3
- package/dist/esm/utilities/RovingFocus/useRovingFocus.js +2 -1
- package/dist/types/components/Accordion/AccordionHeading.d.ts +1 -1
- package/dist/types/components/Accordion/AccordionHeading.d.ts.map +1 -1
- package/dist/types/components/Accordion/AccordionItem.d.ts +2 -2
- package/dist/types/components/Accordion/AccordionItem.d.ts.map +1 -1
- package/dist/types/components/Accordion/AccordionRoot.d.ts +2 -2
- package/dist/types/components/Accordion/AccordionRoot.d.ts.map +1 -1
- package/dist/types/components/Accordion/index.d.ts +2 -2
- package/dist/types/components/Accordion/index.d.ts.map +1 -1
- package/dist/types/components/Alert/Alert.d.ts +3 -3
- package/dist/types/components/Alert/Alert.d.ts.map +1 -1
- package/dist/types/components/Badge/Badge.d.ts +93 -0
- package/dist/types/components/Badge/Badge.d.ts.map +1 -0
- package/dist/types/components/Badge/index.d.ts +3 -0
- package/dist/types/components/Badge/index.d.ts.map +1 -0
- package/dist/types/components/Box/Box.d.ts +5 -5
- package/dist/types/components/Box/Box.d.ts.map +1 -1
- package/dist/types/components/Breadcrumbs/BreadcrumbsItem.d.ts +4 -0
- package/dist/types/components/Breadcrumbs/BreadcrumbsItem.d.ts.map +1 -0
- package/dist/types/components/Breadcrumbs/BreadcrumbsLink.d.ts +10 -0
- package/dist/types/components/Breadcrumbs/BreadcrumbsLink.d.ts.map +1 -0
- package/dist/types/components/Breadcrumbs/BreadcrumbsList.d.ts +4 -0
- package/dist/types/components/Breadcrumbs/BreadcrumbsList.d.ts.map +1 -0
- package/dist/types/components/Breadcrumbs/BreadcrumbsNav.d.ts +14 -0
- package/dist/types/components/Breadcrumbs/BreadcrumbsNav.d.ts.map +1 -0
- package/dist/types/components/Breadcrumbs/BreadcrumbsRoot.d.ts +16 -0
- package/dist/types/components/Breadcrumbs/BreadcrumbsRoot.d.ts.map +1 -0
- package/dist/types/components/Breadcrumbs/index.d.ts +44 -0
- package/dist/types/components/Breadcrumbs/index.d.ts.map +1 -0
- package/dist/types/components/Button/Button.d.ts +6 -6
- package/dist/types/components/Button/Button.d.ts.map +1 -1
- package/dist/types/components/Card/Card.d.ts +3 -3
- package/dist/types/components/Card/Card.d.ts.map +1 -1
- package/dist/types/components/Card/CardContent.d.ts +1 -1
- package/dist/types/components/Card/CardContent.d.ts.map +1 -1
- package/dist/types/components/Card/CardFooter.d.ts +1 -1
- package/dist/types/components/Card/CardFooter.d.ts.map +1 -1
- package/dist/types/components/Card/CardHeader.d.ts +1 -1
- package/dist/types/components/Card/CardHeader.d.ts.map +1 -1
- package/dist/types/components/Card/CardMedia.d.ts +1 -1
- package/dist/types/components/Card/CardMedia.d.ts.map +1 -1
- package/dist/types/components/Card/index.d.ts.map +1 -1
- package/dist/types/components/Chip/Group/Group.d.ts +1 -1
- package/dist/types/components/Chip/Removable/Removable.d.ts +1 -1
- package/dist/types/components/Chip/Toggle/Toggle.d.ts +3 -3
- package/dist/types/components/Chip/Toggle/Toggle.d.ts.map +1 -1
- package/dist/types/components/Divider/Divider.d.ts +1 -1
- package/dist/types/components/Divider/Divider.d.ts.map +1 -1
- package/dist/types/components/DropdownMenu/DropdownMenuContent.d.ts.map +1 -1
- package/dist/types/components/DropdownMenu/DropdownMenuGroup.d.ts.map +1 -1
- package/dist/types/components/DropdownMenu/DropdownMenuTrigger.d.ts +7 -7
- package/dist/types/components/DropdownMenu/index.d.ts.map +1 -1
- package/dist/types/components/ErrorSummary/ErrorSummaryRoot.d.ts +1 -1
- package/dist/types/components/ErrorSummary/index.d.ts.map +1 -1
- package/dist/types/components/Link/Link.d.ts +4 -4
- package/dist/types/components/Link/Link.d.ts.map +1 -1
- package/dist/types/components/List/ListHeading.d.ts +4 -4
- package/dist/types/components/List/ListItem.d.ts +1 -1
- package/dist/types/components/List/ListItem.d.ts.map +1 -1
- package/dist/types/components/List/ListRoot.d.ts +2 -2
- package/dist/types/components/List/ListRoot.d.ts.map +1 -1
- package/dist/types/components/List/Lists.d.ts +2 -2
- package/dist/types/components/List/Lists.d.ts.map +1 -1
- package/dist/types/components/Modal/ModaContent.d.ts +1 -1
- package/dist/types/components/Modal/ModaContent.d.ts.map +1 -1
- package/dist/types/components/Modal/ModalDialog.d.ts +4 -4
- package/dist/types/components/Modal/ModalDialog.d.ts.map +1 -1
- package/dist/types/components/Modal/ModalFooter.d.ts +1 -1
- package/dist/types/components/Modal/ModalFooter.d.ts.map +1 -1
- package/dist/types/components/Modal/ModalHeader.d.ts +19 -3
- package/dist/types/components/Modal/ModalHeader.d.ts.map +1 -1
- package/dist/types/components/Modal/ModalTrigger.d.ts +7 -7
- package/dist/types/components/Modal/index.d.ts +1 -1
- package/dist/types/components/Modal/index.d.ts.map +1 -1
- package/dist/types/components/Modal/useModalState.d.ts.map +1 -1
- package/dist/types/components/Pagination/Pagination.d.ts +4 -4
- package/dist/types/components/Pagination/Pagination.d.ts.map +1 -1
- package/dist/types/components/Pagination/PaginationButton.d.ts +1 -1
- package/dist/types/components/Pagination/PaginationButton.d.ts.map +1 -1
- package/dist/types/components/Pagination/PaginationContent.d.ts +1 -1
- package/dist/types/components/Pagination/PaginationContent.d.ts.map +1 -1
- package/dist/types/components/Pagination/PaginationItem.d.ts +1 -1
- package/dist/types/components/Pagination/PaginationItem.d.ts.map +1 -1
- package/dist/types/components/Pagination/PaginationNextPrev.d.ts +2 -2
- package/dist/types/components/Pagination/PaginationRoot.d.ts +3 -3
- package/dist/types/components/Pagination/PaginationRoot.d.ts.map +1 -1
- package/dist/types/components/Pagination/index.d.ts.map +1 -1
- package/dist/types/components/Popover/PopoverContent.d.ts.map +1 -1
- package/dist/types/components/Popover/PopoverRoot.d.ts +10 -10
- package/dist/types/components/Popover/PopoverRoot.d.ts.map +1 -1
- package/dist/types/components/Popover/PopoverTrigger.d.ts +7 -7
- package/dist/types/components/Popover/index.d.ts.map +1 -1
- package/dist/types/components/SkipLink/SkipLink.d.ts.map +1 -1
- package/dist/types/components/Spinner/Spinner.d.ts.map +1 -1
- package/dist/types/components/Table/Table.d.ts +4 -4
- package/dist/types/components/Table/Table.d.ts.map +1 -1
- package/dist/types/components/Table/TableHeaderCell.d.ts +3 -3
- package/dist/types/components/Table/TableHeaderCell.d.ts.map +1 -1
- package/dist/types/components/Table/index.d.ts.map +1 -1
- package/dist/types/components/Tabs/TabList.d.ts.map +1 -1
- package/dist/types/components/Tabs/TabsRoot.d.ts +4 -4
- package/dist/types/components/Tabs/TabsRoot.d.ts.map +1 -1
- package/dist/types/components/Tag/Tag.d.ts +1 -1
- package/dist/types/components/Tag/Tag.d.ts.map +1 -1
- package/dist/types/components/ToggleGroup/ToggleGroupItem/ToggleGroupItem.d.ts +1 -1
- package/dist/types/components/ToggleGroup/ToggleGroupItem/ToggleGroupItem.d.ts.map +1 -1
- package/dist/types/components/ToggleGroup/ToggleGroupRoot.d.ts +5 -5
- package/dist/types/components/ToggleGroup/ToggleGroupRoot.d.ts.map +1 -1
- package/dist/types/components/ToggleGroup/index.d.ts.map +1 -1
- package/dist/types/components/Tooltip/Tooltip.d.ts +4 -4
- package/dist/types/components/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/types/components/Typography/ErrorMessage/ErrorMessage.d.ts +4 -4
- package/dist/types/components/Typography/ErrorMessage/ErrorMessage.d.ts.map +1 -1
- package/dist/types/components/Typography/Heading/Heading.d.ts +4 -4
- package/dist/types/components/Typography/Heading/Heading.d.ts.map +1 -1
- package/dist/types/components/Typography/Ingress/Ingress.d.ts +3 -3
- package/dist/types/components/Typography/Ingress/Ingress.d.ts.map +1 -1
- package/dist/types/components/Typography/Label/Label.d.ts +4 -4
- package/dist/types/components/Typography/Label/Label.d.ts.map +1 -1
- package/dist/types/components/Typography/Paragraph/Paragraph.d.ts +4 -4
- package/dist/types/components/Typography/Paragraph/Paragraph.d.ts.map +1 -1
- package/dist/types/components/form/CharacterCounter.d.ts.map +1 -1
- package/dist/types/components/form/Checkbox/Checkbox.d.ts +1 -1
- package/dist/types/components/form/Checkbox/Checkbox.d.ts.map +1 -1
- package/dist/types/components/form/Checkbox/{Group/Group.d.ts → CheckboxGroup.d.ts} +5 -5
- package/dist/types/components/form/Checkbox/CheckboxGroup.d.ts.map +1 -0
- package/dist/types/components/form/Checkbox/index.d.ts +2 -2
- package/dist/types/components/form/Checkbox/index.d.ts.map +1 -1
- package/dist/types/components/form/Combobox/Combobox.d.ts +42 -42
- package/dist/types/components/form/Combobox/Combobox.d.ts.map +1 -1
- package/dist/types/components/form/Combobox/ComboboxIdContext.d.ts.map +1 -1
- package/dist/types/components/form/Combobox/Empty.d.ts +1 -1
- package/dist/types/components/form/Combobox/Empty.d.ts.map +1 -1
- package/dist/types/components/form/Combobox/Option/Option.d.ts +2 -2
- package/dist/types/components/form/Combobox/Option/Option.d.ts.map +1 -1
- package/dist/types/components/form/Combobox/Option/useComboboxOption.d.ts +1 -1
- package/dist/types/components/form/Combobox/index.d.ts +3 -0
- package/dist/types/components/form/Combobox/index.d.ts.map +1 -1
- package/dist/types/components/form/Combobox/useCombobox.d.ts.map +1 -1
- package/dist/types/components/form/Combobox/useFloatingCombobox.d.ts +9 -9
- package/dist/types/components/form/Fieldset/Fieldset.d.ts +3 -3
- package/dist/types/components/form/Fieldset/Fieldset.d.ts.map +1 -1
- package/dist/types/components/form/Fieldset/useFieldset.d.ts +2 -2
- package/dist/types/components/form/NativeSelect/NativeSelect.d.ts +6 -6
- package/dist/types/components/form/NativeSelect/NativeSelect.d.ts.map +1 -1
- package/dist/types/components/form/NativeSelect/useNativeSelect.d.ts +1 -1
- package/dist/types/components/form/NativeSelect/useNativeSelect.d.ts.map +1 -1
- package/dist/types/components/form/Radio/{Group/Group.d.ts → RadioGroup.d.ts} +7 -7
- package/dist/types/components/form/Radio/RadioGroup.d.ts.map +1 -0
- package/dist/types/components/form/Radio/index.d.ts +2 -2
- package/dist/types/components/form/Radio/index.d.ts.map +1 -1
- package/dist/types/components/form/Radio/useRadio.d.ts.map +1 -1
- package/dist/types/components/form/Search/Search.d.ts +7 -7
- package/dist/types/components/form/Search/Search.d.ts.map +1 -1
- package/dist/types/components/form/Switch/Switch.d.ts +2 -2
- package/dist/types/components/form/Switch/Switch.d.ts.map +1 -1
- package/dist/types/components/form/Textarea/Textarea.d.ts +7 -7
- package/dist/types/components/form/Textarea/Textarea.d.ts.map +1 -1
- package/dist/types/components/form/Textfield/Textfield.d.ts +7 -7
- package/dist/types/components/form/Textfield/Textfield.d.ts.map +1 -1
- package/dist/types/components/index.d.ts +1 -0
- package/dist/types/components/index.d.ts.map +1 -1
- package/dist/types/utilities/AnimateHeight/AnimateHeight.d.ts.map +1 -1
- package/dist/types/utilities/RovingFocus/RovingFocusItem.d.ts +2 -2
- package/dist/types/utilities/RovingFocus/RovingFocusItem.d.ts.map +1 -1
- package/dist/types/utilities/RovingFocus/RovingFocusRoot.d.ts +10 -2
- package/dist/types/utilities/RovingFocus/RovingFocusRoot.d.ts.map +1 -1
- package/dist/types/utilities/RovingFocus/useRovingFocus.d.ts +11 -10
- package/dist/types/utilities/RovingFocus/useRovingFocus.d.ts.map +1 -1
- package/package.json +18 -8
- package/dist/cjs/node_modules/@babel/runtime/helpers/esm/extends.js +0 -19
- package/dist/esm/node_modules/@babel/runtime/helpers/esm/extends.js +0 -17
- package/dist/types/components/form/Checkbox/Group/Group.d.ts.map +0 -1
- package/dist/types/components/form/Checkbox/Group/index.d.ts +0 -2
- package/dist/types/components/form/Checkbox/Group/index.d.ts.map +0 -1
- package/dist/types/components/form/Radio/Group/Group.d.ts.map +0 -1
- package/dist/types/components/form/Radio/Group/index.d.ts +0 -2
- package/dist/types/components/form/Radio/Group/index.d.ts.map +0 -1
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { useLayoutEffect, useEffect, useRef } from 'react';
|
|
4
4
|
import { getDocument, isMouseLikePointerType, isTypeableCombobox, activeElement, contains, isVirtualClick, isVirtualPointerEvent, getTarget, isSafari, isMac, isTypeableElement, stopEvent, isReactEvent, isRootElement, isEventTargetWithin } from './floating-ui.react.utils.js';
|
|
5
|
-
import { floor } from '
|
|
6
|
-
import {
|
|
7
|
-
export { arrow } from '../../react-dom/dist/floating-ui.react-dom.js';
|
|
8
|
-
import { isElement, isHTMLElement, getOverflowAncestors, getWindow, getNodeName, isLastTraversableNode, getParentNode, getComputedStyle } from '../../utils/dist/floating-ui.utils.dom.js';
|
|
5
|
+
import { floor } from '../node_modules/@floating-ui/utils/dist/floating-ui.utils.js';
|
|
6
|
+
import { getComputedStyle, isElement, isHTMLElement, getWindow, getNodeName, isLastTraversableNode, getParentNode } from '../node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js';
|
|
9
7
|
import { tabbable, isTabbable } from '../../../tabbable/dist/index.esm.js';
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
export {
|
|
8
|
+
import * as ReactDOM from 'react-dom';
|
|
9
|
+
import { useFloating as useFloating$1 } from '../../react-dom/dist/floating-ui.react-dom.js';
|
|
10
|
+
export { arrow, flip, offset, shift, size } from '../../react-dom/dist/floating-ui.react-dom.js';
|
|
11
|
+
import { getOverflowAncestors } from '../../utils/dist/floating-ui.utils.dom.js';
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
14
|
* Merges an array of refs into a single memoized callback ref or `null`.
|
|
@@ -87,14 +86,10 @@ function findNonDisabledIndex(listRef, _temp) {
|
|
|
87
86
|
amount = 1
|
|
88
87
|
} = _temp === void 0 ? {} : _temp;
|
|
89
88
|
const list = listRef.current;
|
|
90
|
-
const isDisabledIndex = disabledIndices ? index => disabledIndices.includes(index) : index => {
|
|
91
|
-
const element = list[index];
|
|
92
|
-
return element == null || element.hasAttribute('disabled') || element.getAttribute('aria-disabled') === 'true';
|
|
93
|
-
};
|
|
94
89
|
let index = startingIndex;
|
|
95
90
|
do {
|
|
96
91
|
index += decrement ? -amount : amount;
|
|
97
|
-
} while (index >= 0 && index <= list.length - 1 &&
|
|
92
|
+
} while (index >= 0 && index <= list.length - 1 && isDisabled(list, index, disabledIndices));
|
|
98
93
|
return index;
|
|
99
94
|
}
|
|
100
95
|
function getGridNavigatedIndex(elementsRef, _ref) {
|
|
@@ -190,8 +185,8 @@ function getGridNavigatedIndex(elementsRef, _ref) {
|
|
|
190
185
|
if (prevIndex % cols !== 0) {
|
|
191
186
|
nextIndex = findNonDisabledIndex(elementsRef, {
|
|
192
187
|
startingIndex: prevIndex,
|
|
193
|
-
|
|
194
|
-
|
|
188
|
+
decrement: true,
|
|
189
|
+
disabledIndices
|
|
195
190
|
});
|
|
196
191
|
if (loop && isDifferentRow(nextIndex, cols, prevRow)) {
|
|
197
192
|
nextIndex = findNonDisabledIndex(elementsRef, {
|
|
@@ -270,13 +265,20 @@ function buildCellMap(sizes, cols, dense) {
|
|
|
270
265
|
function getCellIndexOfCorner(index, sizes, cellMap, cols, corner) {
|
|
271
266
|
if (index === -1) return -1;
|
|
272
267
|
const firstCellIndex = cellMap.indexOf(index);
|
|
268
|
+
const sizeItem = sizes[index];
|
|
273
269
|
switch (corner) {
|
|
274
270
|
case 'tl':
|
|
275
271
|
return firstCellIndex;
|
|
276
272
|
case 'tr':
|
|
277
|
-
|
|
273
|
+
if (!sizeItem) {
|
|
274
|
+
return firstCellIndex;
|
|
275
|
+
}
|
|
276
|
+
return firstCellIndex + sizeItem.width - 1;
|
|
278
277
|
case 'bl':
|
|
279
|
-
|
|
278
|
+
if (!sizeItem) {
|
|
279
|
+
return firstCellIndex;
|
|
280
|
+
}
|
|
281
|
+
return firstCellIndex + (sizeItem.height - 1) * cols;
|
|
280
282
|
case 'br':
|
|
281
283
|
return cellMap.lastIndexOf(index);
|
|
282
284
|
}
|
|
@@ -286,6 +288,13 @@ function getCellIndexOfCorner(index, sizes, cellMap, cols, corner) {
|
|
|
286
288
|
function getCellIndices(indices, cellMap) {
|
|
287
289
|
return cellMap.flatMap((index, cellIndex) => indices.includes(index) ? [cellIndex] : []);
|
|
288
290
|
}
|
|
291
|
+
function isDisabled(list, index, disabledIndices) {
|
|
292
|
+
if (disabledIndices) {
|
|
293
|
+
return disabledIndices.includes(index);
|
|
294
|
+
}
|
|
295
|
+
const element = list[index];
|
|
296
|
+
return element == null || element.hasAttribute('disabled') || element.getAttribute('aria-disabled') === 'true';
|
|
297
|
+
}
|
|
289
298
|
|
|
290
299
|
let rafId = 0;
|
|
291
300
|
function enqueueFocus(el, options) {
|
|
@@ -416,6 +425,16 @@ const FloatingArrow = /*#__PURE__*/React.forwardRef(function FloatingArrow(props
|
|
|
416
425
|
}
|
|
417
426
|
}
|
|
418
427
|
const clipPathId = useId();
|
|
428
|
+
const [isRTL, setIsRTL] = React.useState(false);
|
|
429
|
+
|
|
430
|
+
// https://github.com/floating-ui/floating-ui/issues/2932
|
|
431
|
+
index(() => {
|
|
432
|
+
if (!floating) return;
|
|
433
|
+
const isRTL = getComputedStyle(floating).direction === 'rtl';
|
|
434
|
+
if (isRTL) {
|
|
435
|
+
setIsRTL(true);
|
|
436
|
+
}
|
|
437
|
+
}, [floating]);
|
|
419
438
|
if (!floating) {
|
|
420
439
|
return null;
|
|
421
440
|
}
|
|
@@ -427,7 +446,6 @@ const FloatingArrow = /*#__PURE__*/React.forwardRef(function FloatingArrow(props
|
|
|
427
446
|
const svgX = width / 2 * (tipRadius / -8 + 1);
|
|
428
447
|
const svgY = height / 2 * tipRadius / 4;
|
|
429
448
|
const [side, alignment] = placement.split('-');
|
|
430
|
-
const isRTL = platform.isRTL(floating);
|
|
431
449
|
const isCustomShape = !!d;
|
|
432
450
|
const isVerticalSide = side === 'top' || side === 'bottom';
|
|
433
451
|
const yOffsetProp = staticOffset && alignment === 'end' ? 'bottom' : 'top';
|
|
@@ -550,11 +568,7 @@ function useHover(context, props) {
|
|
|
550
568
|
onOpenChange,
|
|
551
569
|
dataRef,
|
|
552
570
|
events,
|
|
553
|
-
elements
|
|
554
|
-
domReference,
|
|
555
|
-
floating
|
|
556
|
-
},
|
|
557
|
-
refs
|
|
571
|
+
elements
|
|
558
572
|
} = context;
|
|
559
573
|
const {
|
|
560
574
|
enabled = true,
|
|
@@ -568,10 +582,11 @@ function useHover(context, props) {
|
|
|
568
582
|
const parentId = useFloatingParentNodeId();
|
|
569
583
|
const handleCloseRef = useLatestRef(handleClose);
|
|
570
584
|
const delayRef = useLatestRef(delay);
|
|
585
|
+
const openRef = useLatestRef(open);
|
|
571
586
|
const pointerTypeRef = React.useRef();
|
|
572
|
-
const timeoutRef = React.useRef();
|
|
587
|
+
const timeoutRef = React.useRef(-1);
|
|
573
588
|
const handlerRef = React.useRef();
|
|
574
|
-
const restTimeoutRef = React.useRef();
|
|
589
|
+
const restTimeoutRef = React.useRef(-1);
|
|
575
590
|
const blockMouseMoveRef = React.useRef(true);
|
|
576
591
|
const performedPointerEventsMutationRef = React.useRef(false);
|
|
577
592
|
const unbindMouseMoveRef = React.useRef(() => {});
|
|
@@ -584,9 +599,7 @@ function useHover(context, props) {
|
|
|
584
599
|
// When closing before opening, clear the delay timeouts to cancel it
|
|
585
600
|
// from showing.
|
|
586
601
|
React.useEffect(() => {
|
|
587
|
-
if (!enabled)
|
|
588
|
-
return;
|
|
589
|
-
}
|
|
602
|
+
if (!enabled) return;
|
|
590
603
|
function onOpenChange(_ref) {
|
|
591
604
|
let {
|
|
592
605
|
open
|
|
@@ -603,20 +616,20 @@ function useHover(context, props) {
|
|
|
603
616
|
};
|
|
604
617
|
}, [enabled, events]);
|
|
605
618
|
React.useEffect(() => {
|
|
606
|
-
if (!enabled
|
|
607
|
-
|
|
608
|
-
|
|
619
|
+
if (!enabled) return;
|
|
620
|
+
if (!handleCloseRef.current) return;
|
|
621
|
+
if (!open) return;
|
|
609
622
|
function onLeave(event) {
|
|
610
623
|
if (isHoverOpen()) {
|
|
611
624
|
onOpenChange(false, event, 'hover');
|
|
612
625
|
}
|
|
613
626
|
}
|
|
614
|
-
const html = getDocument(floating).documentElement;
|
|
627
|
+
const html = getDocument(elements.floating).documentElement;
|
|
615
628
|
html.addEventListener('mouseleave', onLeave);
|
|
616
629
|
return () => {
|
|
617
630
|
html.removeEventListener('mouseleave', onLeave);
|
|
618
631
|
};
|
|
619
|
-
}, [floating, open, onOpenChange, enabled, handleCloseRef, isHoverOpen]);
|
|
632
|
+
}, [elements.floating, open, onOpenChange, enabled, handleCloseRef, isHoverOpen]);
|
|
620
633
|
const closeWithDelay = React.useCallback(function (event, runElseBranch, reason) {
|
|
621
634
|
if (runElseBranch === void 0) {
|
|
622
635
|
runElseBranch = true;
|
|
@@ -627,64 +640,62 @@ function useHover(context, props) {
|
|
|
627
640
|
const closeDelay = getDelay(delayRef.current, 'close', pointerTypeRef.current);
|
|
628
641
|
if (closeDelay && !handlerRef.current) {
|
|
629
642
|
clearTimeout(timeoutRef.current);
|
|
630
|
-
timeoutRef.current = setTimeout(() => onOpenChange(false, event, reason), closeDelay);
|
|
643
|
+
timeoutRef.current = window.setTimeout(() => onOpenChange(false, event, reason), closeDelay);
|
|
631
644
|
} else if (runElseBranch) {
|
|
632
645
|
clearTimeout(timeoutRef.current);
|
|
633
646
|
onOpenChange(false, event, reason);
|
|
634
647
|
}
|
|
635
648
|
}, [delayRef, onOpenChange]);
|
|
636
|
-
const cleanupMouseMoveHandler =
|
|
649
|
+
const cleanupMouseMoveHandler = useEffectEvent(() => {
|
|
637
650
|
unbindMouseMoveRef.current();
|
|
638
651
|
handlerRef.current = undefined;
|
|
639
|
-
}
|
|
640
|
-
const clearPointerEvents =
|
|
652
|
+
});
|
|
653
|
+
const clearPointerEvents = useEffectEvent(() => {
|
|
641
654
|
if (performedPointerEventsMutationRef.current) {
|
|
642
|
-
const body = getDocument(
|
|
655
|
+
const body = getDocument(elements.floating).body;
|
|
643
656
|
body.style.pointerEvents = '';
|
|
644
657
|
body.removeAttribute(safePolygonIdentifier);
|
|
645
658
|
performedPointerEventsMutationRef.current = false;
|
|
646
659
|
}
|
|
647
|
-
}
|
|
660
|
+
});
|
|
648
661
|
|
|
649
662
|
// Registering the mouse events on the reference directly to bypass React's
|
|
650
663
|
// delegation system. If the cursor was on a disabled element and then entered
|
|
651
664
|
// the reference (no gap), `mouseenter` doesn't fire in the delegation system.
|
|
652
665
|
React.useEffect(() => {
|
|
653
|
-
if (!enabled)
|
|
654
|
-
return;
|
|
655
|
-
}
|
|
666
|
+
if (!enabled) return;
|
|
656
667
|
function isClickLikeOpenEvent() {
|
|
657
668
|
return dataRef.current.openEvent ? ['click', 'mousedown'].includes(dataRef.current.openEvent.type) : false;
|
|
658
669
|
}
|
|
659
670
|
function onMouseEnter(event) {
|
|
660
671
|
clearTimeout(timeoutRef.current);
|
|
661
672
|
blockMouseMoveRef.current = false;
|
|
662
|
-
if (mouseOnly && !isMouseLikePointerType(pointerTypeRef.current) || restMs > 0 && getDelay(delayRef.current, 'open')
|
|
673
|
+
if (mouseOnly && !isMouseLikePointerType(pointerTypeRef.current) || restMs > 0 && !getDelay(delayRef.current, 'open')) {
|
|
663
674
|
return;
|
|
664
675
|
}
|
|
665
676
|
const openDelay = getDelay(delayRef.current, 'open', pointerTypeRef.current);
|
|
666
677
|
if (openDelay) {
|
|
667
|
-
timeoutRef.current = setTimeout(() => {
|
|
668
|
-
|
|
678
|
+
timeoutRef.current = window.setTimeout(() => {
|
|
679
|
+
if (!openRef.current) {
|
|
680
|
+
onOpenChange(true, event, 'hover');
|
|
681
|
+
}
|
|
669
682
|
}, openDelay);
|
|
670
683
|
} else {
|
|
671
684
|
onOpenChange(true, event, 'hover');
|
|
672
685
|
}
|
|
673
686
|
}
|
|
674
687
|
function onMouseLeave(event) {
|
|
675
|
-
if (isClickLikeOpenEvent())
|
|
676
|
-
return;
|
|
677
|
-
}
|
|
688
|
+
if (isClickLikeOpenEvent()) return;
|
|
678
689
|
unbindMouseMoveRef.current();
|
|
679
|
-
const doc = getDocument(floating);
|
|
690
|
+
const doc = getDocument(elements.floating);
|
|
680
691
|
clearTimeout(restTimeoutRef.current);
|
|
681
|
-
if (handleCloseRef.current) {
|
|
692
|
+
if (handleCloseRef.current && dataRef.current.floatingContext) {
|
|
682
693
|
// Prevent clearing `onScrollMouseLeave` timeout.
|
|
683
694
|
if (!open) {
|
|
684
695
|
clearTimeout(timeoutRef.current);
|
|
685
696
|
}
|
|
686
697
|
handlerRef.current = handleCloseRef.current({
|
|
687
|
-
...
|
|
698
|
+
...dataRef.current.floatingContext,
|
|
688
699
|
tree,
|
|
689
700
|
x: event.clientX,
|
|
690
701
|
y: event.clientY,
|
|
@@ -705,7 +716,7 @@ function useHover(context, props) {
|
|
|
705
716
|
// Allow interactivity without `safePolygon` on touch devices. With a
|
|
706
717
|
// pointer, a short close delay is an alternative, so it should work
|
|
707
718
|
// consistently.
|
|
708
|
-
const shouldClose = pointerTypeRef.current === 'touch' ? !contains(floating, event.relatedTarget) : true;
|
|
719
|
+
const shouldClose = pointerTypeRef.current === 'touch' ? !contains(elements.floating, event.relatedTarget) : true;
|
|
709
720
|
if (shouldClose) {
|
|
710
721
|
closeWithDelay(event);
|
|
711
722
|
}
|
|
@@ -715,11 +726,10 @@ function useHover(context, props) {
|
|
|
715
726
|
// did not move.
|
|
716
727
|
// https://github.com/floating-ui/floating-ui/discussions/1692
|
|
717
728
|
function onScrollMouseLeave(event) {
|
|
718
|
-
if (isClickLikeOpenEvent())
|
|
719
|
-
|
|
720
|
-
}
|
|
729
|
+
if (isClickLikeOpenEvent()) return;
|
|
730
|
+
if (!dataRef.current.floatingContext) return;
|
|
721
731
|
handleCloseRef.current == null || handleCloseRef.current({
|
|
722
|
-
...
|
|
732
|
+
...dataRef.current.floatingContext,
|
|
723
733
|
tree,
|
|
724
734
|
x: event.clientX,
|
|
725
735
|
y: event.clientY,
|
|
@@ -730,24 +740,26 @@ function useHover(context, props) {
|
|
|
730
740
|
}
|
|
731
741
|
})(event);
|
|
732
742
|
}
|
|
733
|
-
if (isElement(domReference)) {
|
|
734
|
-
|
|
743
|
+
if (isElement(elements.domReference)) {
|
|
744
|
+
var _elements$floating;
|
|
745
|
+
const ref = elements.domReference;
|
|
735
746
|
open && ref.addEventListener('mouseleave', onScrollMouseLeave);
|
|
736
|
-
floating == null || floating.addEventListener('mouseleave', onScrollMouseLeave);
|
|
747
|
+
(_elements$floating = elements.floating) == null || _elements$floating.addEventListener('mouseleave', onScrollMouseLeave);
|
|
737
748
|
move && ref.addEventListener('mousemove', onMouseEnter, {
|
|
738
749
|
once: true
|
|
739
750
|
});
|
|
740
751
|
ref.addEventListener('mouseenter', onMouseEnter);
|
|
741
752
|
ref.addEventListener('mouseleave', onMouseLeave);
|
|
742
753
|
return () => {
|
|
754
|
+
var _elements$floating2;
|
|
743
755
|
open && ref.removeEventListener('mouseleave', onScrollMouseLeave);
|
|
744
|
-
floating == null ||
|
|
756
|
+
(_elements$floating2 = elements.floating) == null || _elements$floating2.removeEventListener('mouseleave', onScrollMouseLeave);
|
|
745
757
|
move && ref.removeEventListener('mousemove', onMouseEnter);
|
|
746
758
|
ref.removeEventListener('mouseenter', onMouseEnter);
|
|
747
759
|
ref.removeEventListener('mouseleave', onMouseLeave);
|
|
748
760
|
};
|
|
749
761
|
}
|
|
750
|
-
}, [
|
|
762
|
+
}, [elements, enabled, context, mouseOnly, restMs, move, closeWithDelay, cleanupMouseMoveHandler, clearPointerEvents, onOpenChange, open, openRef, tree, delayRef, handleCloseRef, dataRef]);
|
|
751
763
|
|
|
752
764
|
// Block pointer-events of every element other than the reference and floating
|
|
753
765
|
// while the floating element is open and has a `handleClose` handler. Also
|
|
@@ -755,30 +767,29 @@ function useHover(context, props) {
|
|
|
755
767
|
// https://github.com/floating-ui/floating-ui/issues/1722
|
|
756
768
|
index(() => {
|
|
757
769
|
var _handleCloseRef$curre;
|
|
758
|
-
if (!enabled)
|
|
759
|
-
return;
|
|
760
|
-
}
|
|
770
|
+
if (!enabled) return;
|
|
761
771
|
if (open && (_handleCloseRef$curre = handleCloseRef.current) != null && _handleCloseRef$curre.__options.blockPointerEvents && isHoverOpen()) {
|
|
762
|
-
const body = getDocument(floating).body;
|
|
772
|
+
const body = getDocument(elements.floating).body;
|
|
763
773
|
body.setAttribute(safePolygonIdentifier, '');
|
|
764
774
|
body.style.pointerEvents = 'none';
|
|
765
775
|
performedPointerEventsMutationRef.current = true;
|
|
766
|
-
|
|
776
|
+
const floatingEl = elements.floating;
|
|
777
|
+
if (isElement(elements.domReference) && floatingEl) {
|
|
767
778
|
var _tree$nodesRef$curren;
|
|
768
|
-
const ref = domReference;
|
|
779
|
+
const ref = elements.domReference;
|
|
769
780
|
const parentFloating = tree == null || (_tree$nodesRef$curren = tree.nodesRef.current.find(node => node.id === parentId)) == null || (_tree$nodesRef$curren = _tree$nodesRef$curren.context) == null ? void 0 : _tree$nodesRef$curren.elements.floating;
|
|
770
781
|
if (parentFloating) {
|
|
771
782
|
parentFloating.style.pointerEvents = '';
|
|
772
783
|
}
|
|
773
784
|
ref.style.pointerEvents = 'auto';
|
|
774
|
-
|
|
785
|
+
floatingEl.style.pointerEvents = 'auto';
|
|
775
786
|
return () => {
|
|
776
787
|
ref.style.pointerEvents = '';
|
|
777
|
-
|
|
788
|
+
floatingEl.style.pointerEvents = '';
|
|
778
789
|
};
|
|
779
790
|
}
|
|
780
791
|
}
|
|
781
|
-
}, [enabled, open, parentId,
|
|
792
|
+
}, [enabled, open, parentId, elements, tree, handleCloseRef, isHoverOpen]);
|
|
782
793
|
index(() => {
|
|
783
794
|
if (!open) {
|
|
784
795
|
pointerTypeRef.current = undefined;
|
|
@@ -793,48 +804,50 @@ function useHover(context, props) {
|
|
|
793
804
|
clearTimeout(restTimeoutRef.current);
|
|
794
805
|
clearPointerEvents();
|
|
795
806
|
};
|
|
796
|
-
}, [enabled, domReference, cleanupMouseMoveHandler, clearPointerEvents]);
|
|
797
|
-
|
|
798
|
-
if (!enabled) {
|
|
799
|
-
return {};
|
|
800
|
-
}
|
|
807
|
+
}, [enabled, elements.domReference, cleanupMouseMoveHandler, clearPointerEvents]);
|
|
808
|
+
const reference = React.useMemo(() => {
|
|
801
809
|
function setPointerRef(event) {
|
|
802
810
|
pointerTypeRef.current = event.pointerType;
|
|
803
811
|
}
|
|
804
812
|
return {
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
if (mouseOnly && !isMouseLikePointerType(pointerTypeRef.current)) {
|
|
815
|
-
return;
|
|
816
|
-
}
|
|
817
|
-
if (open || restMs === 0) {
|
|
818
|
-
return;
|
|
819
|
-
}
|
|
820
|
-
clearTimeout(restTimeoutRef.current);
|
|
821
|
-
if (pointerTypeRef.current === 'touch') {
|
|
822
|
-
handleMouseMove();
|
|
823
|
-
} else {
|
|
824
|
-
restTimeoutRef.current = setTimeout(handleMouseMove, restMs);
|
|
813
|
+
onPointerDown: setPointerRef,
|
|
814
|
+
onPointerEnter: setPointerRef,
|
|
815
|
+
onMouseMove(event) {
|
|
816
|
+
const {
|
|
817
|
+
nativeEvent
|
|
818
|
+
} = event;
|
|
819
|
+
function handleMouseMove() {
|
|
820
|
+
if (!blockMouseMoveRef.current && !openRef.current) {
|
|
821
|
+
onOpenChange(true, nativeEvent, 'hover');
|
|
825
822
|
}
|
|
826
823
|
}
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
824
|
+
if (mouseOnly && !isMouseLikePointerType(pointerTypeRef.current)) {
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
if (open || restMs === 0) {
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
clearTimeout(restTimeoutRef.current);
|
|
831
|
+
if (pointerTypeRef.current === 'touch') {
|
|
832
|
+
handleMouseMove();
|
|
833
|
+
} else {
|
|
834
|
+
restTimeoutRef.current = window.setTimeout(handleMouseMove, restMs);
|
|
834
835
|
}
|
|
835
836
|
}
|
|
836
837
|
};
|
|
837
|
-
}, [
|
|
838
|
+
}, [mouseOnly, onOpenChange, open, openRef, restMs]);
|
|
839
|
+
const floating = React.useMemo(() => ({
|
|
840
|
+
onMouseEnter() {
|
|
841
|
+
clearTimeout(timeoutRef.current);
|
|
842
|
+
},
|
|
843
|
+
onMouseLeave(event) {
|
|
844
|
+
closeWithDelay(event.nativeEvent, false);
|
|
845
|
+
}
|
|
846
|
+
}), [closeWithDelay]);
|
|
847
|
+
return React.useMemo(() => enabled ? {
|
|
848
|
+
reference,
|
|
849
|
+
floating
|
|
850
|
+
} : {}, [enabled, reference, floating]);
|
|
838
851
|
}
|
|
839
852
|
|
|
840
853
|
function getAncestors(nodes, id) {
|
|
@@ -929,7 +942,8 @@ function applyAttributeToOthers(uncorrectedAvoidElements, body, ariaHidden, iner
|
|
|
929
942
|
if (!parent || elementsToStop.has(parent)) {
|
|
930
943
|
return;
|
|
931
944
|
}
|
|
932
|
-
|
|
945
|
+
[].forEach.call(parent.children, node => {
|
|
946
|
+
if (getNodeName(node) === 'script') return;
|
|
933
947
|
if (elementsToKeep.has(node)) {
|
|
934
948
|
deep(node);
|
|
935
949
|
} else {
|
|
@@ -1036,6 +1050,32 @@ function enableFocusInside(container) {
|
|
|
1036
1050
|
}
|
|
1037
1051
|
});
|
|
1038
1052
|
}
|
|
1053
|
+
function getClosestTabbableElement(tabbableElements, element, floating) {
|
|
1054
|
+
const elementIndex = tabbableElements.indexOf(element);
|
|
1055
|
+
function traverseTabbableElements(next) {
|
|
1056
|
+
const attr = createAttribute('focus-guard');
|
|
1057
|
+
let index = elementIndex + (next ? 1 : 0);
|
|
1058
|
+
let currentElement = tabbableElements[index];
|
|
1059
|
+
while (currentElement && (!currentElement.isConnected || currentElement.hasAttribute(attr) || contains(floating, currentElement))) {
|
|
1060
|
+
if (next) {
|
|
1061
|
+
index++;
|
|
1062
|
+
} else {
|
|
1063
|
+
index--;
|
|
1064
|
+
}
|
|
1065
|
+
currentElement = tabbableElements[index];
|
|
1066
|
+
}
|
|
1067
|
+
return currentElement;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
// First, try to find the next tabbable element
|
|
1071
|
+
const next = traverseTabbableElements(true);
|
|
1072
|
+
if (next) {
|
|
1073
|
+
return next;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
// If we can't find a next tabbable element, try to find the previous one
|
|
1077
|
+
return traverseTabbableElements(false);
|
|
1078
|
+
}
|
|
1039
1079
|
|
|
1040
1080
|
// See Diego Haz's Sandbox for making this logic work well on Safari/iOS:
|
|
1041
1081
|
// https://codesandbox.io/s/tabbable-portal-f4tng?file=/src/FocusTrap.tsx
|
|
@@ -1090,7 +1130,6 @@ const FocusGuard = /*#__PURE__*/React.forwardRef(function FocusGuard(props, ref)
|
|
|
1090
1130
|
|
|
1091
1131
|
const PortalContext = /*#__PURE__*/React.createContext(null);
|
|
1092
1132
|
const attr = /*#__PURE__*/createAttribute('portal');
|
|
1093
|
-
|
|
1094
1133
|
/**
|
|
1095
1134
|
* @see https://floating-ui.com/docs/FloatingPortal#usefloatingportalnode
|
|
1096
1135
|
*/
|
|
@@ -1118,6 +1157,10 @@ function useFloatingPortalNode(props) {
|
|
|
1118
1157
|
};
|
|
1119
1158
|
}, [portalNode]);
|
|
1120
1159
|
index(() => {
|
|
1160
|
+
// Wait for the uniqueId to be generated before creating the portal node in
|
|
1161
|
+
// React <18 (using `useFloatingId` instead of the native `useId`).
|
|
1162
|
+
// https://github.com/floating-ui/floating-ui/issues/2778
|
|
1163
|
+
if (!uniqueId) return;
|
|
1121
1164
|
if (portalNodeRef.current) return;
|
|
1122
1165
|
const existingIdRoot = id ? document.getElementById(id) : null;
|
|
1123
1166
|
if (!existingIdRoot) return;
|
|
@@ -1129,6 +1172,7 @@ function useFloatingPortalNode(props) {
|
|
|
1129
1172
|
setPortalNode(subRoot);
|
|
1130
1173
|
}, [id, uniqueId]);
|
|
1131
1174
|
index(() => {
|
|
1175
|
+
if (!uniqueId) return;
|
|
1132
1176
|
if (portalNodeRef.current) return;
|
|
1133
1177
|
let container = root || (portalContext == null ? void 0 : portalContext.portalNode);
|
|
1134
1178
|
if (container && !isElement(container)) container = container.current;
|
|
@@ -1232,7 +1276,7 @@ function FloatingPortal(props) {
|
|
|
1232
1276
|
}), shouldRenderGuards && portalNode && /*#__PURE__*/React.createElement("span", {
|
|
1233
1277
|
"aria-owns": portalNode.id,
|
|
1234
1278
|
style: HIDDEN_STYLES
|
|
1235
|
-
}), portalNode && /*#__PURE__*/createPortal(children, portalNode), shouldRenderGuards && portalNode && /*#__PURE__*/React.createElement(FocusGuard, {
|
|
1279
|
+
}), portalNode && /*#__PURE__*/ReactDOM.createPortal(children, portalNode), shouldRenderGuards && portalNode && /*#__PURE__*/React.createElement(FocusGuard, {
|
|
1236
1280
|
"data-type": "outside",
|
|
1237
1281
|
ref: afterOutsideRef,
|
|
1238
1282
|
onFocus: event => {
|
|
@@ -1257,8 +1301,9 @@ function addPreviouslyFocusedElement(element) {
|
|
|
1257
1301
|
if (!tabbableEl || getNodeName(tabbableEl) === 'body') return;
|
|
1258
1302
|
if (!isTabbable(tabbableEl, getTabbableOptions())) {
|
|
1259
1303
|
const tabbableChild = tabbable(tabbableEl, getTabbableOptions())[0];
|
|
1260
|
-
if (
|
|
1261
|
-
|
|
1304
|
+
if (tabbableChild) {
|
|
1305
|
+
tabbableEl = tabbableChild;
|
|
1306
|
+
}
|
|
1262
1307
|
}
|
|
1263
1308
|
previouslyFocusedElements.push(tabbableEl);
|
|
1264
1309
|
if (previouslyFocusedElements.length > LIST_LIMIT) {
|
|
@@ -1289,6 +1334,7 @@ function FloatingFocusManager(props) {
|
|
|
1289
1334
|
guards: _guards = true,
|
|
1290
1335
|
initialFocus = 0,
|
|
1291
1336
|
returnFocus = true,
|
|
1337
|
+
restoreFocus = false,
|
|
1292
1338
|
modal = true,
|
|
1293
1339
|
visuallyHiddenDismiss = false,
|
|
1294
1340
|
closeOnFocusOut = true
|
|
@@ -1300,6 +1346,7 @@ function FloatingFocusManager(props) {
|
|
|
1300
1346
|
onOpenChange,
|
|
1301
1347
|
events,
|
|
1302
1348
|
dataRef,
|
|
1349
|
+
floatingId,
|
|
1303
1350
|
elements: {
|
|
1304
1351
|
domReference,
|
|
1305
1352
|
floating
|
|
@@ -1324,31 +1371,37 @@ function FloatingFocusManager(props) {
|
|
|
1324
1371
|
const endDismissButtonRef = React.useRef(null);
|
|
1325
1372
|
const preventReturnFocusRef = React.useRef(false);
|
|
1326
1373
|
const isPointerDownRef = React.useRef(false);
|
|
1374
|
+
const tabbableIndexRef = React.useRef(-1);
|
|
1327
1375
|
const isInsidePortal = portalContext != null;
|
|
1328
|
-
const
|
|
1376
|
+
const firstElementChild = floating == null ? void 0 : floating.firstElementChild;
|
|
1377
|
+
// If the floating element is acting as a positioning wrapper rather than the
|
|
1378
|
+
// element that receives aria props, use it as the focus root instead.
|
|
1379
|
+
const floatingFocusNode = (firstElementChild == null ? void 0 : firstElementChild.id) === floatingId ? firstElementChild : floating;
|
|
1380
|
+
const getTabbableContent = useEffectEvent(function (container) {
|
|
1329
1381
|
if (container === void 0) {
|
|
1330
|
-
container =
|
|
1382
|
+
container = floatingFocusNode;
|
|
1331
1383
|
}
|
|
1332
1384
|
return container ? tabbable(container, getTabbableOptions()) : [];
|
|
1333
|
-
}
|
|
1334
|
-
const getTabbableElements =
|
|
1385
|
+
});
|
|
1386
|
+
const getTabbableElements = useEffectEvent(container => {
|
|
1335
1387
|
const content = getTabbableContent(container);
|
|
1336
1388
|
return orderRef.current.map(type => {
|
|
1337
1389
|
if (domReference && type === 'reference') {
|
|
1338
1390
|
return domReference;
|
|
1339
1391
|
}
|
|
1340
|
-
if (
|
|
1341
|
-
return
|
|
1392
|
+
if (floatingFocusNode && type === 'floating') {
|
|
1393
|
+
return floatingFocusNode;
|
|
1342
1394
|
}
|
|
1343
1395
|
return content;
|
|
1344
1396
|
}).filter(Boolean).flat();
|
|
1345
|
-
}
|
|
1397
|
+
});
|
|
1346
1398
|
React.useEffect(() => {
|
|
1347
|
-
if (disabled
|
|
1399
|
+
if (disabled) return;
|
|
1400
|
+
if (!modal) return;
|
|
1348
1401
|
function onKeyDown(event) {
|
|
1349
1402
|
if (event.key === 'Tab') {
|
|
1350
1403
|
// The focus guards have nothing to focus, so we need to stop the event.
|
|
1351
|
-
if (contains(
|
|
1404
|
+
if (contains(floatingFocusNode, activeElement(getDocument(floatingFocusNode))) && getTabbableContent().length === 0 && !isUntrappedTypeableCombobox) {
|
|
1352
1405
|
stopEvent(event);
|
|
1353
1406
|
}
|
|
1354
1407
|
const els = getTabbableElements();
|
|
@@ -1361,20 +1414,37 @@ function FloatingFocusManager(props) {
|
|
|
1361
1414
|
enqueueFocus(els[1]);
|
|
1362
1415
|
}
|
|
1363
1416
|
}
|
|
1364
|
-
if (orderRef.current[1] === 'floating' && target ===
|
|
1417
|
+
if (orderRef.current[1] === 'floating' && target === floatingFocusNode && event.shiftKey) {
|
|
1365
1418
|
stopEvent(event);
|
|
1366
1419
|
enqueueFocus(els[0]);
|
|
1367
1420
|
}
|
|
1368
1421
|
}
|
|
1369
1422
|
}
|
|
1370
|
-
const doc = getDocument(
|
|
1423
|
+
const doc = getDocument(floatingFocusNode);
|
|
1371
1424
|
doc.addEventListener('keydown', onKeyDown);
|
|
1372
1425
|
return () => {
|
|
1373
1426
|
doc.removeEventListener('keydown', onKeyDown);
|
|
1374
1427
|
};
|
|
1375
|
-
}, [disabled, domReference,
|
|
1428
|
+
}, [disabled, domReference, floatingFocusNode, modal, orderRef, isUntrappedTypeableCombobox, getTabbableContent, getTabbableElements]);
|
|
1429
|
+
React.useEffect(() => {
|
|
1430
|
+
if (disabled) return;
|
|
1431
|
+
if (!floating) return;
|
|
1432
|
+
function handleFocusIn(event) {
|
|
1433
|
+
const target = getTarget(event);
|
|
1434
|
+
const tabbableContent = getTabbableContent();
|
|
1435
|
+
const tabbableIndex = tabbableContent.indexOf(target);
|
|
1436
|
+
if (tabbableIndex !== -1) {
|
|
1437
|
+
tabbableIndexRef.current = tabbableIndex;
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
floating.addEventListener('focusin', handleFocusIn);
|
|
1441
|
+
return () => {
|
|
1442
|
+
floating.removeEventListener('focusin', handleFocusIn);
|
|
1443
|
+
};
|
|
1444
|
+
}, [disabled, floating, getTabbableContent]);
|
|
1376
1445
|
React.useEffect(() => {
|
|
1377
|
-
if (disabled
|
|
1446
|
+
if (disabled) return;
|
|
1447
|
+
if (!closeOnFocusOut) return;
|
|
1378
1448
|
|
|
1379
1449
|
// In Safari, buttons lose focus when pressing them.
|
|
1380
1450
|
function handlePointerDown() {
|
|
@@ -1394,9 +1464,25 @@ function FloatingFocusManager(props) {
|
|
|
1394
1464
|
return ((_node$context3 = node.context) == null ? void 0 : _node$context3.elements.floating) === relatedTarget || ((_node$context4 = node.context) == null ? void 0 : _node$context4.elements.domReference) === relatedTarget;
|
|
1395
1465
|
})));
|
|
1396
1466
|
|
|
1467
|
+
// Restore focus to the previous tabbable element index to prevent
|
|
1468
|
+
// focus from being lost outside the floating tree.
|
|
1469
|
+
if (restoreFocus && movedToUnrelatedNode && activeElement(getDocument(floatingFocusNode)) === getDocument(floatingFocusNode).body) {
|
|
1470
|
+
// Let `FloatingPortal` effect knows that focus is still inside the
|
|
1471
|
+
// floating tree.
|
|
1472
|
+
if (isHTMLElement(floatingFocusNode)) {
|
|
1473
|
+
floatingFocusNode == null || floatingFocusNode.focus();
|
|
1474
|
+
}
|
|
1475
|
+
const prevTabbableIndex = tabbableIndexRef.current;
|
|
1476
|
+
const tabbableContent = getTabbableContent();
|
|
1477
|
+
const nodeToFocus = tabbableContent[prevTabbableIndex] || tabbableContent[tabbableContent.length - 1] || floatingFocusNode;
|
|
1478
|
+
if (isHTMLElement(nodeToFocus)) {
|
|
1479
|
+
nodeToFocus.focus();
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1397
1483
|
// Focus did not move inside the floating tree, and there are no tabbable
|
|
1398
1484
|
// portal guards to handle closing.
|
|
1399
|
-
if (relatedTarget && movedToUnrelatedNode && !isPointerDownRef.current &&
|
|
1485
|
+
if ((isUntrappedTypeableCombobox ? true : !modal) && relatedTarget && movedToUnrelatedNode && !isPointerDownRef.current &&
|
|
1400
1486
|
// Fix React 18 Strict Mode returnFocus due to double rendering.
|
|
1401
1487
|
relatedTarget !== getPreviouslyFocusedElement()) {
|
|
1402
1488
|
preventReturnFocusRef.current = true;
|
|
@@ -1407,14 +1493,14 @@ function FloatingFocusManager(props) {
|
|
|
1407
1493
|
if (floating && isHTMLElement(domReference)) {
|
|
1408
1494
|
domReference.addEventListener('focusout', handleFocusOutside);
|
|
1409
1495
|
domReference.addEventListener('pointerdown', handlePointerDown);
|
|
1410
|
-
|
|
1496
|
+
floating.addEventListener('focusout', handleFocusOutside);
|
|
1411
1497
|
return () => {
|
|
1412
1498
|
domReference.removeEventListener('focusout', handleFocusOutside);
|
|
1413
1499
|
domReference.removeEventListener('pointerdown', handlePointerDown);
|
|
1414
|
-
|
|
1500
|
+
floating.removeEventListener('focusout', handleFocusOutside);
|
|
1415
1501
|
};
|
|
1416
1502
|
}
|
|
1417
|
-
}, [disabled, domReference, floating, modal, nodeId, tree, portalContext, onOpenChange, closeOnFocusOut]);
|
|
1503
|
+
}, [disabled, domReference, floating, floatingFocusNode, modal, nodeId, tree, portalContext, onOpenChange, closeOnFocusOut, restoreFocus, getTabbableContent, isUntrappedTypeableCombobox]);
|
|
1418
1504
|
React.useEffect(() => {
|
|
1419
1505
|
var _portalContext$portal;
|
|
1420
1506
|
if (disabled) return;
|
|
@@ -1430,39 +1516,45 @@ function FloatingFocusManager(props) {
|
|
|
1430
1516
|
}
|
|
1431
1517
|
}, [disabled, domReference, floating, modal, orderRef, portalContext, isUntrappedTypeableCombobox, guards]);
|
|
1432
1518
|
index(() => {
|
|
1433
|
-
if (disabled || !
|
|
1434
|
-
const doc = getDocument(
|
|
1519
|
+
if (disabled || !isHTMLElement(floatingFocusNode)) return;
|
|
1520
|
+
const doc = getDocument(floatingFocusNode);
|
|
1435
1521
|
const previouslyFocusedElement = activeElement(doc);
|
|
1436
1522
|
|
|
1437
1523
|
// Wait for any layout effect state setters to execute to set `tabIndex`.
|
|
1438
1524
|
queueMicrotask(() => {
|
|
1439
|
-
const focusableElements = getTabbableElements(
|
|
1525
|
+
const focusableElements = getTabbableElements(floatingFocusNode);
|
|
1440
1526
|
const initialFocusValue = initialFocusRef.current;
|
|
1441
|
-
const elToFocus = (typeof initialFocusValue === 'number' ? focusableElements[initialFocusValue] : initialFocusValue.current) ||
|
|
1442
|
-
const focusAlreadyInsideFloatingEl = contains(
|
|
1527
|
+
const elToFocus = (typeof initialFocusValue === 'number' ? focusableElements[initialFocusValue] : initialFocusValue.current) || floatingFocusNode;
|
|
1528
|
+
const focusAlreadyInsideFloatingEl = contains(floatingFocusNode, previouslyFocusedElement);
|
|
1443
1529
|
if (!ignoreInitialFocus && !focusAlreadyInsideFloatingEl && open) {
|
|
1444
1530
|
enqueueFocus(elToFocus, {
|
|
1445
|
-
preventScroll: elToFocus ===
|
|
1531
|
+
preventScroll: elToFocus === floatingFocusNode
|
|
1446
1532
|
});
|
|
1447
1533
|
}
|
|
1448
1534
|
});
|
|
1449
|
-
}, [disabled, open,
|
|
1535
|
+
}, [disabled, open, floatingFocusNode, ignoreInitialFocus, getTabbableElements, initialFocusRef]);
|
|
1450
1536
|
index(() => {
|
|
1451
|
-
if (disabled || !
|
|
1537
|
+
if (disabled || !floatingFocusNode) return;
|
|
1452
1538
|
let preventReturnFocusScroll = false;
|
|
1453
|
-
const doc = getDocument(
|
|
1539
|
+
const doc = getDocument(floatingFocusNode);
|
|
1454
1540
|
const previouslyFocusedElement = activeElement(doc);
|
|
1455
1541
|
const contextData = dataRef.current;
|
|
1542
|
+
let openEvent = contextData.openEvent;
|
|
1543
|
+
const domReference = refs.domReference.current;
|
|
1456
1544
|
addPreviouslyFocusedElement(previouslyFocusedElement);
|
|
1457
1545
|
|
|
1458
1546
|
// Dismissing via outside press should always ignore `returnFocus` to
|
|
1459
1547
|
// prevent unwanted scrolling.
|
|
1460
1548
|
function onOpenChange(_ref) {
|
|
1461
1549
|
let {
|
|
1550
|
+
open,
|
|
1462
1551
|
reason,
|
|
1463
1552
|
event,
|
|
1464
1553
|
nested
|
|
1465
1554
|
} = _ref;
|
|
1555
|
+
if (open) {
|
|
1556
|
+
openEvent = event;
|
|
1557
|
+
}
|
|
1466
1558
|
if (reason === 'escape-key' && refs.domReference.current) {
|
|
1467
1559
|
addPreviouslyFocusedElement(refs.domReference.current);
|
|
1468
1560
|
}
|
|
@@ -1485,34 +1577,40 @@ function FloatingFocusManager(props) {
|
|
|
1485
1577
|
var _node$context5;
|
|
1486
1578
|
return contains((_node$context5 = node.context) == null ? void 0 : _node$context5.elements.floating, activeEl);
|
|
1487
1579
|
});
|
|
1488
|
-
const shouldFocusReference = isFocusInsideFloatingTree ||
|
|
1580
|
+
const shouldFocusReference = isFocusInsideFloatingTree || openEvent && ['click', 'mousedown'].includes(openEvent.type);
|
|
1489
1581
|
if (shouldFocusReference && refs.domReference.current) {
|
|
1490
1582
|
addPreviouslyFocusedElement(refs.domReference.current);
|
|
1491
1583
|
}
|
|
1492
|
-
const
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
//
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1584
|
+
const returnContextElement = domReference || previouslyFocusedElement;
|
|
1585
|
+
const tabbableElements = tabbable(getDocument(returnContextElement).body, getTabbableOptions());
|
|
1586
|
+
|
|
1587
|
+
// Wait for the return element to get potentially disconnected before
|
|
1588
|
+
// checking.
|
|
1589
|
+
queueMicrotask(() => {
|
|
1590
|
+
let returnElement = getPreviouslyFocusedElement();
|
|
1591
|
+
if (!returnElement && isHTMLElement(returnContextElement) && floating) {
|
|
1592
|
+
returnElement = getClosestTabbableElement(tabbableElements, returnContextElement, floating);
|
|
1593
|
+
}
|
|
1594
|
+
if (
|
|
1595
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1596
|
+
returnFocusRef.current && !preventReturnFocusRef.current && isHTMLElement(returnElement) && (
|
|
1597
|
+
// If the focus moved somewhere else after mount, avoid returning focus
|
|
1598
|
+
// since it likely entered a different element which should be
|
|
1599
|
+
// respected: https://github.com/floating-ui/floating-ui/issues/2607
|
|
1600
|
+
returnElement !== activeEl && activeEl !== doc.body ? isFocusInsideFloatingTree : true)) {
|
|
1601
|
+
returnElement.focus({
|
|
1602
|
+
preventScroll: preventReturnFocusScroll
|
|
1603
|
+
});
|
|
1604
|
+
}
|
|
1605
|
+
});
|
|
1509
1606
|
};
|
|
1510
|
-
}, [disabled, floating, returnFocusRef, dataRef, refs, events, tree, nodeId]);
|
|
1607
|
+
}, [disabled, floating, floatingFocusNode, returnFocusRef, dataRef, refs, events, tree, nodeId]);
|
|
1511
1608
|
|
|
1512
1609
|
// Synchronize the `context` & `modal` value to the FloatingPortal context.
|
|
1513
1610
|
// It will decide whether or not it needs to render its own guards.
|
|
1514
1611
|
index(() => {
|
|
1515
|
-
if (disabled
|
|
1612
|
+
if (disabled) return;
|
|
1613
|
+
if (!portalContext) return;
|
|
1516
1614
|
portalContext.setFocusManagerState({
|
|
1517
1615
|
modal,
|
|
1518
1616
|
closeOnFocusOut,
|
|
@@ -1525,22 +1623,29 @@ function FloatingFocusManager(props) {
|
|
|
1525
1623
|
};
|
|
1526
1624
|
}, [disabled, portalContext, modal, open, onOpenChange, refs, closeOnFocusOut]);
|
|
1527
1625
|
index(() => {
|
|
1528
|
-
if (disabled
|
|
1529
|
-
|
|
1530
|
-
|
|
1626
|
+
if (disabled) return;
|
|
1627
|
+
if (!floatingFocusNode) return;
|
|
1628
|
+
if (typeof MutationObserver !== 'function') return;
|
|
1629
|
+
if (ignoreInitialFocus) return;
|
|
1531
1630
|
const handleMutation = () => {
|
|
1532
|
-
const tabIndex =
|
|
1533
|
-
|
|
1631
|
+
const tabIndex = floatingFocusNode.getAttribute('tabindex');
|
|
1632
|
+
const tabbableContent = getTabbableContent();
|
|
1633
|
+
const activeEl = activeElement(getDocument(floating));
|
|
1634
|
+
const tabbableIndex = tabbableContent.indexOf(activeEl);
|
|
1635
|
+
if (tabbableIndex !== -1) {
|
|
1636
|
+
tabbableIndexRef.current = tabbableIndex;
|
|
1637
|
+
}
|
|
1638
|
+
if (orderRef.current.includes('floating') || activeEl !== refs.domReference.current && tabbableContent.length === 0) {
|
|
1534
1639
|
if (tabIndex !== '0') {
|
|
1535
|
-
|
|
1640
|
+
floatingFocusNode.setAttribute('tabindex', '0');
|
|
1536
1641
|
}
|
|
1537
1642
|
} else if (tabIndex !== '-1') {
|
|
1538
|
-
|
|
1643
|
+
floatingFocusNode.setAttribute('tabindex', '-1');
|
|
1539
1644
|
}
|
|
1540
1645
|
};
|
|
1541
1646
|
handleMutation();
|
|
1542
1647
|
const observer = new MutationObserver(handleMutation);
|
|
1543
|
-
observer.observe(
|
|
1648
|
+
observer.observe(floatingFocusNode, {
|
|
1544
1649
|
childList: true,
|
|
1545
1650
|
subtree: true,
|
|
1546
1651
|
attributes: true
|
|
@@ -1548,7 +1653,7 @@ function FloatingFocusManager(props) {
|
|
|
1548
1653
|
return () => {
|
|
1549
1654
|
observer.disconnect();
|
|
1550
1655
|
};
|
|
1551
|
-
}, [disabled, floating, refs, orderRef, getTabbableContent, ignoreInitialFocus]);
|
|
1656
|
+
}, [disabled, floating, floatingFocusNode, refs, orderRef, getTabbableContent, ignoreInitialFocus]);
|
|
1552
1657
|
function renderDismissButton(location) {
|
|
1553
1658
|
if (disabled || !visuallyHiddenDismiss || !modal) {
|
|
1554
1659
|
return null;
|
|
@@ -1558,7 +1663,7 @@ function FloatingFocusManager(props) {
|
|
|
1558
1663
|
onClick: event => onOpenChange(false, event.nativeEvent)
|
|
1559
1664
|
}, typeof visuallyHiddenDismiss === 'string' ? visuallyHiddenDismiss : 'Dismiss');
|
|
1560
1665
|
}
|
|
1561
|
-
const shouldRenderGuards = !disabled && guards && (isInsidePortal || modal);
|
|
1666
|
+
const shouldRenderGuards = !disabled && guards && (modal ? !isUntrappedTypeableCombobox : true) && (isInsidePortal || modal);
|
|
1562
1667
|
return /*#__PURE__*/React.createElement(React.Fragment, null, shouldRenderGuards && /*#__PURE__*/React.createElement(FocusGuard, {
|
|
1563
1668
|
"data-type": "inside",
|
|
1564
1669
|
ref: portalContext == null ? void 0 : portalContext.beforeInsideRef,
|
|
@@ -1630,81 +1735,74 @@ function useClick(context, props) {
|
|
|
1630
1735
|
} = props;
|
|
1631
1736
|
const pointerTypeRef = React.useRef();
|
|
1632
1737
|
const didKeyDownRef = React.useRef(false);
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
event.preventDefault();
|
|
1682
|
-
didKeyDownRef.current = true;
|
|
1683
|
-
}
|
|
1684
|
-
if (event.key === 'Enter') {
|
|
1685
|
-
if (open && toggle) {
|
|
1686
|
-
onOpenChange(false, event.nativeEvent, 'click');
|
|
1687
|
-
} else {
|
|
1688
|
-
onOpenChange(true, event.nativeEvent, 'click');
|
|
1689
|
-
}
|
|
1690
|
-
}
|
|
1691
|
-
},
|
|
1692
|
-
onKeyUp(event) {
|
|
1693
|
-
if (event.defaultPrevented || !keyboardHandlers || isButtonTarget(event) || isSpaceIgnored(domReference)) {
|
|
1694
|
-
return;
|
|
1695
|
-
}
|
|
1696
|
-
if (event.key === ' ' && didKeyDownRef.current) {
|
|
1697
|
-
didKeyDownRef.current = false;
|
|
1698
|
-
if (open && toggle) {
|
|
1699
|
-
onOpenChange(false, event.nativeEvent, 'click');
|
|
1700
|
-
} else {
|
|
1701
|
-
onOpenChange(true, event.nativeEvent, 'click');
|
|
1702
|
-
}
|
|
1703
|
-
}
|
|
1738
|
+
const reference = React.useMemo(() => ({
|
|
1739
|
+
onPointerDown(event) {
|
|
1740
|
+
pointerTypeRef.current = event.pointerType;
|
|
1741
|
+
},
|
|
1742
|
+
onMouseDown(event) {
|
|
1743
|
+
const pointerType = pointerTypeRef.current;
|
|
1744
|
+
|
|
1745
|
+
// Ignore all buttons except for the "main" button.
|
|
1746
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button
|
|
1747
|
+
if (event.button !== 0) return;
|
|
1748
|
+
if (eventOption === 'click') return;
|
|
1749
|
+
if (isMouseLikePointerType(pointerType, true) && ignoreMouse) return;
|
|
1750
|
+
if (open && toggle && (dataRef.current.openEvent ? dataRef.current.openEvent.type === 'mousedown' : true)) {
|
|
1751
|
+
onOpenChange(false, event.nativeEvent, 'click');
|
|
1752
|
+
} else {
|
|
1753
|
+
// Prevent stealing focus from the floating element
|
|
1754
|
+
event.preventDefault();
|
|
1755
|
+
onOpenChange(true, event.nativeEvent, 'click');
|
|
1756
|
+
}
|
|
1757
|
+
},
|
|
1758
|
+
onClick(event) {
|
|
1759
|
+
const pointerType = pointerTypeRef.current;
|
|
1760
|
+
if (eventOption === 'mousedown' && pointerTypeRef.current) {
|
|
1761
|
+
pointerTypeRef.current = undefined;
|
|
1762
|
+
return;
|
|
1763
|
+
}
|
|
1764
|
+
if (isMouseLikePointerType(pointerType, true) && ignoreMouse) return;
|
|
1765
|
+
if (open && toggle && (dataRef.current.openEvent ? dataRef.current.openEvent.type === 'click' : true)) {
|
|
1766
|
+
onOpenChange(false, event.nativeEvent, 'click');
|
|
1767
|
+
} else {
|
|
1768
|
+
onOpenChange(true, event.nativeEvent, 'click');
|
|
1769
|
+
}
|
|
1770
|
+
},
|
|
1771
|
+
onKeyDown(event) {
|
|
1772
|
+
pointerTypeRef.current = undefined;
|
|
1773
|
+
if (event.defaultPrevented || !keyboardHandlers || isButtonTarget(event)) {
|
|
1774
|
+
return;
|
|
1775
|
+
}
|
|
1776
|
+
if (event.key === ' ' && !isSpaceIgnored(domReference)) {
|
|
1777
|
+
// Prevent scrolling
|
|
1778
|
+
event.preventDefault();
|
|
1779
|
+
didKeyDownRef.current = true;
|
|
1780
|
+
}
|
|
1781
|
+
if (event.key === 'Enter') {
|
|
1782
|
+
if (open && toggle) {
|
|
1783
|
+
onOpenChange(false, event.nativeEvent, 'click');
|
|
1784
|
+
} else {
|
|
1785
|
+
onOpenChange(true, event.nativeEvent, 'click');
|
|
1704
1786
|
}
|
|
1705
1787
|
}
|
|
1706
|
-
}
|
|
1707
|
-
|
|
1788
|
+
},
|
|
1789
|
+
onKeyUp(event) {
|
|
1790
|
+
if (event.defaultPrevented || !keyboardHandlers || isButtonTarget(event) || isSpaceIgnored(domReference)) {
|
|
1791
|
+
return;
|
|
1792
|
+
}
|
|
1793
|
+
if (event.key === ' ' && didKeyDownRef.current) {
|
|
1794
|
+
didKeyDownRef.current = false;
|
|
1795
|
+
if (open && toggle) {
|
|
1796
|
+
onOpenChange(false, event.nativeEvent, 'click');
|
|
1797
|
+
} else {
|
|
1798
|
+
onOpenChange(true, event.nativeEvent, 'click');
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
}), [dataRef, domReference, eventOption, ignoreMouse, keyboardHandlers, onOpenChange, open, toggle]);
|
|
1803
|
+
return React.useMemo(() => enabled ? {
|
|
1804
|
+
reference
|
|
1805
|
+
} : {}, [enabled, reference]);
|
|
1708
1806
|
}
|
|
1709
1807
|
|
|
1710
1808
|
const bubbleHandlerKeys = {
|
|
@@ -1736,12 +1834,7 @@ function useDismiss(context, props) {
|
|
|
1736
1834
|
const {
|
|
1737
1835
|
open,
|
|
1738
1836
|
onOpenChange,
|
|
1739
|
-
|
|
1740
|
-
elements: {
|
|
1741
|
-
reference,
|
|
1742
|
-
domReference,
|
|
1743
|
-
floating
|
|
1744
|
-
},
|
|
1837
|
+
elements,
|
|
1745
1838
|
dataRef
|
|
1746
1839
|
} = context;
|
|
1747
1840
|
const {
|
|
@@ -1769,9 +1862,11 @@ function useDismiss(context, props) {
|
|
|
1769
1862
|
outsidePress: outsidePressCapture
|
|
1770
1863
|
} = normalizeProp(capture);
|
|
1771
1864
|
const closeOnEscapeKeyDown = useEffectEvent(event => {
|
|
1865
|
+
var _dataRef$current$floa;
|
|
1772
1866
|
if (!open || !enabled || !escapeKey || event.key !== 'Escape') {
|
|
1773
1867
|
return;
|
|
1774
1868
|
}
|
|
1869
|
+
const nodeId = (_dataRef$current$floa = dataRef.current.floatingContext) == null ? void 0 : _dataRef$current$floa.nodeId;
|
|
1775
1870
|
const children = tree ? getChildren(tree.nodesRef.current, nodeId) : [];
|
|
1776
1871
|
if (!escapeKeyBubbles) {
|
|
1777
1872
|
event.stopPropagation();
|
|
@@ -1801,6 +1896,7 @@ function useDismiss(context, props) {
|
|
|
1801
1896
|
(_getTarget2 = getTarget(event)) == null || _getTarget2.addEventListener('keydown', callback);
|
|
1802
1897
|
});
|
|
1803
1898
|
const closeOnPressOutside = useEffectEvent(event => {
|
|
1899
|
+
var _dataRef$current$floa2;
|
|
1804
1900
|
// Given developers can stop the propagation of the synthetic event,
|
|
1805
1901
|
// we can only be confident with a positive value.
|
|
1806
1902
|
const insideReactTree = insideReactTreeRef.current;
|
|
@@ -1823,7 +1919,7 @@ function useDismiss(context, props) {
|
|
|
1823
1919
|
}
|
|
1824
1920
|
const target = getTarget(event);
|
|
1825
1921
|
const inertSelector = "[" + createAttribute('inert') + "]";
|
|
1826
|
-
const markers = getDocument(floating).querySelectorAll(inertSelector);
|
|
1922
|
+
const markers = getDocument(elements.floating).querySelectorAll(inertSelector);
|
|
1827
1923
|
let targetRootAncestor = isElement(target) ? target : null;
|
|
1828
1924
|
while (targetRootAncestor && !isLastTraversableNode(targetRootAncestor)) {
|
|
1829
1925
|
const nextParent = getParentNode(targetRootAncestor);
|
|
@@ -1837,7 +1933,7 @@ function useDismiss(context, props) {
|
|
|
1837
1933
|
// floating element rendered.
|
|
1838
1934
|
if (markers.length && isElement(target) && !isRootElement(target) &&
|
|
1839
1935
|
// Clicked on a direct ancestor (e.g. FloatingOverlay).
|
|
1840
|
-
!contains(target, floating) &&
|
|
1936
|
+
!contains(target, elements.floating) &&
|
|
1841
1937
|
// If the target root element contains none of the markers, then the
|
|
1842
1938
|
// element was injected after the floating element rendered.
|
|
1843
1939
|
Array.from(markers).every(marker => !contains(targetRootAncestor, marker))) {
|
|
@@ -1866,11 +1962,12 @@ function useDismiss(context, props) {
|
|
|
1866
1962
|
return;
|
|
1867
1963
|
}
|
|
1868
1964
|
}
|
|
1965
|
+
const nodeId = (_dataRef$current$floa2 = dataRef.current.floatingContext) == null ? void 0 : _dataRef$current$floa2.nodeId;
|
|
1869
1966
|
const targetIsInsideChildren = tree && getChildren(tree.nodesRef.current, nodeId).some(node => {
|
|
1870
1967
|
var _node$context;
|
|
1871
1968
|
return isEventTargetWithin(event, (_node$context = node.context) == null ? void 0 : _node$context.elements.floating);
|
|
1872
1969
|
});
|
|
1873
|
-
if (isEventTargetWithin(event, floating) || isEventTargetWithin(event, domReference) || targetIsInsideChildren) {
|
|
1970
|
+
if (isEventTargetWithin(event, elements.floating) || isEventTargetWithin(event, elements.domReference) || targetIsInsideChildren) {
|
|
1874
1971
|
return;
|
|
1875
1972
|
}
|
|
1876
1973
|
const children = tree ? getChildren(tree.nodesRef.current, nodeId) : [];
|
|
@@ -1907,19 +2004,19 @@ function useDismiss(context, props) {
|
|
|
1907
2004
|
function onScroll(event) {
|
|
1908
2005
|
onOpenChange(false, event, 'ancestor-scroll');
|
|
1909
2006
|
}
|
|
1910
|
-
const doc = getDocument(floating);
|
|
2007
|
+
const doc = getDocument(elements.floating);
|
|
1911
2008
|
escapeKey && doc.addEventListener('keydown', escapeKeyCapture ? closeOnEscapeKeyDownCapture : closeOnEscapeKeyDown, escapeKeyCapture);
|
|
1912
2009
|
outsidePress && doc.addEventListener(outsidePressEvent, outsidePressCapture ? closeOnPressOutsideCapture : closeOnPressOutside, outsidePressCapture);
|
|
1913
2010
|
let ancestors = [];
|
|
1914
2011
|
if (ancestorScroll) {
|
|
1915
|
-
if (isElement(domReference)) {
|
|
1916
|
-
ancestors = getOverflowAncestors(domReference);
|
|
2012
|
+
if (isElement(elements.domReference)) {
|
|
2013
|
+
ancestors = getOverflowAncestors(elements.domReference);
|
|
1917
2014
|
}
|
|
1918
|
-
if (isElement(floating)) {
|
|
1919
|
-
ancestors = ancestors.concat(getOverflowAncestors(floating));
|
|
2015
|
+
if (isElement(elements.floating)) {
|
|
2016
|
+
ancestors = ancestors.concat(getOverflowAncestors(elements.floating));
|
|
1920
2017
|
}
|
|
1921
|
-
if (!isElement(reference) && reference && reference.contextElement) {
|
|
1922
|
-
ancestors = ancestors.concat(getOverflowAncestors(reference.contextElement));
|
|
2018
|
+
if (!isElement(elements.reference) && elements.reference && elements.reference.contextElement) {
|
|
2019
|
+
ancestors = ancestors.concat(getOverflowAncestors(elements.reference.contextElement));
|
|
1923
2020
|
}
|
|
1924
2021
|
}
|
|
1925
2022
|
|
|
@@ -1940,37 +2037,80 @@ function useDismiss(context, props) {
|
|
|
1940
2037
|
ancestor.removeEventListener('scroll', onScroll);
|
|
1941
2038
|
});
|
|
1942
2039
|
};
|
|
1943
|
-
}, [dataRef,
|
|
2040
|
+
}, [dataRef, elements, escapeKey, outsidePress, outsidePressEvent, open, onOpenChange, ancestorScroll, enabled, escapeKeyBubbles, outsidePressBubbles, closeOnEscapeKeyDown, escapeKeyCapture, closeOnEscapeKeyDownCapture, closeOnPressOutside, outsidePressCapture, closeOnPressOutsideCapture]);
|
|
1944
2041
|
React.useEffect(() => {
|
|
1945
2042
|
insideReactTreeRef.current = false;
|
|
1946
2043
|
}, [outsidePress, outsidePressEvent]);
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
2044
|
+
const reference = React.useMemo(() => ({
|
|
2045
|
+
onKeyDown: closeOnEscapeKeyDown,
|
|
2046
|
+
[bubbleHandlerKeys[referencePressEvent]]: event => {
|
|
2047
|
+
if (referencePress) {
|
|
2048
|
+
onOpenChange(false, event.nativeEvent, 'reference-press');
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
}), [closeOnEscapeKeyDown, onOpenChange, referencePress, referencePressEvent]);
|
|
2052
|
+
const floating = React.useMemo(() => ({
|
|
2053
|
+
onKeyDown: closeOnEscapeKeyDown,
|
|
2054
|
+
onMouseDown() {
|
|
2055
|
+
endedOrStartedInsideRef.current = true;
|
|
2056
|
+
},
|
|
2057
|
+
onMouseUp() {
|
|
2058
|
+
endedOrStartedInsideRef.current = true;
|
|
2059
|
+
},
|
|
2060
|
+
[captureHandlerKeys[outsidePressEvent]]: () => {
|
|
2061
|
+
insideReactTreeRef.current = true;
|
|
2062
|
+
}
|
|
2063
|
+
}), [closeOnEscapeKeyDown, outsidePressEvent]);
|
|
2064
|
+
return React.useMemo(() => enabled ? {
|
|
2065
|
+
reference,
|
|
2066
|
+
floating
|
|
2067
|
+
} : {}, [enabled, reference, floating]);
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
function useFloatingRootContext(options) {
|
|
2071
|
+
const {
|
|
2072
|
+
open = false,
|
|
2073
|
+
onOpenChange: onOpenChangeProp,
|
|
2074
|
+
elements: elementsProp
|
|
2075
|
+
} = options;
|
|
2076
|
+
const floatingId = useId();
|
|
2077
|
+
const dataRef = React.useRef({});
|
|
2078
|
+
const [events] = React.useState(() => createPubSub());
|
|
2079
|
+
const nested = useFloatingParentNodeId() != null;
|
|
2080
|
+
if (process.env.NODE_ENV !== "production") {
|
|
2081
|
+
const optionDomReference = elementsProp.reference;
|
|
2082
|
+
if (optionDomReference && !isElement(optionDomReference)) {
|
|
2083
|
+
error('Cannot pass a virtual element to the `elements.reference` option,', 'as it must be a real DOM element. Use `refs.setPositionReference()`', 'instead.');
|
|
1950
2084
|
}
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
2085
|
+
}
|
|
2086
|
+
const [positionReference, setPositionReference] = React.useState(elementsProp.reference);
|
|
2087
|
+
const onOpenChange = useEffectEvent((open, event, reason) => {
|
|
2088
|
+
dataRef.current.openEvent = open ? event : undefined;
|
|
2089
|
+
events.emit('openchange', {
|
|
2090
|
+
open,
|
|
2091
|
+
event,
|
|
2092
|
+
reason,
|
|
2093
|
+
nested
|
|
2094
|
+
});
|
|
2095
|
+
onOpenChangeProp == null || onOpenChangeProp(open, event, reason);
|
|
2096
|
+
});
|
|
2097
|
+
const refs = React.useMemo(() => ({
|
|
2098
|
+
setPositionReference
|
|
2099
|
+
}), []);
|
|
2100
|
+
const elements = React.useMemo(() => ({
|
|
2101
|
+
reference: positionReference || elementsProp.reference || null,
|
|
2102
|
+
floating: elementsProp.floating || null,
|
|
2103
|
+
domReference: elementsProp.reference
|
|
2104
|
+
}), [positionReference, elementsProp.reference, elementsProp.floating]);
|
|
2105
|
+
return React.useMemo(() => ({
|
|
2106
|
+
dataRef,
|
|
2107
|
+
open,
|
|
2108
|
+
onOpenChange,
|
|
2109
|
+
elements,
|
|
2110
|
+
events,
|
|
2111
|
+
floatingId,
|
|
2112
|
+
refs
|
|
2113
|
+
}), [open, onOpenChange, elements, events, floatingId, refs]);
|
|
1974
2114
|
}
|
|
1975
2115
|
|
|
1976
2116
|
/**
|
|
@@ -1978,24 +2118,28 @@ function useDismiss(context, props) {
|
|
|
1978
2118
|
* @see https://floating-ui.com/docs/useFloating
|
|
1979
2119
|
*/
|
|
1980
2120
|
function useFloating(options) {
|
|
1981
|
-
var _options$elements;
|
|
1982
2121
|
if (options === void 0) {
|
|
1983
2122
|
options = {};
|
|
1984
2123
|
}
|
|
1985
2124
|
const {
|
|
1986
|
-
open = false,
|
|
1987
|
-
onOpenChange: unstable_onOpenChange,
|
|
1988
2125
|
nodeId
|
|
1989
2126
|
} = options;
|
|
2127
|
+
const internalRootContext = useFloatingRootContext({
|
|
2128
|
+
...options,
|
|
2129
|
+
elements: {
|
|
2130
|
+
reference: null,
|
|
2131
|
+
floating: null,
|
|
2132
|
+
...options.elements
|
|
2133
|
+
}
|
|
2134
|
+
});
|
|
2135
|
+
const rootContext = options.rootContext || internalRootContext;
|
|
2136
|
+
const computedElements = rootContext.elements;
|
|
1990
2137
|
const [_domReference, setDomReference] = React.useState(null);
|
|
1991
2138
|
const [positionReference, _setPositionReference] = React.useState(null);
|
|
1992
|
-
const optionDomReference =
|
|
2139
|
+
const optionDomReference = computedElements == null ? void 0 : computedElements.reference;
|
|
1993
2140
|
const domReference = optionDomReference || _domReference;
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
error('Cannot pass a virtual element to the `elements.reference` option,', 'as it must be a real DOM element. Use `refs.setPositionReference()`', 'instead.');
|
|
1997
|
-
}
|
|
1998
|
-
}
|
|
2141
|
+
const domReferenceRef = React.useRef(null);
|
|
2142
|
+
const tree = useFloatingTree();
|
|
1999
2143
|
index(() => {
|
|
2000
2144
|
if (domReference) {
|
|
2001
2145
|
domReferenceRef.current = domReference;
|
|
@@ -2004,28 +2148,12 @@ function useFloating(options) {
|
|
|
2004
2148
|
const position = useFloating$1({
|
|
2005
2149
|
...options,
|
|
2006
2150
|
elements: {
|
|
2007
|
-
...
|
|
2151
|
+
...computedElements,
|
|
2008
2152
|
...(positionReference && {
|
|
2009
2153
|
reference: positionReference
|
|
2010
2154
|
})
|
|
2011
2155
|
}
|
|
2012
2156
|
});
|
|
2013
|
-
const tree = useFloatingTree();
|
|
2014
|
-
const nested = useFloatingParentNodeId() != null;
|
|
2015
|
-
const onOpenChange = useEffectEvent((open, event, reason) => {
|
|
2016
|
-
dataRef.current.openEvent = open ? event : undefined;
|
|
2017
|
-
events.emit('openchange', {
|
|
2018
|
-
open,
|
|
2019
|
-
event,
|
|
2020
|
-
reason,
|
|
2021
|
-
nested
|
|
2022
|
-
});
|
|
2023
|
-
unstable_onOpenChange == null || unstable_onOpenChange(open, event, reason);
|
|
2024
|
-
});
|
|
2025
|
-
const domReferenceRef = React.useRef(null);
|
|
2026
|
-
const dataRef = React.useRef({});
|
|
2027
|
-
const events = React.useState(() => createPubSub())[0];
|
|
2028
|
-
const floatingId = useId();
|
|
2029
2157
|
const setPositionReference = React.useCallback(node => {
|
|
2030
2158
|
const computedPositionReference = isElement(node) ? {
|
|
2031
2159
|
getBoundingClientRect: () => node.getBoundingClientRect(),
|
|
@@ -2064,16 +2192,13 @@ function useFloating(options) {
|
|
|
2064
2192
|
}), [position.elements, domReference]);
|
|
2065
2193
|
const context = React.useMemo(() => ({
|
|
2066
2194
|
...position,
|
|
2195
|
+
...rootContext,
|
|
2067
2196
|
refs,
|
|
2068
2197
|
elements,
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
floatingId,
|
|
2072
|
-
events,
|
|
2073
|
-
open,
|
|
2074
|
-
onOpenChange
|
|
2075
|
-
}), [position, nodeId, floatingId, events, open, onOpenChange, refs, elements]);
|
|
2198
|
+
nodeId
|
|
2199
|
+
}), [position, refs, elements, nodeId, rootContext]);
|
|
2076
2200
|
index(() => {
|
|
2201
|
+
rootContext.dataRef.current.floatingContext = context;
|
|
2077
2202
|
const node = tree == null ? void 0 : tree.nodesRef.current.find(node => node.id === nodeId);
|
|
2078
2203
|
if (node) {
|
|
2079
2204
|
node.context = context;
|
|
@@ -2100,10 +2225,8 @@ function useFocus(context, props) {
|
|
|
2100
2225
|
open,
|
|
2101
2226
|
onOpenChange,
|
|
2102
2227
|
events,
|
|
2103
|
-
|
|
2104
|
-
elements
|
|
2105
|
-
domReference
|
|
2106
|
-
}
|
|
2228
|
+
dataRef,
|
|
2229
|
+
elements
|
|
2107
2230
|
} = context;
|
|
2108
2231
|
const {
|
|
2109
2232
|
enabled = true,
|
|
@@ -2113,16 +2236,14 @@ function useFocus(context, props) {
|
|
|
2113
2236
|
const timeoutRef = React.useRef();
|
|
2114
2237
|
const keyboardModalityRef = React.useRef(true);
|
|
2115
2238
|
React.useEffect(() => {
|
|
2116
|
-
if (!enabled)
|
|
2117
|
-
|
|
2118
|
-
}
|
|
2119
|
-
const win = getWindow(domReference);
|
|
2239
|
+
if (!enabled) return;
|
|
2240
|
+
const win = getWindow(elements.domReference);
|
|
2120
2241
|
|
|
2121
2242
|
// If the reference was focused and the user left the tab/window, and the
|
|
2122
2243
|
// floating element was not open, the focus should be blocked when they
|
|
2123
2244
|
// return to the tab/window.
|
|
2124
2245
|
function onBlur() {
|
|
2125
|
-
if (!open && isHTMLElement(domReference) && domReference === activeElement(getDocument(domReference))) {
|
|
2246
|
+
if (!open && isHTMLElement(elements.domReference) && elements.domReference === activeElement(getDocument(elements.domReference))) {
|
|
2126
2247
|
blockFocusRef.current = true;
|
|
2127
2248
|
}
|
|
2128
2249
|
}
|
|
@@ -2135,11 +2256,9 @@ function useFocus(context, props) {
|
|
|
2135
2256
|
win.removeEventListener('blur', onBlur);
|
|
2136
2257
|
win.removeEventListener('keydown', onKeyDown, true);
|
|
2137
2258
|
};
|
|
2138
|
-
}, [domReference, open, enabled]);
|
|
2259
|
+
}, [elements.domReference, open, enabled]);
|
|
2139
2260
|
React.useEffect(() => {
|
|
2140
|
-
if (!enabled)
|
|
2141
|
-
return;
|
|
2142
|
-
}
|
|
2261
|
+
if (!enabled) return;
|
|
2143
2262
|
function onOpenChange(_ref) {
|
|
2144
2263
|
let {
|
|
2145
2264
|
reason
|
|
@@ -2158,69 +2277,67 @@ function useFocus(context, props) {
|
|
|
2158
2277
|
clearTimeout(timeoutRef.current);
|
|
2159
2278
|
};
|
|
2160
2279
|
}, []);
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
return
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
if
|
|
2176
|
-
|
|
2177
|
-
if (
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
if (!target.matches(':focus-visible')) return;
|
|
2184
|
-
} catch (e) {
|
|
2185
|
-
// Old browsers will throw an error when using `:focus-visible`.
|
|
2186
|
-
if (!keyboardModalityRef.current && !isTypeableElement(target)) {
|
|
2187
|
-
return;
|
|
2188
|
-
}
|
|
2189
|
-
}
|
|
2280
|
+
const reference = React.useMemo(() => ({
|
|
2281
|
+
onPointerDown(event) {
|
|
2282
|
+
if (isVirtualPointerEvent(event.nativeEvent)) return;
|
|
2283
|
+
keyboardModalityRef.current = false;
|
|
2284
|
+
},
|
|
2285
|
+
onMouseLeave() {
|
|
2286
|
+
blockFocusRef.current = false;
|
|
2287
|
+
},
|
|
2288
|
+
onFocus(event) {
|
|
2289
|
+
if (blockFocusRef.current) return;
|
|
2290
|
+
const target = getTarget(event.nativeEvent);
|
|
2291
|
+
if (visibleOnly && isElement(target)) {
|
|
2292
|
+
try {
|
|
2293
|
+
// Mac Safari unreliably matches `:focus-visible` on the reference
|
|
2294
|
+
// if focus was outside the page initially - use the fallback
|
|
2295
|
+
// instead.
|
|
2296
|
+
if (isSafari() && isMac()) throw Error();
|
|
2297
|
+
if (!target.matches(':focus-visible')) return;
|
|
2298
|
+
} catch (e) {
|
|
2299
|
+
// Old browsers will throw an error when using `:focus-visible`.
|
|
2300
|
+
if (!keyboardModalityRef.current && !isTypeableElement(target)) {
|
|
2301
|
+
return;
|
|
2190
2302
|
}
|
|
2191
|
-
onOpenChange(true, event.nativeEvent, 'focus');
|
|
2192
|
-
},
|
|
2193
|
-
onBlur(event) {
|
|
2194
|
-
blockFocusRef.current = false;
|
|
2195
|
-
const relatedTarget = event.relatedTarget;
|
|
2196
|
-
|
|
2197
|
-
// Hit the non-modal focus management portal guard. Focus will be
|
|
2198
|
-
// moved into the floating element immediately after.
|
|
2199
|
-
const movedToFocusGuard = isElement(relatedTarget) && relatedTarget.hasAttribute(createAttribute('focus-guard')) && relatedTarget.getAttribute('data-type') === 'outside';
|
|
2200
|
-
|
|
2201
|
-
// Wait for the window blur listener to fire.
|
|
2202
|
-
timeoutRef.current = window.setTimeout(() => {
|
|
2203
|
-
const activeEl = activeElement(domReference ? domReference.ownerDocument : document);
|
|
2204
|
-
|
|
2205
|
-
// Focus left the page, keep it open.
|
|
2206
|
-
if (!relatedTarget && activeEl === domReference) return;
|
|
2207
|
-
|
|
2208
|
-
// When focusing the reference element (e.g. regular click), then
|
|
2209
|
-
// clicking into the floating element, prevent it from hiding.
|
|
2210
|
-
// Note: it must be focusable, e.g. `tabindex="-1"`.
|
|
2211
|
-
// We can not rely on relatedTarget to point to the correct element
|
|
2212
|
-
// as it will only point to the shadow host of the newly focused element
|
|
2213
|
-
// and not the element that actually has received focus if it is located
|
|
2214
|
-
// inside a shadow root.
|
|
2215
|
-
if (contains(refs.floating.current, activeEl) || contains(domReference, activeEl) || movedToFocusGuard) {
|
|
2216
|
-
return;
|
|
2217
|
-
}
|
|
2218
|
-
onOpenChange(false, event.nativeEvent, 'focus');
|
|
2219
|
-
});
|
|
2220
2303
|
}
|
|
2221
2304
|
}
|
|
2222
|
-
|
|
2223
|
-
|
|
2305
|
+
onOpenChange(true, event.nativeEvent, 'focus');
|
|
2306
|
+
},
|
|
2307
|
+
onBlur(event) {
|
|
2308
|
+
blockFocusRef.current = false;
|
|
2309
|
+
const relatedTarget = event.relatedTarget;
|
|
2310
|
+
const nativeEvent = event.nativeEvent;
|
|
2311
|
+
|
|
2312
|
+
// Hit the non-modal focus management portal guard. Focus will be
|
|
2313
|
+
// moved into the floating element immediately after.
|
|
2314
|
+
const movedToFocusGuard = isElement(relatedTarget) && relatedTarget.hasAttribute(createAttribute('focus-guard')) && relatedTarget.getAttribute('data-type') === 'outside';
|
|
2315
|
+
|
|
2316
|
+
// Wait for the window blur listener to fire.
|
|
2317
|
+
timeoutRef.current = window.setTimeout(() => {
|
|
2318
|
+
var _dataRef$current$floa;
|
|
2319
|
+
const activeEl = activeElement(elements.domReference ? elements.domReference.ownerDocument : document);
|
|
2320
|
+
|
|
2321
|
+
// Focus left the page, keep it open.
|
|
2322
|
+
if (!relatedTarget && activeEl === elements.domReference) return;
|
|
2323
|
+
|
|
2324
|
+
// When focusing the reference element (e.g. regular click), then
|
|
2325
|
+
// clicking into the floating element, prevent it from hiding.
|
|
2326
|
+
// Note: it must be focusable, e.g. `tabindex="-1"`.
|
|
2327
|
+
// We can not rely on relatedTarget to point to the correct element
|
|
2328
|
+
// as it will only point to the shadow host of the newly focused element
|
|
2329
|
+
// and not the element that actually has received focus if it is located
|
|
2330
|
+
// inside a shadow root.
|
|
2331
|
+
if (contains((_dataRef$current$floa = dataRef.current.floatingContext) == null ? void 0 : _dataRef$current$floa.refs.floating.current, activeEl) || contains(elements.domReference, activeEl) || movedToFocusGuard) {
|
|
2332
|
+
return;
|
|
2333
|
+
}
|
|
2334
|
+
onOpenChange(false, nativeEvent, 'focus');
|
|
2335
|
+
});
|
|
2336
|
+
}
|
|
2337
|
+
}), [dataRef, elements.domReference, onOpenChange, visibleOnly]);
|
|
2338
|
+
return React.useMemo(() => enabled ? {
|
|
2339
|
+
reference
|
|
2340
|
+
} : {}, [enabled, reference]);
|
|
2224
2341
|
}
|
|
2225
2342
|
|
|
2226
2343
|
const ACTIVE_KEY = 'active';
|
|
@@ -2280,7 +2397,6 @@ function mergeProps(userProps, propsList, elementKey) {
|
|
|
2280
2397
|
}, {})
|
|
2281
2398
|
};
|
|
2282
2399
|
}
|
|
2283
|
-
|
|
2284
2400
|
/**
|
|
2285
2401
|
* Merges an array of interaction hooks' props into prop getters, allowing
|
|
2286
2402
|
* event handler functions to be composed together without overwriting one
|
|
@@ -2291,22 +2407,18 @@ function useInteractions(propsList) {
|
|
|
2291
2407
|
if (propsList === void 0) {
|
|
2292
2408
|
propsList = [];
|
|
2293
2409
|
}
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
const
|
|
2410
|
+
const referenceDeps = propsList.map(key => key == null ? void 0 : key.reference);
|
|
2411
|
+
const floatingDeps = propsList.map(key => key == null ? void 0 : key.floating);
|
|
2412
|
+
const itemDeps = propsList.map(key => key == null ? void 0 : key.item);
|
|
2297
2413
|
const getReferenceProps = React.useCallback(userProps => mergeProps(userProps, propsList, 'reference'),
|
|
2298
2414
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2299
|
-
|
|
2415
|
+
referenceDeps);
|
|
2300
2416
|
const getFloatingProps = React.useCallback(userProps => mergeProps(userProps, propsList, 'floating'),
|
|
2301
2417
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2302
|
-
|
|
2418
|
+
floatingDeps);
|
|
2303
2419
|
const getItemProps = React.useCallback(userProps => mergeProps(userProps, propsList, 'item'),
|
|
2304
|
-
// Granularly check for `item` changes, because the `getItemProps` getter
|
|
2305
|
-
// should be as referentially stable as possible since it may be passed as
|
|
2306
|
-
// a prop to many components. All `item` key values must therefore be
|
|
2307
|
-
// memoized.
|
|
2308
2420
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2309
|
-
|
|
2421
|
+
itemDeps);
|
|
2310
2422
|
return React.useMemo(() => ({
|
|
2311
2423
|
getReferenceProps,
|
|
2312
2424
|
getFloatingProps,
|
|
@@ -2354,11 +2466,7 @@ function useListNavigation(context, props) {
|
|
|
2354
2466
|
const {
|
|
2355
2467
|
open,
|
|
2356
2468
|
onOpenChange,
|
|
2357
|
-
|
|
2358
|
-
elements: {
|
|
2359
|
-
domReference,
|
|
2360
|
-
floating
|
|
2361
|
-
}
|
|
2469
|
+
elements
|
|
2362
2470
|
} = context;
|
|
2363
2471
|
const {
|
|
2364
2472
|
listRef,
|
|
@@ -2403,47 +2511,59 @@ function useListNavigation(context, props) {
|
|
|
2403
2511
|
const keyRef = React.useRef(null);
|
|
2404
2512
|
const isPointerModalityRef = React.useRef(true);
|
|
2405
2513
|
const previousOnNavigateRef = React.useRef(onNavigate);
|
|
2406
|
-
const previousMountedRef = React.useRef(!!floating);
|
|
2514
|
+
const previousMountedRef = React.useRef(!!elements.floating);
|
|
2515
|
+
const previousOpenRef = React.useRef(open);
|
|
2407
2516
|
const forceSyncFocus = React.useRef(false);
|
|
2408
2517
|
const forceScrollIntoViewRef = React.useRef(false);
|
|
2409
2518
|
const disabledIndicesRef = useLatestRef(disabledIndices);
|
|
2410
2519
|
const latestOpenRef = useLatestRef(open);
|
|
2411
2520
|
const scrollItemIntoViewRef = useLatestRef(scrollItemIntoView);
|
|
2521
|
+
const floatingRef = useLatestRef(elements.floating);
|
|
2522
|
+
const selectedIndexRef = useLatestRef(selectedIndex);
|
|
2412
2523
|
const [activeId, setActiveId] = React.useState();
|
|
2413
2524
|
const [virtualId, setVirtualId] = React.useState();
|
|
2414
2525
|
const focusItem = useEffectEvent(function (listRef, indexRef, forceScrollIntoView) {
|
|
2415
2526
|
if (forceScrollIntoView === void 0) {
|
|
2416
2527
|
forceScrollIntoView = false;
|
|
2417
2528
|
}
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2529
|
+
function runFocus(item) {
|
|
2530
|
+
if (virtual) {
|
|
2531
|
+
setActiveId(item.id);
|
|
2532
|
+
tree == null || tree.events.emit('virtualfocus', item);
|
|
2533
|
+
if (virtualItemRef) {
|
|
2534
|
+
virtualItemRef.current = item;
|
|
2535
|
+
}
|
|
2536
|
+
} else {
|
|
2537
|
+
enqueueFocus(item, {
|
|
2538
|
+
preventScroll: true,
|
|
2539
|
+
// Mac Safari does not move the virtual cursor unless the focus call
|
|
2540
|
+
// is sync. However, for the very first focus call, we need to wait
|
|
2541
|
+
// for the position to be ready in order to prevent unwanted
|
|
2542
|
+
// scrolling. This means the virtual cursor will not move to the first
|
|
2543
|
+
// item when first opening the floating element, but will on
|
|
2544
|
+
// subsequent calls. `preventScroll` is supported in modern Safari,
|
|
2545
|
+
// so we can use that instead.
|
|
2546
|
+
// iOS Safari must be async or the first item will not be focused.
|
|
2547
|
+
sync: isMac() && isSafari() ? isPreventScrollSupported || forceSyncFocus.current : false
|
|
2548
|
+
});
|
|
2425
2549
|
}
|
|
2426
|
-
}
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
// is sync. However, for the very first focus call, we need to wait
|
|
2431
|
-
// for the position to be ready in order to prevent unwanted
|
|
2432
|
-
// scrolling. This means the virtual cursor will not move to the first
|
|
2433
|
-
// item when first opening the floating element, but will on
|
|
2434
|
-
// subsequent calls. `preventScroll` is supported in modern Safari,
|
|
2435
|
-
// so we can use that instead.
|
|
2436
|
-
// iOS Safari must be async or the first item will not be focused.
|
|
2437
|
-
sync: isMac() && isSafari() ? isPreventScrollSupported || forceSyncFocus.current : false
|
|
2438
|
-
});
|
|
2550
|
+
}
|
|
2551
|
+
const initialItem = listRef.current[indexRef.current];
|
|
2552
|
+
if (initialItem) {
|
|
2553
|
+
runFocus(initialItem);
|
|
2439
2554
|
}
|
|
2440
2555
|
requestAnimationFrame(() => {
|
|
2556
|
+
const waitedItem = listRef.current[indexRef.current] || initialItem;
|
|
2557
|
+
if (!waitedItem) return;
|
|
2558
|
+
if (!initialItem) {
|
|
2559
|
+
runFocus(waitedItem);
|
|
2560
|
+
}
|
|
2441
2561
|
const scrollIntoViewOptions = scrollItemIntoViewRef.current;
|
|
2442
2562
|
const shouldScrollIntoView = scrollIntoViewOptions && item && (forceScrollIntoView || !isPointerModalityRef.current);
|
|
2443
2563
|
if (shouldScrollIntoView) {
|
|
2444
2564
|
// JSDOM doesn't support `.scrollIntoView()` but it's widely supported
|
|
2445
2565
|
// by all browsers.
|
|
2446
|
-
|
|
2566
|
+
waitedItem.scrollIntoView == null || waitedItem.scrollIntoView(typeof scrollIntoViewOptions === 'boolean' ? {
|
|
2447
2567
|
block: 'nearest',
|
|
2448
2568
|
inline: 'nearest'
|
|
2449
2569
|
} : scrollIntoViewOptions);
|
|
@@ -2462,10 +2582,8 @@ function useListNavigation(context, props) {
|
|
|
2462
2582
|
// Sync `selectedIndex` to be the `activeIndex` upon opening the floating
|
|
2463
2583
|
// element. Also, reset `activeIndex` upon closing the floating element.
|
|
2464
2584
|
index(() => {
|
|
2465
|
-
if (!enabled)
|
|
2466
|
-
|
|
2467
|
-
}
|
|
2468
|
-
if (open && floating) {
|
|
2585
|
+
if (!enabled) return;
|
|
2586
|
+
if (open && elements.floating) {
|
|
2469
2587
|
if (focusItemOnOpenRef.current && selectedIndex != null) {
|
|
2470
2588
|
// Regardless of the pointer modality, we want to ensure the selected
|
|
2471
2589
|
// item comes into view when the floating element is opened.
|
|
@@ -2480,18 +2598,16 @@ function useListNavigation(context, props) {
|
|
|
2480
2598
|
indexRef.current = -1;
|
|
2481
2599
|
previousOnNavigateRef.current(null);
|
|
2482
2600
|
}
|
|
2483
|
-
}, [enabled, open, floating, selectedIndex, onNavigate]);
|
|
2601
|
+
}, [enabled, open, elements.floating, selectedIndex, onNavigate]);
|
|
2484
2602
|
|
|
2485
2603
|
// Sync `activeIndex` to be the focused item while the floating element is
|
|
2486
2604
|
// open.
|
|
2487
2605
|
index(() => {
|
|
2488
|
-
if (!enabled)
|
|
2489
|
-
|
|
2490
|
-
}
|
|
2491
|
-
if (open && floating) {
|
|
2606
|
+
if (!enabled) return;
|
|
2607
|
+
if (open && elements.floating) {
|
|
2492
2608
|
if (activeIndex == null) {
|
|
2493
2609
|
forceSyncFocus.current = false;
|
|
2494
|
-
if (
|
|
2610
|
+
if (selectedIndexRef.current != null) {
|
|
2495
2611
|
return;
|
|
2496
2612
|
}
|
|
2497
2613
|
|
|
@@ -2502,7 +2618,7 @@ function useListNavigation(context, props) {
|
|
|
2502
2618
|
}
|
|
2503
2619
|
|
|
2504
2620
|
// Initial sync.
|
|
2505
|
-
if (!previousMountedRef.current && focusItemOnOpenRef.current && (keyRef.current != null || focusItemOnOpenRef.current === true && keyRef.current == null)) {
|
|
2621
|
+
if ((!previousOpenRef.current || !previousMountedRef.current) && focusItemOnOpenRef.current && (keyRef.current != null || focusItemOnOpenRef.current === true && keyRef.current == null)) {
|
|
2506
2622
|
let runs = 0;
|
|
2507
2623
|
const waitForListPopulated = () => {
|
|
2508
2624
|
if (listRef.current[0] == null) {
|
|
@@ -2528,27 +2644,30 @@ function useListNavigation(context, props) {
|
|
|
2528
2644
|
forceScrollIntoViewRef.current = false;
|
|
2529
2645
|
}
|
|
2530
2646
|
}
|
|
2531
|
-
}, [enabled, open, floating, activeIndex,
|
|
2647
|
+
}, [enabled, open, elements.floating, activeIndex, selectedIndexRef, nested, listRef, orientation, rtl, onNavigate, focusItem, disabledIndicesRef]);
|
|
2532
2648
|
|
|
2533
2649
|
// Ensure the parent floating element has focus when a nested child closes
|
|
2534
2650
|
// to allow arrow key navigation to work after the pointer leaves the child.
|
|
2535
2651
|
index(() => {
|
|
2536
2652
|
var _nodes$find;
|
|
2537
|
-
if (!enabled || floating || !tree || virtual || !previousMountedRef.current) {
|
|
2653
|
+
if (!enabled || elements.floating || !tree || virtual || !previousMountedRef.current) {
|
|
2538
2654
|
return;
|
|
2539
2655
|
}
|
|
2540
2656
|
const nodes = tree.nodesRef.current;
|
|
2541
2657
|
const parent = (_nodes$find = nodes.find(node => node.id === parentId)) == null || (_nodes$find = _nodes$find.context) == null ? void 0 : _nodes$find.elements.floating;
|
|
2542
|
-
const activeEl = activeElement(getDocument(floating));
|
|
2658
|
+
const activeEl = activeElement(getDocument(elements.floating));
|
|
2543
2659
|
const treeContainsActiveEl = nodes.some(node => node.context && contains(node.context.elements.floating, activeEl));
|
|
2544
2660
|
if (parent && !treeContainsActiveEl && isPointerModalityRef.current) {
|
|
2545
2661
|
parent.focus({
|
|
2546
2662
|
preventScroll: true
|
|
2547
2663
|
});
|
|
2548
2664
|
}
|
|
2549
|
-
}, [enabled, floating, tree, parentId, virtual]);
|
|
2665
|
+
}, [enabled, elements.floating, tree, parentId, virtual]);
|
|
2550
2666
|
index(() => {
|
|
2551
|
-
if (!enabled
|
|
2667
|
+
if (!enabled) return;
|
|
2668
|
+
if (!tree) return;
|
|
2669
|
+
if (!virtual) return;
|
|
2670
|
+
if (parentId) return;
|
|
2552
2671
|
function handleVirtualFocus(item) {
|
|
2553
2672
|
setVirtualId(item.id);
|
|
2554
2673
|
if (virtualItemRef) {
|
|
@@ -2562,13 +2681,16 @@ function useListNavigation(context, props) {
|
|
|
2562
2681
|
}, [enabled, tree, virtual, parentId, virtualItemRef]);
|
|
2563
2682
|
index(() => {
|
|
2564
2683
|
previousOnNavigateRef.current = onNavigate;
|
|
2565
|
-
previousMountedRef.current = !!floating;
|
|
2684
|
+
previousMountedRef.current = !!elements.floating;
|
|
2566
2685
|
});
|
|
2567
2686
|
index(() => {
|
|
2568
2687
|
if (!open) {
|
|
2569
2688
|
keyRef.current = null;
|
|
2570
2689
|
}
|
|
2571
2690
|
}, [open]);
|
|
2691
|
+
index(() => {
|
|
2692
|
+
previousOpenRef.current = open;
|
|
2693
|
+
}, [open]);
|
|
2572
2694
|
const hasActiveIndex = activeIndex != null;
|
|
2573
2695
|
const item = React.useMemo(() => {
|
|
2574
2696
|
function syncCurrentTarget(currentTarget) {
|
|
@@ -2612,7 +2734,7 @@ function useListNavigation(context, props) {
|
|
|
2612
2734
|
focusItem(listRef, indexRef);
|
|
2613
2735
|
onNavigate(null);
|
|
2614
2736
|
if (!virtual) {
|
|
2615
|
-
enqueueFocus(
|
|
2737
|
+
enqueueFocus(floatingRef.current, {
|
|
2616
2738
|
preventScroll: true
|
|
2617
2739
|
});
|
|
2618
2740
|
}
|
|
@@ -2620,126 +2742,137 @@ function useListNavigation(context, props) {
|
|
|
2620
2742
|
})
|
|
2621
2743
|
};
|
|
2622
2744
|
return props;
|
|
2623
|
-
}, [open,
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2745
|
+
}, [open, floatingRef, focusItem, focusItemOnHover, listRef, onNavigate, virtual]);
|
|
2746
|
+
const commonOnKeyDown = useEffectEvent(event => {
|
|
2747
|
+
isPointerModalityRef.current = false;
|
|
2748
|
+
forceSyncFocus.current = true;
|
|
2749
|
+
|
|
2750
|
+
// If the floating element is animating out, ignore navigation. Otherwise,
|
|
2751
|
+
// the `activeIndex` gets set to 0 despite not being open so the next time
|
|
2752
|
+
// the user ArrowDowns, the first item won't be focused.
|
|
2753
|
+
if (!latestOpenRef.current && event.currentTarget === floatingRef.current) {
|
|
2754
|
+
return;
|
|
2627
2755
|
}
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
// If the floating element is animating out, ignore navigation. Otherwise,
|
|
2634
|
-
// the `activeIndex` gets set to 0 despite not being open so the next time
|
|
2635
|
-
// the user ArrowDowns, the first item won't be focused.
|
|
2636
|
-
if (!latestOpenRef.current && event.currentTarget === refs.floating.current) {
|
|
2637
|
-
return;
|
|
2756
|
+
if (nested && isCrossOrientationCloseKey(event.key, orientation, rtl)) {
|
|
2757
|
+
stopEvent(event);
|
|
2758
|
+
onOpenChange(false, event.nativeEvent, 'list-navigation');
|
|
2759
|
+
if (isHTMLElement(elements.domReference) && !virtual) {
|
|
2760
|
+
elements.domReference.focus();
|
|
2638
2761
|
}
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2762
|
+
return;
|
|
2763
|
+
}
|
|
2764
|
+
const currentIndex = indexRef.current;
|
|
2765
|
+
const minIndex = getMinIndex(listRef, disabledIndices);
|
|
2766
|
+
const maxIndex = getMaxIndex(listRef, disabledIndices);
|
|
2767
|
+
if (event.key === 'Home') {
|
|
2768
|
+
stopEvent(event);
|
|
2769
|
+
indexRef.current = minIndex;
|
|
2770
|
+
onNavigate(indexRef.current);
|
|
2771
|
+
}
|
|
2772
|
+
if (event.key === 'End') {
|
|
2773
|
+
stopEvent(event);
|
|
2774
|
+
indexRef.current = maxIndex;
|
|
2775
|
+
onNavigate(indexRef.current);
|
|
2776
|
+
}
|
|
2777
|
+
|
|
2778
|
+
// Grid navigation.
|
|
2779
|
+
if (cols > 1) {
|
|
2780
|
+
const sizes = itemSizes || Array.from({
|
|
2781
|
+
length: listRef.current.length
|
|
2782
|
+
}, () => ({
|
|
2783
|
+
width: 1,
|
|
2784
|
+
height: 1
|
|
2785
|
+
}));
|
|
2786
|
+
// To calculate movements on the grid, we use hypothetical cell indices
|
|
2787
|
+
// as if every item was 1x1, then convert back to real indices.
|
|
2788
|
+
const cellMap = buildCellMap(sizes, cols, dense);
|
|
2789
|
+
const minGridIndex = cellMap.findIndex(index => index != null && !isDisabled(listRef.current, index, disabledIndices));
|
|
2790
|
+
// last enabled index
|
|
2791
|
+
const maxGridIndex = cellMap.reduce((foundIndex, index, cellIndex) => index != null && !isDisabled(listRef.current, index, disabledIndices) ? cellIndex : foundIndex, -1);
|
|
2792
|
+
indexRef.current = cellMap[getGridNavigatedIndex({
|
|
2793
|
+
current: cellMap.map(itemIndex => itemIndex != null ? listRef.current[itemIndex] : null)
|
|
2794
|
+
}, {
|
|
2795
|
+
event,
|
|
2796
|
+
orientation,
|
|
2797
|
+
loop,
|
|
2798
|
+
cols,
|
|
2799
|
+
// treat undefined (empty grid spaces) as disabled indices so we
|
|
2800
|
+
// don't end up in them
|
|
2801
|
+
disabledIndices: getCellIndices([...(disabledIndices || listRef.current.map((_, index) => isDisabled(listRef.current, index) ? index : undefined)), undefined], cellMap),
|
|
2802
|
+
minIndex: minGridIndex,
|
|
2803
|
+
maxIndex: maxGridIndex,
|
|
2804
|
+
prevIndex: getCellIndexOfCorner(indexRef.current > maxIndex ? minIndex : indexRef.current, sizes, cellMap, cols,
|
|
2805
|
+
// use a corner matching the edge closest to the direction
|
|
2806
|
+
// we're moving in so we don't end up in the same item. Prefer
|
|
2807
|
+
// top/left over bottom/right.
|
|
2808
|
+
event.key === ARROW_DOWN ? 'bl' : event.key === ARROW_RIGHT ? 'tr' : 'tl'),
|
|
2809
|
+
stopEvent: true
|
|
2810
|
+
})]; // navigated cell will never be nullish
|
|
2811
|
+
|
|
2812
|
+
onNavigate(indexRef.current);
|
|
2813
|
+
if (orientation === 'both') {
|
|
2645
2814
|
return;
|
|
2646
2815
|
}
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
if (event.key === 'Home') {
|
|
2651
|
-
stopEvent(event);
|
|
2652
|
-
indexRef.current = minIndex;
|
|
2653
|
-
onNavigate(indexRef.current);
|
|
2654
|
-
}
|
|
2655
|
-
if (event.key === 'End') {
|
|
2656
|
-
stopEvent(event);
|
|
2657
|
-
indexRef.current = maxIndex;
|
|
2658
|
-
onNavigate(indexRef.current);
|
|
2659
|
-
}
|
|
2660
|
-
|
|
2661
|
-
// Grid navigation.
|
|
2662
|
-
if (cols > 1) {
|
|
2663
|
-
const sizes = itemSizes || Array.from({
|
|
2664
|
-
length: listRef.current.length
|
|
2665
|
-
}, () => ({
|
|
2666
|
-
width: 1,
|
|
2667
|
-
height: 1
|
|
2668
|
-
}));
|
|
2669
|
-
// To calculate movements on the grid, we use hypothetical cell indices
|
|
2670
|
-
// as if every item was 1x1, then convert back to real indices.
|
|
2671
|
-
const cellMap = buildCellMap(sizes, cols, dense);
|
|
2672
|
-
const minGridIndex = cellMap.findIndex(index => index != null && !(disabledIndices != null && disabledIndices.includes(index)));
|
|
2673
|
-
// last enabled index
|
|
2674
|
-
const maxGridIndex = cellMap.reduce((foundIndex, index, cellIndex) => index != null && !(disabledIndices != null && disabledIndices.includes(index)) ? cellIndex : foundIndex, -1);
|
|
2675
|
-
indexRef.current = cellMap[getGridNavigatedIndex({
|
|
2676
|
-
current: cellMap.map(itemIndex => itemIndex != null ? listRef.current[itemIndex] : null)
|
|
2677
|
-
}, {
|
|
2678
|
-
event,
|
|
2679
|
-
orientation,
|
|
2680
|
-
loop,
|
|
2681
|
-
cols,
|
|
2682
|
-
// treat undefined (empty grid spaces) as disabled indices so we
|
|
2683
|
-
// don't end up in them
|
|
2684
|
-
disabledIndices: getCellIndices([...(disabledIndices || []), undefined], cellMap),
|
|
2685
|
-
minIndex: minGridIndex,
|
|
2686
|
-
maxIndex: maxGridIndex,
|
|
2687
|
-
prevIndex: getCellIndexOfCorner(indexRef.current, sizes, cellMap, cols,
|
|
2688
|
-
// use a corner matching the edge closest to the direction
|
|
2689
|
-
// we're moving in so we don't end up in the same item. Prefer
|
|
2690
|
-
// top/left over bottom/right.
|
|
2691
|
-
event.key === ARROW_DOWN ? 'bl' : event.key === ARROW_RIGHT ? 'tr' : 'tl'),
|
|
2692
|
-
stopEvent: true
|
|
2693
|
-
})]; // navigated cell will never be nullish
|
|
2816
|
+
}
|
|
2817
|
+
if (isMainOrientationKey(event.key, orientation)) {
|
|
2818
|
+
stopEvent(event);
|
|
2694
2819
|
|
|
2820
|
+
// Reset the index if no item is focused.
|
|
2821
|
+
if (open && !virtual && activeElement(event.currentTarget.ownerDocument) === event.currentTarget) {
|
|
2822
|
+
indexRef.current = isMainOrientationToEndKey(event.key, orientation, rtl) ? minIndex : maxIndex;
|
|
2695
2823
|
onNavigate(indexRef.current);
|
|
2696
|
-
|
|
2697
|
-
return;
|
|
2698
|
-
}
|
|
2824
|
+
return;
|
|
2699
2825
|
}
|
|
2700
|
-
if (
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
onNavigate(indexRef.current);
|
|
2707
|
-
return;
|
|
2708
|
-
}
|
|
2709
|
-
if (isMainOrientationToEndKey(event.key, orientation, rtl)) {
|
|
2710
|
-
if (loop) {
|
|
2711
|
-
indexRef.current = currentIndex >= maxIndex ? allowEscape && currentIndex !== listRef.current.length ? -1 : minIndex : findNonDisabledIndex(listRef, {
|
|
2712
|
-
startingIndex: currentIndex,
|
|
2713
|
-
disabledIndices
|
|
2714
|
-
});
|
|
2715
|
-
} else {
|
|
2716
|
-
indexRef.current = Math.min(maxIndex, findNonDisabledIndex(listRef, {
|
|
2717
|
-
startingIndex: currentIndex,
|
|
2718
|
-
disabledIndices
|
|
2719
|
-
}));
|
|
2720
|
-
}
|
|
2826
|
+
if (isMainOrientationToEndKey(event.key, orientation, rtl)) {
|
|
2827
|
+
if (loop) {
|
|
2828
|
+
indexRef.current = currentIndex >= maxIndex ? allowEscape && currentIndex !== listRef.current.length ? -1 : minIndex : findNonDisabledIndex(listRef, {
|
|
2829
|
+
startingIndex: currentIndex,
|
|
2830
|
+
disabledIndices
|
|
2831
|
+
});
|
|
2721
2832
|
} else {
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
disabledIndices
|
|
2727
|
-
});
|
|
2728
|
-
} else {
|
|
2729
|
-
indexRef.current = Math.max(minIndex, findNonDisabledIndex(listRef, {
|
|
2730
|
-
startingIndex: currentIndex,
|
|
2731
|
-
decrement: true,
|
|
2732
|
-
disabledIndices
|
|
2733
|
-
}));
|
|
2734
|
-
}
|
|
2833
|
+
indexRef.current = Math.min(maxIndex, findNonDisabledIndex(listRef, {
|
|
2834
|
+
startingIndex: currentIndex,
|
|
2835
|
+
disabledIndices
|
|
2836
|
+
}));
|
|
2735
2837
|
}
|
|
2736
|
-
|
|
2737
|
-
|
|
2838
|
+
} else {
|
|
2839
|
+
if (loop) {
|
|
2840
|
+
indexRef.current = currentIndex <= minIndex ? allowEscape && currentIndex !== -1 ? listRef.current.length : maxIndex : findNonDisabledIndex(listRef, {
|
|
2841
|
+
startingIndex: currentIndex,
|
|
2842
|
+
decrement: true,
|
|
2843
|
+
disabledIndices
|
|
2844
|
+
});
|
|
2738
2845
|
} else {
|
|
2739
|
-
|
|
2846
|
+
indexRef.current = Math.max(minIndex, findNonDisabledIndex(listRef, {
|
|
2847
|
+
startingIndex: currentIndex,
|
|
2848
|
+
decrement: true,
|
|
2849
|
+
disabledIndices
|
|
2850
|
+
}));
|
|
2740
2851
|
}
|
|
2741
2852
|
}
|
|
2853
|
+
if (isIndexOutOfBounds(listRef, indexRef.current)) {
|
|
2854
|
+
onNavigate(null);
|
|
2855
|
+
} else {
|
|
2856
|
+
onNavigate(indexRef.current);
|
|
2857
|
+
}
|
|
2742
2858
|
}
|
|
2859
|
+
});
|
|
2860
|
+
const ariaActiveDescendantProp = React.useMemo(() => {
|
|
2861
|
+
return virtual && open && hasActiveIndex && {
|
|
2862
|
+
'aria-activedescendant': virtualId || activeId
|
|
2863
|
+
};
|
|
2864
|
+
}, [virtual, open, hasActiveIndex, virtualId, activeId]);
|
|
2865
|
+
const floating = React.useMemo(() => {
|
|
2866
|
+
return {
|
|
2867
|
+
'aria-orientation': orientation === 'both' ? undefined : orientation,
|
|
2868
|
+
...(!isTypeableCombobox(elements.domReference) && ariaActiveDescendantProp),
|
|
2869
|
+
onKeyDown: commonOnKeyDown,
|
|
2870
|
+
onPointerMove() {
|
|
2871
|
+
isPointerModalityRef.current = true;
|
|
2872
|
+
}
|
|
2873
|
+
};
|
|
2874
|
+
}, [ariaActiveDescendantProp, commonOnKeyDown, elements.domReference, orientation]);
|
|
2875
|
+
const reference = React.useMemo(() => {
|
|
2743
2876
|
function checkVirtualMouse(event) {
|
|
2744
2877
|
if (focusItemOnOpen === 'auto' && isVirtualClick(event.nativeEvent)) {
|
|
2745
2878
|
focusItemOnOpenRef.current = true;
|
|
@@ -2752,105 +2885,95 @@ function useListNavigation(context, props) {
|
|
|
2752
2885
|
focusItemOnOpenRef.current = true;
|
|
2753
2886
|
}
|
|
2754
2887
|
}
|
|
2755
|
-
const ariaActiveDescendantProp = virtual && open && hasActiveIndex && {
|
|
2756
|
-
'aria-activedescendant': virtualId || activeId
|
|
2757
|
-
};
|
|
2758
|
-
const activeItem = listRef.current.find(item => (item == null ? void 0 : item.id) === activeId);
|
|
2759
2888
|
return {
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
setVirtualId(undefined);
|
|
2785
|
-
}
|
|
2786
|
-
}
|
|
2787
|
-
if (isMainKey && deepestNode.context) {
|
|
2788
|
-
if (deepestNode.context.open && deepestNode.parentId && event.currentTarget !== deepestNode.context.elements.domReference) {
|
|
2789
|
-
var _deepestNode$context$;
|
|
2790
|
-
stopEvent(event);
|
|
2791
|
-
(_deepestNode$context$ = deepestNode.context.elements.domReference) == null || _deepestNode$context$.dispatchEvent(eventObject);
|
|
2792
|
-
return;
|
|
2793
|
-
}
|
|
2889
|
+
...ariaActiveDescendantProp,
|
|
2890
|
+
onKeyDown(event) {
|
|
2891
|
+
isPointerModalityRef.current = false;
|
|
2892
|
+
const isArrowKey = event.key.indexOf('Arrow') === 0;
|
|
2893
|
+
const isCrossOpenKey = isCrossOrientationOpenKey(event.key, orientation, rtl);
|
|
2894
|
+
const isCrossCloseKey = isCrossOrientationCloseKey(event.key, orientation, rtl);
|
|
2895
|
+
const isMainKey = isMainOrientationKey(event.key, orientation);
|
|
2896
|
+
const isNavigationKey = (nested ? isCrossOpenKey : isMainKey) || event.key === 'Enter' || event.key.trim() === '';
|
|
2897
|
+
if (virtual && open) {
|
|
2898
|
+
const rootNode = tree == null ? void 0 : tree.nodesRef.current.find(node => node.parentId == null);
|
|
2899
|
+
const deepestNode = tree && rootNode ? getDeepestNode(tree.nodesRef.current, rootNode.id) : null;
|
|
2900
|
+
if (isArrowKey && deepestNode && virtualItemRef) {
|
|
2901
|
+
const eventObject = new KeyboardEvent('keydown', {
|
|
2902
|
+
key: event.key,
|
|
2903
|
+
bubbles: true
|
|
2904
|
+
});
|
|
2905
|
+
if (isCrossOpenKey || isCrossCloseKey) {
|
|
2906
|
+
var _deepestNode$context, _deepestNode$context2;
|
|
2907
|
+
const isCurrentTarget = ((_deepestNode$context = deepestNode.context) == null ? void 0 : _deepestNode$context.elements.domReference) === event.currentTarget;
|
|
2908
|
+
const dispatchItem = isCrossCloseKey && !isCurrentTarget ? (_deepestNode$context2 = deepestNode.context) == null ? void 0 : _deepestNode$context2.elements.domReference : isCrossOpenKey ? listRef.current.find(item => (item == null ? void 0 : item.id) === activeId) : null;
|
|
2909
|
+
if (dispatchItem) {
|
|
2910
|
+
stopEvent(event);
|
|
2911
|
+
dispatchItem.dispatchEvent(eventObject);
|
|
2912
|
+
setVirtualId(undefined);
|
|
2794
2913
|
}
|
|
2795
2914
|
}
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
return;
|
|
2803
|
-
}
|
|
2804
|
-
if (isNavigationKey) {
|
|
2805
|
-
keyRef.current = nested && isMainKey ? null : event.key;
|
|
2806
|
-
}
|
|
2807
|
-
if (nested) {
|
|
2808
|
-
if (isCrossOpenKey) {
|
|
2809
|
-
stopEvent(event);
|
|
2810
|
-
if (open) {
|
|
2811
|
-
indexRef.current = getMinIndex(listRef, disabledIndices);
|
|
2812
|
-
onNavigate(indexRef.current);
|
|
2813
|
-
} else {
|
|
2814
|
-
onOpenChange(true, event.nativeEvent, 'list-navigation');
|
|
2915
|
+
if (isMainKey && deepestNode.context) {
|
|
2916
|
+
if (deepestNode.context.open && deepestNode.parentId && event.currentTarget !== deepestNode.context.elements.domReference) {
|
|
2917
|
+
var _deepestNode$context$;
|
|
2918
|
+
stopEvent(event);
|
|
2919
|
+
(_deepestNode$context$ = deepestNode.context.elements.domReference) == null || _deepestNode$context$.dispatchEvent(eventObject);
|
|
2920
|
+
return;
|
|
2815
2921
|
}
|
|
2816
2922
|
}
|
|
2817
|
-
return;
|
|
2818
2923
|
}
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2924
|
+
return commonOnKeyDown(event);
|
|
2925
|
+
}
|
|
2926
|
+
|
|
2927
|
+
// If a floating element should not open on arrow key down, avoid
|
|
2928
|
+
// setting `activeIndex` while it's closed.
|
|
2929
|
+
if (!open && !openOnArrowKeyDown && isArrowKey) {
|
|
2930
|
+
return;
|
|
2931
|
+
}
|
|
2932
|
+
if (isNavigationKey) {
|
|
2933
|
+
keyRef.current = nested && isMainKey ? null : event.key;
|
|
2934
|
+
}
|
|
2935
|
+
if (nested) {
|
|
2936
|
+
if (isCrossOpenKey) {
|
|
2823
2937
|
stopEvent(event);
|
|
2824
|
-
if (!open && openOnArrowKeyDown) {
|
|
2825
|
-
onOpenChange(true, event.nativeEvent, 'list-navigation');
|
|
2826
|
-
} else {
|
|
2827
|
-
onKeyDown(event);
|
|
2828
|
-
}
|
|
2829
2938
|
if (open) {
|
|
2939
|
+
indexRef.current = getMinIndex(listRef, disabledIndicesRef.current);
|
|
2830
2940
|
onNavigate(indexRef.current);
|
|
2941
|
+
} else {
|
|
2942
|
+
onOpenChange(true, event.nativeEvent, 'list-navigation');
|
|
2831
2943
|
}
|
|
2832
2944
|
}
|
|
2833
|
-
|
|
2834
|
-
|
|
2945
|
+
return;
|
|
2946
|
+
}
|
|
2947
|
+
if (isMainKey) {
|
|
2948
|
+
if (selectedIndex != null) {
|
|
2949
|
+
indexRef.current = selectedIndex;
|
|
2950
|
+
}
|
|
2951
|
+
stopEvent(event);
|
|
2952
|
+
if (!open && openOnArrowKeyDown) {
|
|
2953
|
+
onOpenChange(true, event.nativeEvent, 'list-navigation');
|
|
2954
|
+
} else {
|
|
2955
|
+
commonOnKeyDown(event);
|
|
2956
|
+
}
|
|
2835
2957
|
if (open) {
|
|
2836
|
-
onNavigate(
|
|
2958
|
+
onNavigate(indexRef.current);
|
|
2837
2959
|
}
|
|
2838
|
-
}
|
|
2839
|
-
onPointerDown: checkVirtualPointer,
|
|
2840
|
-
onMouseDown: checkVirtualMouse,
|
|
2841
|
-
onClick: checkVirtualMouse
|
|
2960
|
+
}
|
|
2842
2961
|
},
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
onKeyDown,
|
|
2847
|
-
onPointerMove() {
|
|
2848
|
-
isPointerModalityRef.current = true;
|
|
2962
|
+
onFocus() {
|
|
2963
|
+
if (open && !virtual) {
|
|
2964
|
+
onNavigate(null);
|
|
2849
2965
|
}
|
|
2850
2966
|
},
|
|
2851
|
-
|
|
2967
|
+
onPointerDown: checkVirtualPointer,
|
|
2968
|
+
onMouseDown: checkVirtualMouse,
|
|
2969
|
+
onClick: checkVirtualMouse
|
|
2852
2970
|
};
|
|
2853
|
-
}, [
|
|
2971
|
+
}, [activeId, ariaActiveDescendantProp, commonOnKeyDown, disabledIndicesRef, focusItemOnOpen, listRef, nested, onNavigate, onOpenChange, open, openOnArrowKeyDown, orientation, rtl, selectedIndex, tree, virtual, virtualItemRef]);
|
|
2972
|
+
return React.useMemo(() => enabled ? {
|
|
2973
|
+
reference,
|
|
2974
|
+
floating,
|
|
2975
|
+
item
|
|
2976
|
+
} : {}, [enabled, reference, floating, item]);
|
|
2854
2977
|
}
|
|
2855
2978
|
|
|
2856
2979
|
const componentRoleToAriaRoleMap = /*#__PURE__*/new Map([['select', 'listbox'], ['combobox', 'listbox'], ['label', false]]);
|
|
@@ -2877,8 +3000,34 @@ function useRole(context, props) {
|
|
|
2877
3000
|
const referenceId = useId();
|
|
2878
3001
|
const parentId = useFloatingParentNodeId();
|
|
2879
3002
|
const isNested = parentId != null;
|
|
2880
|
-
|
|
2881
|
-
if (
|
|
3003
|
+
const reference = React.useMemo(() => {
|
|
3004
|
+
if (ariaRole === 'tooltip' || role === 'label') {
|
|
3005
|
+
return {
|
|
3006
|
+
["aria-" + (role === 'label' ? 'labelledby' : 'describedby')]: open ? floatingId : undefined
|
|
3007
|
+
};
|
|
3008
|
+
}
|
|
3009
|
+
return {
|
|
3010
|
+
'aria-expanded': open ? 'true' : 'false',
|
|
3011
|
+
'aria-haspopup': ariaRole === 'alertdialog' ? 'dialog' : ariaRole,
|
|
3012
|
+
'aria-controls': open ? floatingId : undefined,
|
|
3013
|
+
...(ariaRole === 'listbox' && {
|
|
3014
|
+
role: 'combobox'
|
|
3015
|
+
}),
|
|
3016
|
+
...(ariaRole === 'menu' && {
|
|
3017
|
+
id: referenceId
|
|
3018
|
+
}),
|
|
3019
|
+
...(ariaRole === 'menu' && isNested && {
|
|
3020
|
+
role: 'menuitem'
|
|
3021
|
+
}),
|
|
3022
|
+
...(role === 'select' && {
|
|
3023
|
+
'aria-autocomplete': 'none'
|
|
3024
|
+
}),
|
|
3025
|
+
...(role === 'combobox' && {
|
|
3026
|
+
'aria-autocomplete': 'list'
|
|
3027
|
+
})
|
|
3028
|
+
};
|
|
3029
|
+
}, [ariaRole, floatingId, isNested, open, referenceId, role]);
|
|
3030
|
+
const floating = React.useMemo(() => {
|
|
2882
3031
|
const floatingProps = {
|
|
2883
3032
|
id: floatingId,
|
|
2884
3033
|
...(ariaRole && {
|
|
@@ -2886,75 +3035,53 @@ function useRole(context, props) {
|
|
|
2886
3035
|
})
|
|
2887
3036
|
};
|
|
2888
3037
|
if (ariaRole === 'tooltip' || role === 'label') {
|
|
2889
|
-
return
|
|
2890
|
-
reference: {
|
|
2891
|
-
["aria-" + (role === 'label' ? 'labelledby' : 'describedby')]: open ? floatingId : undefined
|
|
2892
|
-
},
|
|
2893
|
-
floating: floatingProps
|
|
2894
|
-
};
|
|
3038
|
+
return floatingProps;
|
|
2895
3039
|
}
|
|
2896
3040
|
return {
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
'aria-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
'aria-autocomplete': 'list'
|
|
2915
|
-
})
|
|
2916
|
-
},
|
|
2917
|
-
floating: {
|
|
2918
|
-
...floatingProps,
|
|
2919
|
-
...(ariaRole === 'menu' && {
|
|
2920
|
-
'aria-labelledby': referenceId
|
|
2921
|
-
})
|
|
2922
|
-
},
|
|
2923
|
-
item(_ref) {
|
|
2924
|
-
let {
|
|
2925
|
-
active,
|
|
2926
|
-
selected
|
|
2927
|
-
} = _ref;
|
|
2928
|
-
const commonProps = {
|
|
2929
|
-
role: 'option',
|
|
2930
|
-
...(active && {
|
|
2931
|
-
id: floatingId + "-option"
|
|
2932
|
-
})
|
|
2933
|
-
};
|
|
3041
|
+
...floatingProps,
|
|
3042
|
+
...(ariaRole === 'menu' && {
|
|
3043
|
+
'aria-labelledby': referenceId
|
|
3044
|
+
})
|
|
3045
|
+
};
|
|
3046
|
+
}, [ariaRole, floatingId, referenceId, role]);
|
|
3047
|
+
const item = React.useCallback(_ref => {
|
|
3048
|
+
let {
|
|
3049
|
+
active,
|
|
3050
|
+
selected
|
|
3051
|
+
} = _ref;
|
|
3052
|
+
const commonProps = {
|
|
3053
|
+
role: 'option',
|
|
3054
|
+
...(active && {
|
|
3055
|
+
id: floatingId + "-option"
|
|
3056
|
+
})
|
|
3057
|
+
};
|
|
2934
3058
|
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
}
|
|
3059
|
+
// For `menu`, we are unable to tell if the item is a `menuitemradio`
|
|
3060
|
+
// or `menuitemcheckbox`. For backwards-compatibility reasons, also
|
|
3061
|
+
// avoid defaulting to `menuitem` as it may overwrite custom role props.
|
|
3062
|
+
switch (role) {
|
|
3063
|
+
case 'select':
|
|
3064
|
+
return {
|
|
3065
|
+
...commonProps,
|
|
3066
|
+
'aria-selected': active && selected
|
|
3067
|
+
};
|
|
3068
|
+
case 'combobox':
|
|
3069
|
+
{
|
|
3070
|
+
return {
|
|
3071
|
+
...commonProps,
|
|
3072
|
+
...(active && {
|
|
3073
|
+
'aria-selected': true
|
|
3074
|
+
})
|
|
3075
|
+
};
|
|
2953
3076
|
}
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
3077
|
+
}
|
|
3078
|
+
return {};
|
|
3079
|
+
}, [floatingId, role]);
|
|
3080
|
+
return React.useMemo(() => enabled ? {
|
|
3081
|
+
reference,
|
|
3082
|
+
floating,
|
|
3083
|
+
item
|
|
3084
|
+
} : {}, [enabled, reference, floating, item]);
|
|
2958
3085
|
}
|
|
2959
3086
|
|
|
2960
3087
|
// Converts a JS style key like `backgroundColor` to a CSS transition-property
|
|
@@ -2969,11 +3096,11 @@ function useDelayUnmount(open, durationMs) {
|
|
|
2969
3096
|
setIsMounted(true);
|
|
2970
3097
|
}
|
|
2971
3098
|
React.useEffect(() => {
|
|
2972
|
-
if (!open) {
|
|
3099
|
+
if (!open && isMounted) {
|
|
2973
3100
|
const timeout = setTimeout(() => setIsMounted(false), durationMs);
|
|
2974
3101
|
return () => clearTimeout(timeout);
|
|
2975
3102
|
}
|
|
2976
|
-
}, [open, durationMs]);
|
|
3103
|
+
}, [open, isMounted, durationMs]);
|
|
2977
3104
|
return isMounted;
|
|
2978
3105
|
}
|
|
2979
3106
|
/**
|
|
@@ -2996,19 +3123,11 @@ function useTransitionStatus(context, props) {
|
|
|
2996
3123
|
} = props;
|
|
2997
3124
|
const isNumberDuration = typeof duration === 'number';
|
|
2998
3125
|
const closeDuration = (isNumberDuration ? duration : duration.close) || 0;
|
|
2999
|
-
const [initiated, setInitiated] = React.useState(false);
|
|
3000
3126
|
const [status, setStatus] = React.useState('unmounted');
|
|
3001
3127
|
const isMounted = useDelayUnmount(open, closeDuration);
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
// after the initial one allows the correct side animation to play when the
|
|
3006
|
-
// placement has changed.
|
|
3007
|
-
index(() => {
|
|
3008
|
-
if (initiated && !isMounted) {
|
|
3009
|
-
setStatus('unmounted');
|
|
3010
|
-
}
|
|
3011
|
-
}, [initiated, isMounted]);
|
|
3128
|
+
if (!isMounted && status === 'close') {
|
|
3129
|
+
setStatus('unmounted');
|
|
3130
|
+
}
|
|
3012
3131
|
index(() => {
|
|
3013
3132
|
if (!floating) return;
|
|
3014
3133
|
if (open) {
|
|
@@ -3020,7 +3139,6 @@ function useTransitionStatus(context, props) {
|
|
|
3020
3139
|
cancelAnimationFrame(frame);
|
|
3021
3140
|
};
|
|
3022
3141
|
}
|
|
3023
|
-
setInitiated(true);
|
|
3024
3142
|
setStatus('close');
|
|
3025
3143
|
}, [open, floating]);
|
|
3026
3144
|
return {
|
|
@@ -3108,4 +3226,4 @@ function useTransitionStyles(context, props) {
|
|
|
3108
3226
|
};
|
|
3109
3227
|
}
|
|
3110
3228
|
|
|
3111
|
-
export { FloatingArrow, FloatingFocusManager, FloatingPortal, getOverflowAncestors,
|
|
3229
|
+
export { FloatingArrow, FloatingFocusManager, FloatingPortal, getOverflowAncestors, useClick, useDismiss, useFloating, useFloatingParentNodeId, useFloatingPortalNode, useFloatingRootContext, useFloatingTree, useFocus, useHover, useId, useInteractions, useListNavigation, useMergeRefs, useRole, useTransitionStatus, useTransitionStyles };
|