Mirror of https://github.com/roostorg/coop
github.com/roostorg/coop
1import { useEffect, useRef } from 'react';
2
3/**
4 * This hook can be used to capture clicks outside of a component.
5 * For example, use this in a dropdown component to capture clicks
6 * outside of the dropdown to close it.
7 * @param onClick - the callback that gets called when a user clicks
8 * outside the component in which this hook is used.
9 *
10 * Implementation details: https://www.robinwieruch.de/react-hook-detect-click-outside-component/
11 */
12export function useOutsideClick(onClick: (_: MouseEvent) => void) {
13 const ref = useRef() as React.MutableRefObject<HTMLInputElement>;
14
15 useEffect(() => {
16 const handleClick = (event: MouseEvent) => {
17 /**
18 * Some ant design components have subcomponents that aren't
19 * actually child components. They set separately in the component
20 * tree and are positioned absolutely, not relatively. These components
21 * are treated as part of the rest of the DOM, i.e. 'outside' the
22 * component referenced by the ref param.
23 * One example: the dropdown menu component in ant design's <Select />
24 * component is not a child of the <Select /> component. So clicking an
25 * item in the dropdown would normally trigger the onClick() function
26 * here, as if it were outside the dropdown component altogether,
27 * and we don't want that. So we have a few hardcoded ant design component
28 * class names that we exempt from ever being considered 'outside' a
29 * component that would use this hook.
30 */
31 const prohibitedClassNames = [
32 'ant-select-item-option-content',
33 'ant-picker-cell-inner',
34 ];
35
36 if (
37 ref.current &&
38 event.target instanceof HTMLElement &&
39 !ref.current.contains(event.target) &&
40 !prohibitedClassNames.includes(event.target.className)
41 ) {
42 onClick(event);
43 }
44 };
45
46 document.addEventListener('click', handleClick, true);
47
48 return () => {
49 document.removeEventListener('click', handleClick, true);
50 };
51 }, [ref, onClick]);
52
53 return ref;
54}