Skip to content

Instantly share code, notes, and snippets.

@sujinleeme
Created April 4, 2020 09:08
Show Gist options
  • Save sujinleeme/2bccf6f94226cc8ec20f7a3699e5da5f to your computer and use it in GitHub Desktop.
Save sujinleeme/2bccf6f94226cc8ec20f7a3699e5da5f to your computer and use it in GitHub Desktop.
import { RefObject, useEffect } from 'react';
const MOUSEDOWN = 'mousedown';
const TOUCHSTART = 'touchstart';
type HandledEvents = [typeof MOUSEDOWN, typeof TOUCHSTART];
interface UseOnClickOutsideProps {
innerRef: RefObject<HTMLElement>;
outerRef?: RefObject<HTMLElement> | { current: HTMLDocument };
handler?: {
innerRef?: () => void;
outerRef?: () => void;
};
}
const useOnClickOutside = ({
innerRef,
outerRef = { current: document },
handler,
}: UseOnClickOutsideProps) => {
useEffect(() => {
if (!handler || !innerRef) return;
const outRefListener = (e: Event): void => {
if (!innerRef.current || !handler || innerRef.current.contains(e.target as Node)) return;
e.preventDefault();
e.stopPropagation();
handler.outerRef && handler.outerRef();
};
const innerRefListener = (e: Event): void => {
e.stopPropagation();
handler.innerRef && handler.innerRef();
};
const events: HandledEvents = [MOUSEDOWN, TOUCHSTART];
events.forEach(event => {
outerRef.current && outerRef.current.addEventListener(event, outRefListener);
innerRef.current && innerRef.current.addEventListener(event, innerRefListener);
});
return () => {
events.forEach(event => {
outerRef.current && outerRef.current.removeEventListener(event, outRefListener);
innerRef.current && innerRef.current.removeEventListener(event, innerRefListener);
});
};
}, [handler]);
};
export default useOnClickOutside;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment