wix-style-react
Version:
wix-style-react
78 lines • 3.06 kB
JavaScript
import { useEffect, useState, useCallback, useRef, Children } from 'react';
export const usePopoverState = ({ scrollAreaRef, disabled, isMenuOpen, ...rest }) => {
const children = Children.toArray(rest.children);
const popoverContentRef = useRef(null);
const [moveBy, setMoveBy] = useState({ y: 0 });
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const [isMouseOver, setIsMouseOver] = useState(false);
useEffect(() => {
const onSidebarScroll = () => !isPopoverOpen && setMoveBy({ y: 0 });
const scrollArea = scrollAreaRef && scrollAreaRef.current;
if (scrollArea) {
scrollArea && scrollArea.addEventListener('scroll', onSidebarScroll);
window.addEventListener('scroll', onSidebarScroll);
}
return () => {
scrollArea && scrollArea.removeEventListener('scroll', onSidebarScroll);
window.removeEventListener('scroll', onSidebarScroll);
};
// TODO: fix ESLint error
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [scrollAreaRef]);
const calculateMoveBy = useCallback(() => {
const rect = popoverContentRef &&
popoverContentRef.current &&
popoverContentRef.current.getBoundingClientRect();
if (!rect)
return 0;
const margin = 12;
const popoverPaddings = 2 * 12;
const screenHeight = window.innerHeight;
const { top } = rect;
const height = rect.height + popoverPaddings;
const isPopoverOffsetToTop = top <= margin;
const popoverTopValue = -(top - popoverPaddings - margin);
const isPopoverOffsetToBottom = top + height > screenHeight;
const popoverBottomValue = screenHeight - top - height - margin;
if (isPopoverOffsetToTop) {
return popoverTopValue;
}
if (isPopoverOffsetToBottom) {
return popoverBottomValue;
}
return 0;
}, [popoverContentRef]);
useEffect(() => {
let timeout;
if (isPopoverOpen) {
timeout = setTimeout(() => {
setMoveBy({ y: moveBy.y || calculateMoveBy() });
}, 200);
}
return () => {
clearTimeout(timeout);
};
}, [isPopoverOpen, calculateMoveBy, moveBy.y]);
useEffect(() => {
if (!isMouseOver) {
return;
}
setIsPopoverOpen(!isMenuOpen);
}, [isMenuOpen, isMouseOver]);
const onOpen = useCallback(() => {
if (disabled || !children || !children.length)
return;
if (!isMenuOpen) {
setIsPopoverOpen(true);
}
setIsMouseOver(true);
// TODO: fix ESLint error
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [disabled, isMenuOpen]);
const onClose = () => {
setIsPopoverOpen(false);
setIsMouseOver(false);
};
return { moveBy, popoverContentRef, isPopoverOpen, onOpen, onClose };
};
//# sourceMappingURL=usePopoverState.js.map