Skip to content

Instantly share code, notes, and snippets.

@erkobridee
Last active April 11, 2019 09:00
Show Gist options
  • Save erkobridee/fd1d04afc93b9696c55c6b6fce18ecae to your computer and use it in GitHub Desktop.
Save erkobridee/fd1d04afc93b9696c55c6b6fce18ecae to your computer and use it in GitHub Desktop.
import * as React from 'react';
export interface IClickOutsideProps {
onClick: () => void;
/** element to add the click event listener, default selector is body */
parentTargetQuerySelector?: string;
}
/**
* Function Component to re-use the behavior of click outside
*
* expects to have a children and a defined onClick callback
*/
const ClickOutside: React.FunctionComponent<IClickOutsideProps> = ({
parentTargetQuerySelector = 'body',
children,
onClick
}) => {
const refs = React.Children.map(children, () => React.useRef<any>(null));
const appElement = window.document.querySelector(parentTargetQuerySelector) || window.document;
const handleClick = React.useCallback(
(e: Event) => {
const isOutside = refs.every(ref => {
if (!ref.current) {
return false;
}
return !ref.current!.contains(e.target);
});
if (isOutside) {
onClick();
}
},
[onClick]
);
React.useEffect(() => {
appElement.addEventListener('click', handleClick);
return () => appElement.removeEventListener('click', handleClick);
}, [handleClick]);
return <>{React.Children.map(children, (element: any, idx) => React.cloneElement(element, { ref: refs[idx] }))}</>;
};
export default ClickOutside;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment