UNPKG

@nomios/web-uikit

Version:
174 lines (154 loc) 5.1 kB
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } import React, { Component, cloneElement } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import ReactModal from 'react-modal'; import scrollbarCompensate from 'scrollbar-compensate'; import { ModalCloseContext } from './ModalClose'; import styles from './Modal.css'; const MODAL_TRANSITION_DURATION = 450; document.addEventListener('DOMContentLoaded', () => { scrollbarCompensate([`.${styles.modalBodyOpen}`]); }); class Modal extends Component { constructor(...args) { super(...args); _defineProperty(this, "state", { modalStatus: 'exited', contentStatus: 'exited' }); _defineProperty(this, "handleModalEntered", () => { this.setState({ modalStatus: 'entered' }); }); _defineProperty(this, "handleModalExited", () => { this.setState({ modalStatus: 'exited' }); }); _defineProperty(this, "handleContentEntered", () => { this.setState({ contentStatus: 'entered' }); }); _defineProperty(this, "handleContentExited", () => { this.setState({ contentStatus: 'exited' }); }); } static getDerivedStateFromProps(props, state) { const { open } = props; let { contentStatus, modalStatus } = state; // Ensure the `entering` and `exiting` status for the modal, according to the `open` prop if (open && modalStatus !== 'entered') { modalStatus = 'entering'; } else if (!open && contentStatus === 'exited' && modalStatus !== 'exited') { modalStatus = 'exiting'; } // Ensure the `entering` and `exiting` status for the content, according to the `open` prop if (open && modalStatus === 'entered' && contentStatus !== 'entered') { contentStatus = 'entering'; } else if (!open && contentStatus !== 'exited') { contentStatus = 'exiting'; } return { modalStatus, contentStatus }; } componentDidMount() { if (this.props.open) { this.startEnterTimer(); } } componentDidUpdate(prevProps, prevState) { if (this.props.open && !prevProps.open) { this.startEnterTimer(); } if (this.state.contentStatus === 'entered' && prevState.contentStatus !== 'entered') { this.props.onEntered && this.props.onEntered(); } else if (this.state.modalStatus === 'exited' && prevState.modalStatus !== 'exited') { this.props.onExited && this.props.onExited(); } } componentWillUnmount() { clearTimeout(this.enterTimeoutId); } render() { const { open, shouldCloseOnEsc, shouldCloseOnOverlayClick, onRequestClose, children, className } = this.props; const { contentStatus, modalStatus } = this.state; const finalClassName = { base: classNames(styles.modal, className), afterOpen: styles.afterOpen, beforeClose: styles.beforeClose }; const finalOverlayClassName = { base: styles.modalOverlay, afterOpen: styles.afterOpen, beforeClose: styles.beforeClose }; const modalIn = open ? true : contentStatus !== 'exited'; const contentIn = open ? modalStatus === 'entered' : false; const contentProps = { in: contentIn, onEntered: this.handleContentEntered, onExited: this.handleContentExited }; return React.createElement(ModalCloseContext.Provider, { value: onRequestClose }, React.createElement(ReactModal, { isOpen: modalIn, onRequestClose: onRequestClose, closeTimeoutMS: MODAL_TRANSITION_DURATION, onAfterClose: this.handleModalExited, shouldCloseOnEsc: shouldCloseOnEsc, shouldCloseOnOverlayClick: shouldCloseOnOverlayClick, className: finalClassName, overlayClassName: finalOverlayClassName, portalClassName: styles.modalPortal, bodyOpenClassName: styles.modalBodyOpen }, React.createElement("div", { className: styles.modalCenter }, React.createElement("div", { className: styles.modalContent }, typeof children === 'function' ? children(contentProps) : cloneElement(children, { ...children.props, ...contentProps }))))); } startEnterTimer() { clearTimeout(this.enterTimeoutId); this.enterTimeoutId = setTimeout(this.handleModalEntered, MODAL_TRANSITION_DURATION); } } Modal.propTypes = { open: PropTypes.bool, shouldCloseOnEsc: PropTypes.bool, shouldCloseOnOverlayClick: PropTypes.bool, onRequestClose: PropTypes.func, onExited: PropTypes.func, onEntered: PropTypes.func, className: PropTypes.string, children: PropTypes.oneOfType([PropTypes.element, PropTypes.func]).isRequired }; Modal.defaultProps = { open: false, shouldCloseOnEsc: false, shouldCloseOnOverlayClick: false }; export const setAppElement = el => ReactModal.setAppElement(el); export default Modal;