import * as React from 'react'; interface IClickOutsideProps extends React.HTMLProps { active: boolean, children: any, onTrigger: (event: Event, isClick: boolean) => void, triggerOnClick: boolean, triggerOnEsc: boolean, } export class ClickOutside extends React.PureComponent { public static defaultProps = { active: true, triggerOnClick: true, triggerOnEsc: true, }; private wrapperRef = React.createRef(); public componentDidMount() { const { active } = this.props; if (active) { this.bindEvents(); } } public componentWillUnmount() { const { active } = this.props; if (active) { this.bindEvents(); } } public componentDidUpdate(prevProps: IClickOutsideProps) { const { active } = this.props; if (active !== prevProps.active) { if (active) { this.bindEvents(); } else { this.unbindEvents(); } } } public bindEvents() { document.addEventListener('click', this.handleClick); document.addEventListener('keydown', this.handleKeyDown); } public unbindEvents = () => { document.removeEventListener('click', this.handleClick); document.removeEventListener('keydown', this.handleKeyDown); }; public handleClick = (event: Event) => { const { triggerOnClick, onTrigger } = this.props; const { target, type } = event; const isClick = type === 'click'; if (triggerOnClick && !this.wrapperRef.current!.contains(target as Element)) { onTrigger(event, isClick); } }; public handleKeyDown = (event: KeyboardEvent) => { const { triggerOnEsc, onTrigger } = this.props; if (triggerOnEsc && event.key === 'Escape') { onTrigger(event, false); } }; public render() { const { active, children, onTrigger, triggerOnClick, triggerOnEsc, ...rest } = this.props; return (
{children}
); } }