UNPKG

@kadoui/react

Version:

Kadoui primitive components for React

56 lines (55 loc) 2.13 kB
"use client"; import { jsx as _jsx } from "react/jsx-runtime"; import { useCallback, useEffect, useRef, useState } from "react"; import { getBrowserScrollbarWith } from "../../utils"; import { ContextMenuContext } from "./ContextMenuContext"; export function ContextMenuRoot({ onContextMenu, ...p }) { const [position, setPosition] = useState(undefined); const [isOpen, setOpen] = useState(false); const contentRef = useRef(null); const handleClickOutside = useCallback((ev) => { if (!contentRef.current?.contains(ev.target)) { setOpen(false); setPosition(undefined); } }, []); useEffect(() => { document.addEventListener("click", handleClickOutside); return () => document.removeEventListener("click", handleClickOutside); }, [handleClickOutside]); useEffect(() => { const scrollbarWidth = getBrowserScrollbarWith(); if (isOpen) { document.body.style.overflow = "hidden"; document.body.style.paddingRight = `${scrollbarWidth}px`; } else { document.body.style.overflow = "unset"; document.body.style.paddingRight = "0px"; } ; }, [isOpen]); const handleContextMenu = (ev) => { if (!contentRef.current) return; ev.preventDefault(); const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; const menuWidth = contentRef.current.scrollWidth; const menuHeight = contentRef.current.scrollHeight; let x = ev.clientX; let y = ev.clientY; if (x + menuWidth > viewportWidth) { x = viewportWidth - menuWidth - 10; } if (y + menuHeight > viewportHeight) { y = viewportHeight - menuHeight - 10; } setPosition({ x, y }); setOpen(true); }; return (_jsx(ContextMenuContext, { value: { contentRef, isOpen, position }, children: _jsx("div", { onContextMenu: ev => { onContextMenu?.(ev); handleContextMenu(ev); }, ...p }) })); }