UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

166 lines (165 loc) 4.6 kB
"use client"; import React, { useCallback, useContext, useEffect, useState } from 'react'; import classnames from 'classnames'; import { makeUniqueId } from "../../shared/component-helper.js"; import useMountEffect from "../../shared/helpers/useMountEffect.js"; import useMounted from "../../shared/helpers/useMounted.js"; import { useTheme } from "../../shared/index.js"; import { getThemeClasses } from "../../shared/Theme.js"; import PortalRoot from "../PortalRoot.js"; import ModalContext from "../modal/ModalContext.js"; import PopoverContainer from "./PopoverContainer.js"; let popoverPortal; if (typeof globalThis !== 'undefined') { globalThis.popoverPortal = globalThis.popoverPortal || {}; popoverPortal = globalThis.popoverPortal; } else { popoverPortal = {}; } function PopoverPortal(props) { const { baseClassNames = ['dnb-popover'], active, targetElement, showDelay, hideDelay, keepInDOM, noAnimation, portalRootClass, children, attributes, arrowPosition, placement, alignOnTarget, horizontalOffset, arrowPositionSelector, fixedPosition, contentRef, triggerOffset, autoAlignMode, hideArrow, arrowEdgeOffset, targetRefreshKey } = props; const [id] = useState(() => makeUniqueId()); const modalContext = useContext(ModalContext); const theme = useTheme(); const { isActive: portalActive, shouldRenderPortal } = usePopoverPortalLifecycle({ id, active, hideDelay, keepInDOM, noAnimation }); if (!shouldRenderPortal) { return null; } return React.createElement(PortalRoot, null, React.createElement("div", { className: classnames(baseClassNames.map(base => `${base}__portal`), portalRootClass, theme && getThemeClasses(theme), (modalContext === null || modalContext === void 0 ? void 0 : modalContext.id) && baseClassNames.map(base => `${base}--inside-modal`)) }, React.createElement(PopoverContainer, { baseClassNames: baseClassNames, active: portalActive, targetElement: targetElement || null, showDelay: showDelay, hideDelay: hideDelay, keepInDOM: keepInDOM, noAnimation: noAnimation, arrowPosition: arrowPosition, placement: placement, alignOnTarget: alignOnTarget, horizontalOffset: horizontalOffset, arrowPositionSelector: arrowPositionSelector, fixedPosition: fixedPosition, attributes: attributes, contentRef: contentRef, triggerOffset: triggerOffset, autoAlignMode: autoAlignMode, hideArrow: hideArrow, arrowEdgeOffset: arrowEdgeOffset, targetRefreshKey: targetRefreshKey }, children))); } export default PopoverPortal; function usePopoverPortalLifecycle({ id, active, hideDelay, keepInDOM, noAnimation }) { const [isActive, setIsActive] = useState(active); const [isInDOM, setIsInDOM] = useState(() => keepInDOM || active); const isMountedRef = useMounted(); const ensurePortalEntry = useCallback(() => { if (!popoverPortal[id]) { popoverPortal[id] = { count: 0 }; } return popoverPortal[id]; }, [id]); const clearTimers = useCallback(() => { const entry = popoverPortal[id]; if (entry) { clearTimeout(entry.delayTimeout); clearTimeout(entry.hiddenTimeout); } }, [id]); useEffect(() => { const entry = ensurePortalEntry(); if (active) { clearTimers(); setIsActive(true); setIsInDOM(true); if (!isMountedRef.current) { entry.count++; } return () => { clearTimers(); }; } if (keepInDOM) { clearTimers(); setIsActive(false); setIsInDOM(true); return () => { clearTimers(); }; } if (!isMountedRef.current) { return () => { clearTimers(); }; } const delayRender = () => setIsActive(false); const delayHidden = () => { setIsInDOM(false); }; if (noAnimation || globalThis.IS_TEST) { delayRender(); delayHidden(); return () => { clearTimers(); }; } const delay = parseFloat(String(hideDelay)); entry.delayTimeout = setTimeout(delayRender, delay); entry.hiddenTimeout = setTimeout(delayHidden, delay + 300); return () => { clearTimers(); }; }, [active, clearTimers, ensurePortalEntry, hideDelay, isMountedRef, keepInDOM, noAnimation]); useMountEffect(() => { if (keepInDOM) { ensurePortalEntry(); } }); return { isActive, shouldRenderPortal: isInDOM || keepInDOM }; } //# sourceMappingURL=PopoverPortal.js.map