@kadoui/react
Version:
Kadoui primitive components for React
56 lines (55 loc) • 2.13 kB
JavaScript
"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 }) }));
}