-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuseOnClickOutside.ts
34 lines (28 loc) · 1.05 KB
/
useOnClickOutside.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import { useEffect, useRef } from 'react';
const DEFAULT_EVENTS = ['mousedown', 'touchstart'];
export function useOnClickOutside<T extends HTMLElement = any>(
handler: () => void,
events?: string[] | null,
nodes?: (HTMLElement | null)[],
) {
const ref = useRef<T>();
useEffect(() => {
const listener = (event: any) => {
const { target } = event ?? {};
if (Array.isArray(nodes)) {
const shouldIgnore =
target?.hasAttribute('data-ignore-outside-clicks') ||
(!document.body.contains(target) && target.tagName !== 'HTML');
const shouldTrigger = nodes.every(node => !!node && !event.composedPath().includes(node));
shouldTrigger && !shouldIgnore && handler();
} else if (ref.current && !ref.current.contains(target)) {
handler();
}
};
(events || DEFAULT_EVENTS).forEach(fn => document.addEventListener(fn, listener));
return () => {
(events || DEFAULT_EVENTS).forEach(fn => document.removeEventListener(fn, listener));
};
}, [ref, handler, nodes]);
return ref;
}