50 lines
1.4 KiB
TypeScript
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;
|