UNPKG

react-modal-construction-kit

Version:
365 lines (311 loc) 11.1 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.getTransitionStyles = undefined; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); var _Portal = require('../Portal/Portal'); var _Portal2 = _interopRequireDefault(_Portal); var _reactTransitionGroup = require('react-transition-group'); var _utils = require('../utils'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var getTransitionStyles = exports.getTransitionStyles = function getTransitionStyles() { return { exited: { display: 'none' }, entering: { opacity: 0.01, transform: 'scale(1.05)' }, entered: { opacity: 1, transform: 'none' }, exiting: { opacity: 0.01, transform: 'scale(0.90)' } }; }; var getStyle = function getStyle(_ref) { var zIndex = _ref.zIndex, isCentered = _ref.isCentered, transitionDuration = _ref.transitionDuration; return { component: { overflowX: 'hidden', overflowY: 'auto', position: 'fixed', top: 0, right: 0, bottom: 0, left: 0, zIndex: zIndex, outline: 0, transition: 'opacity ' + transitionDuration / 2 + 'ms linear, transform ' + transitionDuration + 'ms ease-out' }, dialog: { display: 'flex', alignItems: 'center', position: 'relative', maxWidth: '500px', margin: isCentered ? '0 auto' : '1.75rem auto', minHeight: isCentered && '100%', width: 'auto', boxSizing: 'border-box', pointerEvents: 'none' }, content: { position: 'relative', WebkitBoxOrient: 'vertical', WebkitBoxDirection: 'normal', MsFlexDirection: 'column', flexDirection: 'column', width: '100%', pointerEvents: 'auto', backgroundColor: 'white', backgroundClip: 'padding-box', outline: 0, display: 'flex', boxSizing: 'border-box' } }; }; var Modal = function (_React$Component) { _inherits(Modal, _React$Component); function Modal(props) { _classCallCheck(this, Modal); var _this = _possibleConstructorReturn(this, (Modal.__proto__ || Object.getPrototypeOf(Modal)).call(this, props)); _this.onOpened = function (node, isAppearing) { var _this$props = _this.props, onOpened = _this$props.onOpened, onEntered = _this$props.onEntered; onOpened(); onEntered(node, isAppearing); }; _this.onClosed = function (node) { var _this$props2 = _this.props, onClosed = _this$props2.onClosed, onExited = _this$props2.onExited; onClosed(); onExited(node); _this.destroy(); if (_this._isMounted) { _this.setState({ isOpen: false }); } }; _this.handleEscape = function (e) { var _this$props3 = _this.props, isOpen = _this$props3.isOpen, hasEscapeClose = _this$props3.hasEscapeClose, onClosed = _this$props3.onClosed; if (isOpen && hasEscapeClose && e.keyCode === 27 && onClosed) { onClosed(); } }; _this.handleClick = function (e) { var hasClickedOutside = !_this.contentRef.contains(e.target); if (hasClickedOutside) { _this.props.onClosed(); } }; _this.element = null; _this.originalBodyPadding = null; _this.state = { isOpen: props.isOpen }; if (props.isOpen) { _this.init(); } return _this; } _createClass(Modal, [{ key: 'componentDidMount', value: function componentDidMount() { if (this.props.onEnter) { this.props.onEnter(); } if (this.state.isOpen && this.props.autoFocus) { this.setFocus(); } window.addEventListener('keydown', this.handleEscape, true); this._isMounted = true; } }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { if (nextProps.isOpen && !this.props.isOpen) { this.setState({ isOpen: nextProps.isOpen }); } } }, { key: 'componentWillUpdate', value: function componentWillUpdate(nextProps, nextState) { if (nextState.isOpen && !this.state.isOpen) { this.init(); } } }, { key: 'componentDidUpdate', value: function componentDidUpdate(prevProps, prevState) { if (this.props.autoFocus && this.state.isOpen && !prevState.isOpen) { this.setFocus(); } } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { if (this.props.onExit) { this.props.onExit(); } if (this.state.isOpen) { this.destroy(); } window.removeEventListener('keydown', this.handleEscape, true); this._isMounted = false; } }, { key: 'setFocus', value: function setFocus() { if (this.dialogRef && this.dialogRef.parentNode && typeof this.dialogRef.parentNode.focus === 'function') { this.dialogRef.parentNode.focus(); } } }, { key: 'init', value: function init() { this.element = document.createElement('div'); this.element.setAttribute('tabindex', '-1'); this.element.style.position = 'relative'; this.element.style.zIndex = this.props.zIndex; this.originalBodyPadding = (0, _utils.getOriginalBodyPadding)(); (0, _utils.conditionallyUpdateScrollbar)(); document.body.appendChild(this.element); if (!this._bodyStyleAdded) { document.body.style.overflow = 'hidden'; this._bodyStyleAdded = true; } } }, { key: 'destroy', value: function destroy() { if (this.element) { document.body.removeChild(this.element); this.element = null; } if (this._bodyStyleAdded) { document.body.style.overflow = null; this._bodyStyleAdded = false; } (0, _utils.setScrollbarWidth)(this.originalBodyPadding); } }, { key: 'render', value: function render() { var _this2 = this; if (!this.state.isOpen) { return null; } var _props = this.props, isOpen = _props.isOpen, role = _props.role, transitionDuration = _props.transitionDuration, children = _props.children, className = _props.className, dialogClassName = _props.dialogClassName, contentClassName = _props.contentClassName, hasOutsideClickClose = _props.hasOutsideClickClose; var style = getStyle(this.props); return _react2.default.createElement( _Portal2.default, { node: this.element }, _react2.default.createElement( _reactTransitionGroup.Transition, { appear: true, onEntered: this.onOpened, onExited: this.onClosed, timeout: transitionDuration, 'in': isOpen }, function (state) { return _react2.default.createElement( 'div', { onClick: hasOutsideClickClose ? _this2.handleClick : null, tabIndex: '-1', role: role, className: className, style: _extends({}, style.component, getTransitionStyles()[state]) }, _react2.default.createElement( 'div', { className: dialogClassName, style: style.dialog, role: 'document', ref: function ref(c) { _this2.dialogRef = c; } }, _react2.default.createElement( 'div', { className: contentClassName, ref: function ref(c) { _this2.contentRef = c; }, style: style.content }, children ) ) ); } ) ); } }]); return Modal; }(_react2.default.Component); Modal.propTypes = { isOpen: _propTypes2.default.bool, autoFocus: _propTypes2.default.bool, hasEscapeClose: _propTypes2.default.bool, hasOutsideClickClose: _propTypes2.default.bool, role: _propTypes2.default.string, onEnter: _propTypes2.default.func, onExit: _propTypes2.default.func, onOpened: _propTypes2.default.func, onClosed: _propTypes2.default.func, zIndex: _propTypes2.default.number, children: _propTypes2.default.node.isRequired, onEntered: _propTypes2.default.func, onExited: _propTypes2.default.func, transitionDuration: _propTypes2.default.number, className: _propTypes2.default.string, dialogClassName: _propTypes2.default.string, contentClassName: _propTypes2.default.string, // eslint-disable-next-line react/no-unused-prop-types isCentered: _propTypes2.default.bool }; Modal.defaultProps = { isOpen: false, autoFocus: true, role: 'dialog', zIndex: 750, onOpened: _utils.noop, hasEscapeClose: true, hasOutsideClickClose: true, onClosed: _utils.noop, transitionDuration: 300, onEntered: _utils.noop, onExited: _utils.noop, isCentered: true }; exports.default = Modal;