@brizy/ui
Version:
React elements in Brizy style
76 lines (75 loc) • 2.96 kB
JavaScript
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: [],
};