Vercel/src/utility/useClickInsideOutside.ts
2025-02-01 22:53:33 -06:00

50 lines
1.4 KiB
TypeScript

import { RefObject, useCallback, useEffect } from 'react';
const MOUSE_DOWN = 'mousedown';
interface Options {
// HTML reference
htmlElements: RefObject<HTMLElement | null>[],
// Callbacks based on click target
onClick?: (event?: MouseEvent) => void,
onClickInside?: (event?: MouseEvent) => void,
onClickOutside?: (event?: MouseEvent) => void,
// Dynamically listen to click events
shouldListenToClicks?: boolean,
}
const useClickInsideOutside = ({
htmlElements,
onClick,
onClickInside,
onClickOutside,
shouldListenToClicks = true,
}: Options) => {
const handleClick = useCallback((event: MouseEvent) => {
const target = event.target as HTMLElement;
const htmlElementsContainTarget = htmlElements
.some(element => element.current?.contains(target));
// On click
onClick?.(event);
// On click inside
if (htmlElementsContainTarget) {
onClickInside?.(event);
}
// On click outside
if (!htmlElementsContainTarget) {
onClickOutside?.(event);
}
}, [onClick, onClickInside, onClickOutside, htmlElements]);
useEffect(() => {
if (shouldListenToClicks) {
document.addEventListener(MOUSE_DOWN, handleClick);
return () => { document.removeEventListener(MOUSE_DOWN, handleClick); };
}
}, [htmlElements, shouldListenToClicks, handleClick]);
};
export default useClickInsideOutside;