UNPKG

@brizy/ui

Version:
76 lines (75 loc) 2.96 kB
import React from "react"; import ReactDOM from "react-dom"; const instances = []; export class ClickOutside extends React.Component { constructor() { super(...arguments); this.handleAll = (e) => { const el = e.target; instances.forEach(instance => { const { exceptions, onClickOutside } = instance.props; let exceptionsCount = 0; if (exceptions.length > 0) { const { functionExceptions, stringExceptions } = exceptions.reduce((acc, exception) => { switch (typeof exception) { case "function": acc.functionExceptions.push(exception); break; case "string": acc.stringExceptions.push(exception); break; } return acc; }, { functionExceptions: [], stringExceptions: [] }); if (functionExceptions.length > 0) { exceptionsCount += functionExceptions.filter(exception => exception(el)).length; } if (exceptionsCount === 0 && stringExceptions.length > 0) { exceptionsCount += el.closest(stringExceptions.join(",")) ? 1 : 0; } } if (exceptionsCount === 0) { // eslint-disable-next-line react/no-find-dom-node const node = ReactDOM.findDOMNode(instance); if (node && !node.contains(el)) { onClickOutside(e); } } }); }; } componentDidMount() { // we add just one listener for all instances // because otherwise we would end up with tens of // listeners on the document // (and it's a little faster when adding just one) if (instances.length === 0) { try { document.addEventListener("mousedown", this.handleAll, true); window.parent.document.addEventListener("mousedown", this.handleAll, true); } catch (error) { console.error(error); } } instances.push(this); } componentWillUnmount() { instances.splice(instances.indexOf(this), 1); if (instances.length === 0) { try { document.removeEventListener("mousedown", this.handleAll, true); window.parent.document.removeEventListener("mousedown", this.handleAll, true); } catch (error) { console.error(error); } } } render() { return React.Children.only(this.props.children); } } ClickOutside.defaultProps = { exceptions: [], };