mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-30 03:33:48 -05:00
42 lines
1.5 KiB
TypeScript
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]);
|
|
};
|