Files
formbricks/apps/web/lib/utils/hooks/useClickOutside.ts
T
2025-10-07 11:20:16 +05:30

42 lines
1.5 KiB
TypeScript

import { RefObject, useEffect } from "react";
// Helper function to check if a value is a DOM element with contains method
const isDOMElement = (element: unknown): element is HTMLElement => {
return element instanceof HTMLElement;
};
// Improved version of https://usehooks.com/useOnClickOutside/
export const useClickOutside = (
ref: RefObject<HTMLElement | HTMLDivElement | null>,
handler: (event: MouseEvent | TouchEvent) => void
): void => {
useEffect(() => {
let startedInside = false;
let startedWhenMounted = false;
const listener = (event: MouseEvent | TouchEvent) => {
// Do nothing if `mousedown` or `touchstart` started inside ref element
if (startedInside || !startedWhenMounted) return;
// Do nothing if clicking ref's element or descendent elements
if (!isDOMElement(ref.current) || ref.current.contains(event.target as Node)) return;
handler(event);
};
const validateEventStart = (event: MouseEvent | TouchEvent) => {
startedWhenMounted = isDOMElement(ref.current);
startedInside = isDOMElement(ref.current) && ref.current.contains(event.target as Node);
};
document.addEventListener("mousedown", validateEventStart);
document.addEventListener("touchstart", validateEventStart);
document.addEventListener("click", listener);
return () => {
document.removeEventListener("mousedown", validateEventStart);
document.removeEventListener("touchstart", validateEventStart);
document.removeEventListener("click", listener);
};
}, [ref, handler]);
};