UNPKG

@ozen-ui/kit

Version:

React component library

168 lines (167 loc) 11.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Popover = exports.cnPopover = void 0; var tslib_1 = require("tslib"); var react_1 = tslib_1.__importStar(require("react")); var react_popper_1 = require("react-popper"); var react_transition_group_1 = require("react-transition-group"); require("./Popover.css"); var environment_1 = require("../../constants/environment"); var useClickOutside_1 = require("../../hooks/useClickOutside"); var useEventListener_1 = require("../../hooks/useEventListener"); var useFocusTrap_1 = require("../../hooks/useFocusTrap"); var useMultiRef_1 = require("../../hooks/useMultiRef"); var usePortalContainer_1 = require("../../hooks/usePortalContainer"); var useThemeProps_1 = require("../../hooks/useThemeProps"); var classname_1 = require("../../utils/classname"); var isKey_1 = require("../../utils/isKey"); var polymorphicComponentWithRef_1 = require("../../utils/polymorphicComponentWithRef"); var Paper_1 = require("../Paper"); var PortalBase_1 = require("../PortalBase"); var components_1 = require("./components"); var constants_1 = require("./constants"); var index_1 = require("./index"); var PopoverContext_1 = require("./PopoverContext"); exports.cnPopover = (0, classname_1.cn)('Popover'); exports.Popover = (0, polymorphicComponentWithRef_1.polymorphicComponentWithRef)(function (inProps, ref) { var props = (0, useThemeProps_1.useThemeProps)({ props: inProps, name: 'Popover' }); var _a = props.arrow, arrow = _a === void 0 ? constants_1.POPOVER_DEFAULT_ARROW : _a, _b = props.open, open = _b === void 0 ? constants_1.POPOVER_DEFAULT_OPEN : _b, _c = props.disableInteractive, disableInteractive = _c === void 0 ? constants_1.POPOVER_DEFAULT_DISABLE_INTERACTIVE : _c, _d = props.disableEnforceFocus, disableEnforceFocus = _d === void 0 ? constants_1.POPOVER_DEFAULT_DISABLE_ENFORCE_FOCUS : _d, _e = props.disableReturnFocus, disableReturnFocus = _e === void 0 ? constants_1.POPOVER_DEFAULT_DISABLE_RETURN_FOCUS : _e, _f = props.disableClickOutside, disableClickOutside = _f === void 0 ? constants_1.POPOVER_DEFAULT_DISABLE_CLICK_OUTSIDE : _f, _g = props.placement, placement = _g === void 0 ? constants_1.POPOVER_DEFAULT_PLACEMENT : _g, _h = props.strategy, strategy = _h === void 0 ? constants_1.POPOVER_DEFAULT_STRATEGY : _h, _j = props.disablePreventOverflow, disablePreventOverflow = _j === void 0 ? constants_1.POPOVER_DEFAULT_DISABLE_PREVENT_OVERFLOW : _j, _k = props.container, containerProp = _k === void 0 ? constants_1.POPOVER_DEFAULT_PORTAL_CONTAINER : _k, ignoreClickOutsideRefs = props.ignoreClickOutsideRefs, disableEscapeKeyDown = props.disableEscapeKeyDown, arrowProps = props.arrowProps, anchorRef = props.anchorRef, equalAnchorWidth = props.equalAnchorWidth, offset = props.offset, children = props.children, transitionProps = props.transitionProps, onClose = props.onClose, onEnter = props.onEnter, onEntered = props.onEntered, onExit = props.onExit, onExitedProp = props.onExited, className = props.className, position = props.position, style = props.style, setUpdate = props.setUpdate, modifiersProp = props.modifiers, _l = props.as, as = _l === void 0 ? constants_1.POPOVER_DEFAULT_TAG : _l, other = tslib_1.__rest(props, ["arrow", "open", "disableInteractive", "disableEnforceFocus", "disableReturnFocus", "disableClickOutside", "placement", "strategy", "disablePreventOverflow", "container", "ignoreClickOutsideRefs", "disableEscapeKeyDown", "arrowProps", "anchorRef", "equalAnchorWidth", "offset", "children", "transitionProps", "onClose", "onEnter", "onEntered", "onExit", "onExited", "className", "position", "style", "setUpdate", "modifiers", "as"]); var Tag = (0, react_1.useMemo)(function () { // eslint-disable-next-line react/display-name return (0, react_1.forwardRef)(function (props, ref) { return (react_1.default.createElement(Paper_1.Paper, tslib_1.__assign({ radius: "l", shadow: "m", background: "main" }, props, { as: as, ref: ref }))); }); }, [as]); var _m = tslib_1.__read((0, react_1.useState)(false), 2), openState = _m[0], setOpenState = _m[1]; var focusedElement = (0, react_1.useRef)(null); var popoverRef = (0, react_1.useRef)(null); var _o = (0, index_1.usePopoverManager)(popoverRef, 1000, openState), refsClickOutside = _o.refsClickOutside, isTop = _o.isTop; // Ловушка фокуса var trapRef = (0, useFocusTrap_1.useFocusTrap)({ active: !disableEnforceFocus && isTop, focusinTrap: false, }); var _p = tslib_1.__read((0, react_1.useState)(null), 2), popperElement = _p[0], setPopperElement = _p[1]; var portalRef = (0, useMultiRef_1.useMultiRef)([ref, popoverRef, trapRef, setPopperElement]); // Нажатие клавиши {ESC} (0, useEventListener_1.useEventListener)({ eventName: 'keydown', handler: function (event) { if (!(0, isKey_1.isKey)(event, 'Escape')) return; onClose === null || onClose === void 0 ? void 0 : onClose(); }, active: isTop && !disableEscapeKeyDown, }); (0, useClickOutside_1.useClickOutside)({ refs: tslib_1.__spreadArray(tslib_1.__spreadArray(tslib_1.__spreadArray([ popoverRef ], tslib_1.__read(refsClickOutside), false), tslib_1.__read((anchorRef ? [anchorRef] : [])), false), tslib_1.__read((ignoreClickOutsideRefs || [])), false), handler: onClose, active: openState && !disableClickOutside, }); var onExited = (0, react_1.useCallback)(function () { var _a, _b; if (environment_1.isServer) { return; } // Возвращаем фокус активного элемента if (!disableReturnFocus && (((_a = popoverRef.current) === null || _a === void 0 ? void 0 : _a.contains(document.activeElement)) || document.activeElement === document.body)) { (_b = focusedElement.current) === null || _b === void 0 ? void 0 : _b.focus({ preventScroll: true }); } onExitedProp === null || onExitedProp === void 0 ? void 0 : onExitedProp(); }, [onExitedProp]); var modifiers = (0, react_1.useMemo)(function () { return tslib_1.__spreadArray([ // Вычисление стилей позиционирования { name: 'computeStyles', options: { // Позиционирование через position: absolute // https://popper.js.org/docs/v2/modifiers/compute-styles/#gpuacceleration gpuAcceleration: false, }, }, { name: 'preventOverflow', enabled: disablePreventOverflow }, // Ширина всплывающего элемента { name: 'sameWidth', enabled: !!equalAnchorWidth, fn: function (_a) { var state = _a.state; if ('popper' in state.styles) { // eslint-disable-next-line no-param-reassign state.styles.popper.width = "".concat(state.rects.reference.width, "px"); } }, effect: function (_a) { var _b; var state = _a.state; // eslint-disable-next-line no-param-reassign state.elements.popper.style.width = "".concat((_b = state.elements.reference) === null || _b === void 0 ? void 0 : _b.offsetWidth, "px"); }, phase: 'beforeWrite', requires: ['computeStyles'], }, { name: 'arrow', options: { padding: 12, }, }, // Отступы от якорного элемента { name: 'offset', options: { offset: offset, }, } ], tslib_1.__read((modifiersProp || [])), false); }, [offset, equalAnchorWidth, modifiersProp]); // Якорный элемент или координаты var resolveReferenceElement = (0, react_1.useMemo)(function () { if (anchorRef === null || anchorRef === void 0 ? void 0 : anchorRef.current) return anchorRef === null || anchorRef === void 0 ? void 0 : anchorRef.current; if (position) return { getBoundingClientRect: function () { return { top: (position === null || position === void 0 ? void 0 : position.y) || 0, left: (position === null || position === void 0 ? void 0 : position.x) || 0, bottom: (position === null || position === void 0 ? void 0 : position.y) || 0, right: (position === null || position === void 0 ? void 0 : position.x) || 0, width: 0, height: 0, }; }, }; return undefined; }, [anchorRef === null || anchorRef === void 0 ? void 0 : anchorRef.current, position]); var _q = (0, react_popper_1.usePopper)(resolveReferenceElement, popperElement, { placement: placement, strategy: strategy, modifiers: modifiers, }), styles = _q.styles, attributes = _q.attributes, update = _q.update; // Передача метода по перерасчету расположения компонента Popover в родительский компонент (0, react_1.useEffect)(function () { setUpdate === null || setUpdate === void 0 ? void 0 : setUpdate(update); }, [update]); (0, react_1.useEffect)(function () { var _a; // Сохраняем фокус активного элемента до момента открытия всплывающего окна if (open && !disableReturnFocus) { focusedElement.current = document.activeElement; (_a = focusedElement.current) === null || _a === void 0 ? void 0 : _a.blur(); } setOpenState(open); }, [open]); var container = (0, usePortalContainer_1.usePortalContainer)(containerProp); if (!container) { return null; } return (react_1.default.createElement(PopoverContext_1.PopoverContext.Provider, { value: { isTop: isTop } }, react_1.default.createElement(react_transition_group_1.CSSTransition, tslib_1.__assign({ nodeRef: popoverRef, classNames: (0, exports.cnPopover)({ animation: true }), timeout: 120 }, transitionProps, { in: openState, onEnter: onEnter, onEntered: onEntered, onExit: onExit, onExited: onExited, unmountOnExit: true }), react_1.default.createElement(PortalBase_1.PortalBase, tslib_1.__assign({ as: Tag }, other, { style: tslib_1.__assign(tslib_1.__assign({}, style), styles.popper), ref: portalRef, container: container, className: (0, exports.cnPopover)({ disableInteractive: disableInteractive }, [className]) }, attributes.popper), children, arrow && (react_1.default.createElement(components_1.PopoverArrow, tslib_1.__assign({}, arrowProps, { style: tslib_1.__assign(tslib_1.__assign({}, arrowProps === null || arrowProps === void 0 ? void 0 : arrowProps.style), styles.arrow), "data-popper-arrow": true }))))))); }); exports.Popover.displayName = 'Popover';