@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
166 lines (165 loc) • 4.6 kB
JavaScript
"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