UNPKG

wix-style-react

Version:
79 lines 3.55 kB
import React, { forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useRef, useState, } from 'react'; import Popover from '../../Popover'; import { SidebarNextContext } from '../../SidebarNext/SidebarNextContext'; import { classes } from '../SidebarSubMenuNext.st.css'; export const ContextMenuPopover = forwardRef(({ element, content, disabled, dataHook, onShow, onHide }, ref) => { const { skin, scrollAreaRef } = useContext(SidebarNextContext); const popoverContentRef = useRef(null); const [shouldShow, setShouldShow] = useState(false); const visible = !disabled && shouldShow; const showPopover = useCallback(() => { setShouldShow(true); }, []); const hidePopover = useCallback(() => { setShouldShow(false); }, []); useImperativeHandle(ref, () => ({ hide: hidePopover, }), [hidePopover]); const popoverOffset = usePopoverOffset(visible, scrollAreaRef, popoverContentRef); return (React.createElement(Popover, { dataHook: dataHook, className: classes.navigationPopoverRoot, shown: visible, showArrow: true, fixed: true, appendTo: "window", placement: "right", zIndex: 3000, flip: false, theme: skin === 'neutral' ? 'light' : skin, moveBy: popoverOffset, animate: visible, hideDelay: 50, showDelay: 200, onMouseEnter: showPopover, onMouseLeave: hidePopover, onShow: onShow, onHide: onHide }, React.createElement(Popover.Element, null, element), React.createElement(Popover.Content, null, React.createElement("ul", { ref: popoverContentRef, className: classes.navigationPopover, "aria-hidden": true }, content)))); }); const usePopoverOffset = (popoverVisible, scrollAreaRef, popoverContentRef) => { // FIXME: doesn't work in the original implementation (and here too) const [moveBy, setMoveBy] = useState({ y: 0 }); useEffect(() => { const scrollArea = scrollAreaRef?.current; if (!scrollArea) { return; } const handleScroll = () => { if (!popoverVisible) { setMoveBy({ y: 0 }); } }; scrollArea && scrollArea.addEventListener('scroll', handleScroll); window.addEventListener('scroll', handleScroll); return () => { scrollArea && scrollArea.removeEventListener('scroll', handleScroll); window.removeEventListener('scroll', handleScroll); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [scrollAreaRef]); useEffect(() => { if (!popoverVisible) { return; } const timeout = setTimeout(() => { const y = moveBy.y || calculateOffsetY(popoverContentRef.current); setMoveBy({ y }); }, 200); return () => { clearTimeout(timeout); }; }, [popoverVisible, moveBy.y, popoverContentRef]); return moveBy; }; const calculateOffsetY = (popoverContentElement) => { // FIXME: mostly copy-pasta of original implementation const rect = popoverContentElement?.getBoundingClientRect(); if (!rect) { return 0; } const margin = 12; const popoverPaddings = 2 * 12; const screenHeight = window.innerHeight; const { top } = rect; const height = rect.height + popoverPaddings; if (top <= margin) { return -(top - popoverPaddings - margin); } if (top + height > screenHeight) { return screenHeight - top - height - margin; } return 0; }; //# sourceMappingURL=ContextMenuPopover.js.map