@supunlakmal/hooks
Version:
A collection of reusable React hooks
61 lines • 2.74 kB
JavaScript
import { useCallback, useState } from 'react';
import { useEventListener } from '../event-handling/useEventListener'; // Reuse useEventListener
/**
* Custom hook to manage the state for a custom context menu.
* Listens for contextmenu events on the target element and provides menu state (position, visibility).
*
* @param {RefObject<HTMLElement | null>} targetRef - Ref attached to the element that triggers the context menu.
* @returns {UseContextMenuResult} An object containing menu state and control functions.
*/
export const useContextMenu = (targetRef) => {
const [isOpen, setIsOpen] = useState(false);
const [position, setPosition] = useState({ x: 0, y: 0 });
// Handler for the contextmenu event
const handleContextMenu = useCallback((event) => {
if (targetRef.current &&
targetRef.current.contains(event.target)) {
event.preventDefault(); // Prevent the default browser context menu
setIsOpen(true);
setPosition({ x: event.clientX, y: event.clientY });
}
else {
// If the event didn't originate from within the target, close any open menu
setIsOpen(false);
}
}, [targetRef]);
// Handler for clicks outside the menu area (or anywhere)
const handleClickOutside = useCallback(() => {
// We simply close the menu on any click outside the context menu itself.
// More sophisticated logic might involve checking if the click was inside
// the custom menu component, but this hook doesn't know about that component.
if (isOpen) {
// Let potential menu item clicks be handled before closing
setTimeout(() => setIsOpen(false), 0);
}
}, [isOpen]);
// Handler for scroll events - close menu on scroll
const handleScroll = useCallback(() => {
if (isOpen) {
setIsOpen(false);
}
}, [isOpen]);
// Add listeners using useEventListener for conciseness
useEventListener('contextmenu', handleContextMenu, typeof document !== 'undefined' ? document : undefined);
useEventListener('click', handleClickOutside, typeof document !== 'undefined' ? document : undefined);
useEventListener('scroll', handleScroll, typeof document !== 'undefined' ? document : undefined, { capture: true }); // Use capture for scroll
// Manual control functions
const open = useCallback((event) => {
setIsOpen(true);
setPosition({ x: event.clientX, y: event.clientY });
}, []);
const close = useCallback(() => {
setIsOpen(false);
}, []);
return {
isOpen,
position,
open,
close,
};
};
//# sourceMappingURL=useContextMenu.js.map