UNPKG

@shopify/polaris

Version:

Shopify’s product component library

115 lines (99 loc) 4.44 kB
import { objectWithoutProperties as _objectWithoutProperties } from '../../_virtual/_rollupPluginBabelHelpers.js'; import React$1, { useState, useRef, useCallback, useEffect, Children } from 'react'; import { useUniqueId } from '../../utilities/unique-id/hooks.js'; import { portal } from '../shared.js'; import { findFirstFocusableNodeIncludingDisabled, focusNextFocusableNode } from '../../utilities/focus.js'; import { Portal as Portal$1 } from '../Portal/Portal.js'; import { Section as Section$1 } from './components/Section/Section.js'; import { Pane as Pane$1 } from './components/Pane/Pane.js'; import { PopoverOverlay as PopoverOverlay$1, PopoverCloseSource } from './components/PopoverOverlay/PopoverOverlay.js'; export { PopoverCloseSource } from './components/PopoverOverlay/PopoverOverlay.js'; import { setActivatorAttributes as setActivatorAttributes$1 } from './set-activator-attributes.js'; // TypeScript can't generate types that correctly infer the typing of // subcomponents so explicitly state the subcomponents in the type definition. // Letting this be implicit works in this project but fails in projects that use // generated *.d.ts files. const Popover = function Popover(_ref) { let { activatorWrapper = 'div', children, onClose, activator, preventFocusOnClose, active, fixed, ariaHaspopup, preferInputActivator = true, colorScheme } = _ref, rest = _objectWithoutProperties(_ref, ["activatorWrapper", "children", "onClose", "activator", "preventFocusOnClose", "active", "fixed", "ariaHaspopup", "preferInputActivator", "colorScheme"]); const [activatorNode, setActivatorNode] = useState(); const activatorContainer = useRef(null); const WrapperComponent = activatorWrapper; const id = useUniqueId('popover'); const setAccessibilityAttributes = useCallback(() => { if (activatorContainer.current == null) { return; } const firstFocusable = findFirstFocusableNodeIncludingDisabled(activatorContainer.current); const focusableActivator = firstFocusable || activatorContainer.current; const activatorDisabled = 'disabled' in focusableActivator && Boolean(focusableActivator.disabled); setActivatorAttributes$1(focusableActivator, { id, active, ariaHaspopup, activatorDisabled }); }, [id, active, ariaHaspopup]); const handleClose = source => { onClose(source); if (activatorContainer.current == null || preventFocusOnClose) { return; } if ((source === PopoverCloseSource.FocusOut || source === PopoverCloseSource.EscapeKeypress) && activatorNode) { const focusableActivator = findFirstFocusableNodeIncludingDisabled(activatorNode) || findFirstFocusableNodeIncludingDisabled(activatorContainer.current) || activatorContainer.current; if (!focusNextFocusableNode(focusableActivator, isInPortal)) { focusableActivator.focus(); } } }; useEffect(() => { if (!activatorNode && activatorContainer.current) { setActivatorNode(activatorContainer.current.firstElementChild); } else if (activatorNode && activatorContainer.current && !activatorContainer.current.contains(activatorNode)) { setActivatorNode(activatorContainer.current.firstElementChild); } setAccessibilityAttributes(); }, [activatorNode, setAccessibilityAttributes]); useEffect(() => { if (activatorNode && activatorContainer.current) { setActivatorNode(activatorContainer.current.firstElementChild); } setAccessibilityAttributes(); }, [activatorNode, setAccessibilityAttributes]); const portal = activatorNode ? /*#__PURE__*/React$1.createElement(Portal$1, { idPrefix: "popover" }, /*#__PURE__*/React$1.createElement(PopoverOverlay$1, Object.assign({ id: id, activator: activatorNode, preferInputActivator: preferInputActivator, onClose: handleClose, active: active, fixed: fixed, colorScheme: colorScheme }, rest), children)) : null; return /*#__PURE__*/React$1.createElement(WrapperComponent, { ref: activatorContainer }, Children.only(activator), portal); }; function isInPortal(element) { let parentElement = element.parentElement; while (parentElement) { if (parentElement.matches(portal.selector)) return false; parentElement = parentElement.parentElement; } return true; } Popover.Pane = Pane$1; Popover.Section = Section$1; export { Popover };