diff options
Diffstat (limited to 'src/utils/hooks/use-on-click-outside/use-on-click-outside.ts')
| -rw-r--r-- | src/utils/hooks/use-on-click-outside/use-on-click-outside.ts | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/src/utils/hooks/use-on-click-outside/use-on-click-outside.ts b/src/utils/hooks/use-on-click-outside/use-on-click-outside.ts new file mode 100644 index 0000000..c9a1132 --- /dev/null +++ b/src/utils/hooks/use-on-click-outside/use-on-click-outside.ts @@ -0,0 +1,38 @@ +import { useCallback, useEffect, useRef, type MutableRefObject } from 'react'; + +export type useOnClickOutsideHandler = (ev: MouseEvent | FocusEvent) => void; + +/** + * Detect clicks (or focus) outside a component. + * + * @param {useOnClickOutsideHandler} [handler] - A function to handle the event. + * @returns {RefObject<T>} A ref object. + */ +export const useOnClickOutside = <T extends HTMLElement>( + handler?: useOnClickOutsideHandler +): MutableRefObject<T | null> => { + const ref = useRef<T | null>(null); + + const listener = useCallback( + (ev: MouseEvent | FocusEvent) => { + if (!handler || !ref.current || ref.current.contains(ev.target as Node)) { + return; + } + + handler(ev); + }, + [handler] + ); + + useEffect(() => { + document.addEventListener('click', listener, true); + document.addEventListener('focusin', listener, true); + + return () => { + document.removeEventListener('click', listener, true); + document.removeEventListener('focusin', listener, true); + }; + }, [listener]); + + return ref; +}; |
