@spaced-out/ui-design-system
Version:
Sense UI components library
130 lines (129 loc) • 4.53 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ClickAway = void 0;
var React = _interopRequireWildcard(require("react"));
var _invariant = _interopRequireDefault(require("invariant"));
var _dom = require("../dom");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
// TODO(Nishant): Make this a functional component
class ClickAway extends React.Component {
static defaultProps = {
containsNestedFloatingPortals: false,
closeOnEscapeKeypress: true
};
state = {
isOpen: false,
height: null,
pageBottom: null
};
el = null;
boundaryRef = /*#__PURE__*/React.createRef();
triggerRef = /*#__PURE__*/React.createRef();
componentDidMount() {
if (this.el) {
this.setState({
height: this.el.offsetHeight,
pageBottom: this.pageBottom()
});
}
}
componentDidUpdate(prevProps, prevState) {
const {
isOpen
} = this.state;
if (prevState.isOpen !== isOpen) {
if (this.state.isOpen) {
window.document.addEventListener('click', this.handleCloseClick, {
capture: true
});
if (this.props.closeOnEscapeKeypress) {
window.document.addEventListener('keyup', this.handleCloseOnEscapeKeypress);
}
} else {
window.document.removeEventListener('click', this.handleCloseClick, {
capture: true
});
window.document.removeEventListener('keyup', this.handleCloseOnEscapeKeypress);
}
}
}
componentWillUnmount() {
window.document.removeEventListener('click', this.handleCloseClick, {
capture: true
});
window.document.removeEventListener('keyup', this.handleCloseOnEscapeKeypress);
}
render() {
const {
height,
isOpen,
pageBottom
} = this.state;
const {
clickAwayRef
} = this.props;
if (clickAwayRef) {
clickAwayRef.current = {
forceClose: this.forceClose,
forceOpen: this.handleOpenClick
};
}
return this.props.children({
onOpen: this.handleOpenClick,
isOpen,
height,
pageBottom,
clickAway: this.forceClose,
boundaryRef: this.boundaryRef,
triggerRef: this.triggerRef
});
}
handleOpenClick = () => {
// NOTE (kyle): we recalculate the position on click because sibling and niece components
// could have changed.
let {
pageBottom
} = this.state;
if (this.el) {
pageBottom = this.pageBottom();
}
this.setState({
isOpen: !this.state.isOpen,
pageBottom
}, this.handleOnChange);
};
handleCloseClick = evt => {
if (evt.target instanceof Node && this.props.containsNestedFloatingPortals && this.boundaryRef.current?.parentElement && (this.boundaryRef.current.parentElement === evt.target || this.boundaryRef.current.parentElement.contains(evt.target))) {
return;
}
if (evt.target instanceof Node && this.boundaryRef && (this.boundaryRef === evt.target || this.boundaryRef.current?.contains(evt.target))) {
return;
}
if (evt.target instanceof Node && this.triggerRef && (this.triggerRef === evt.target || this.triggerRef.current?.contains(evt.target))) {
return;
}
this.setState({
isOpen: false
}, this.handleOnChange);
};
handleCloseOnEscapeKeypress = evt => {
if (evt?.key === 'Escape') {
this.forceClose();
}
};
forceClose = () => {
this.setState({
isOpen: false
}, this.handleOnChange);
};
handleOnChange = () => this.props.onChange && this.props.onChange(this.state.isOpen);
pageBottom() {
(0, _invariant.default)(this.el, 'pageBottom() requires that this.el not be null');
const bottomBound = this.el ? this.el.getBoundingClientRect().bottom : 0;
return (0, _dom.pageHeight)() - bottomBound + window.scrollY;
}
}
exports.ClickAway = ClickAway;