67 lines
2.2 KiB
TypeScript
67 lines
2.2 KiB
TypeScript
import { useEffect, useRef } from "react";
|
|
|
|
export function useOuterClick(
|
|
callback: () => void,
|
|
contextClassNames: string[],
|
|
enabled: boolean = true,
|
|
ignoreIfMoved: boolean = true,
|
|
clickType: "left" | "right" = "left",
|
|
dependencies: any[] = []
|
|
) {
|
|
const callbackRef = useRef(callback);
|
|
const classNamesRef = useRef(contextClassNames);
|
|
const mouseDownTargetRef = useRef<EventTarget | null>(null);
|
|
const movedRef = useRef(false);
|
|
|
|
// Keep refs updated
|
|
useEffect(() => {
|
|
callbackRef.current = callback;
|
|
}, [callback]);
|
|
|
|
useEffect(() => {
|
|
classNamesRef.current = contextClassNames;
|
|
}, [contextClassNames]);
|
|
|
|
useEffect(() => {
|
|
if (!enabled) return;
|
|
|
|
const handleMouseDown = (event: MouseEvent) => {
|
|
mouseDownTargetRef.current = event.target;
|
|
movedRef.current = false;
|
|
};
|
|
|
|
const handleMouseMove = () => {
|
|
movedRef.current = true;
|
|
};
|
|
|
|
const handleMouseUp = (event: MouseEvent) => {
|
|
const downTarget = mouseDownTargetRef.current as HTMLElement | null;
|
|
const upTarget = event.target as HTMLElement;
|
|
if (!downTarget || !upTarget) return;
|
|
|
|
// Check click type
|
|
const isCorrectClick = (clickType === "left" && event.button === 0) || (clickType === "right" && event.button === 2);
|
|
|
|
if (!isCorrectClick) return;
|
|
if (ignoreIfMoved && movedRef.current) return;
|
|
|
|
// Check if click is inside any ignored context
|
|
const isInside = classNamesRef.current.some((className) => downTarget.closest(`.${className}`) || upTarget.closest(`.${className}`));
|
|
|
|
if (!isInside) {
|
|
callbackRef.current();
|
|
}
|
|
};
|
|
|
|
document.addEventListener("mousedown", handleMouseDown);
|
|
document.addEventListener("mousemove", handleMouseMove);
|
|
document.addEventListener("mouseup", handleMouseUp);
|
|
|
|
return () => {
|
|
document.removeEventListener("mousedown", handleMouseDown);
|
|
document.removeEventListener("mousemove", handleMouseMove);
|
|
document.removeEventListener("mouseup", handleMouseUp);
|
|
};
|
|
}, [enabled, ignoreIfMoved, clickType, ...dependencies]);
|
|
}
|