@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
156 lines (155 loc) • 5.04 kB
JavaScript
"use client";
import React, { useCallback, useEffect, useRef, useState } from 'react';
import clsx from 'clsx';
import { warn, getClosestScrollViewElement } from "../../shared/component-helper.js";
import PortalRoot from "../../components/PortalRoot.js";
import { jsx as _jsx } from "react/jsx-runtime";
function DrawerListPortal({
ref: refProp,
id,
open,
rootRef = {
current: undefined
},
includeOwnerWidth,
independentWidth,
fixedPosition,
skipPortal,
className,
children
}) {
const [isMounted, setIsMounted] = useState(false);
const [, setForceRerender] = useState();
const localRef = useRef(null);
const portalRef = refProp && typeof refProp !== 'function' ? refProp : localRef;
const setPosition = useRef(undefined);
const positionTimeout = useRef(undefined);
const customElem = useRef(undefined);
const resizeObserver = useRef(undefined);
const init = useCallback(() => {
setIsMounted(true);
}, []);
const removePositionObserver = useCallback(() => {
clearTimeout(positionTimeout.current);
if (typeof window !== 'undefined' && setPosition.current) {
if (customElem.current) {
customElem.current.removeEventListener('scroll', setPosition.current);
}
if (resizeObserver.current) {
resizeObserver.current.disconnect();
resizeObserver.current = null;
}
window.removeEventListener('resize', setPosition.current);
}
setPosition.current = null;
}, []);
useEffect(() => {
if (document.readyState === 'complete') {
init();
} else if (typeof window !== 'undefined') {
window.addEventListener('load', init);
}
}, [init]);
useEffect(() => {
return () => {
if (typeof window !== 'undefined') {
window.removeEventListener('load', init);
}
removePositionObserver();
};
}, [init, removePositionObserver]);
const makeStyle = useCallback(() => {
if (typeof window === 'undefined' || !isMounted) {
return undefined;
}
try {
const rootElem = rootRef.current;
if (!rootElem) {
return undefined;
}
const ownerElem = rootElem.parentElement;
let width = 64;
const ownerWidth = window.getComputedStyle(ownerElem).width;
if (independentWidth || parseFloat(ownerWidth) < 64) {
let minWidth = 0;
if (portalRef.current) {
minWidth = parseFloat(window.getComputedStyle(portalRef.current).getPropertyValue('--drawer-list-width')) || 0;
}
width = minWidth * 16;
}
const customWidth = rootElem.getBoundingClientRect().width;
if (!independentWidth && (customWidth || 0) >= 64) {
width = customWidth;
}
const rect = rootElem.getBoundingClientRect();
const scrollY = fixedPosition ? 0 : window.scrollY !== undefined ? window.scrollY : window.pageYOffset;
const scrollX = fixedPosition ? 0 : window.scrollX !== undefined ? window.scrollX : window.pageXOffset;
let top = scrollY + rect.top;
let left = scrollX + rect.left + (includeOwnerWidth ? parseFloat(ownerWidth || '0') : 0);
if (width > window.innerWidth) {
width = window.innerWidth;
}
if (top < 0) {
top = 0;
}
if (left < 0) {
left = 0;
}
const style = {
width,
'--drawer-list-width': `${width / 16}rem`,
top,
left
};
return style;
} catch (e) {
warn(e);
}
return undefined;
}, [isMounted, rootRef, independentWidth, fixedPosition, includeOwnerWidth, portalRef]);
const addPositionObserver = useCallback(() => {
if (setPosition.current || typeof window === 'undefined') {
return undefined;
}
setPosition.current = () => {
clearTimeout(positionTimeout.current);
positionTimeout.current = setTimeout(() => {
if (open) {
setForceRerender(Date.now());
}
}, 200);
};
customElem.current = getClosestScrollViewElement(rootRef.current) || window;
customElem.current.addEventListener('scroll', setPosition.current);
try {
resizeObserver.current = new ResizeObserver(setPosition.current);
resizeObserver.current.observe(document.body);
} catch (e) {
window.addEventListener('resize', setPosition.current);
}
}, [open, rootRef]);
if (skipPortal) {
return children;
}
if (typeof window !== 'undefined' && isMounted) {
if (open) {
addPositionObserver();
}
const style = open ? makeStyle() : {};
return _jsx(PortalRoot, {
children: _jsx("span", {
className: "dnb-drawer-list__portal",
id: `${id}-portal`,
ref: portalRef,
children: _jsx("span", {
className: clsx('dnb-drawer-list__portal__style', className, fixedPosition && 'dnb-drawer-list__portal__style--fixed'),
style: style,
children: children
})
})
});
}
return null;
}
export default DrawerListPortal;
//# sourceMappingURL=DrawerListPortal.js.map