UNPKG

@spaced-out/ui-design-system

Version:
130 lines (129 loc) 4.53 kB
"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;