"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = exports.styles = void 0;

var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));

var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));

var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));

var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));

var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));

var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));

var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized"));

var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));

var _react = _interopRequireDefault(require("react"));

var _reactDom = _interopRequireDefault(require("react-dom"));

var _propTypes = _interopRequireDefault(require("prop-types"));

var _ownerDocument = _interopRequireDefault(require("../utils/ownerDocument"));

var _Portal = _interopRequireDefault(require("../Portal"));

var _helpers = require("../utils/helpers");

var _reactHelpers = require("../utils/reactHelpers");

var _withForwardedRef = _interopRequireDefault(require("../utils/withForwardedRef"));

var _styles = require("@material-ui/styles");

var _utils = require("@material-ui/utils");

var _zIndex = _interopRequireDefault(require("../styles/zIndex"));

var _ModalManager = _interopRequireDefault(require("./ModalManager"));

var _TrapFocus = _interopRequireDefault(require("./TrapFocus"));

var _SimpleBackdrop = _interopRequireDefault(require("./SimpleBackdrop"));

var _manageAriaHidden = require("./manageAriaHidden");

function getContainer(container) {
  container = typeof container === 'function' ? container() : container;
  return _reactDom.default.findDOMNode(container);
}

function getHasTransition(props) {
  return props.children ? props.children.props.hasOwnProperty('in') : false;
}

var styles = function styles(theme) {
  return {
    /* Styles applied to the root element. */
    root: {
      position: 'fixed',
      zIndex: theme.zIndex.modal,
      right: 0,
      bottom: 0,
      top: 0,
      left: 0
    },

    /* Styles applied to the root element if the `Modal` has exited. */
    hidden: {
      visibility: 'hidden'
    }
  };
};
/**
 * Modal is a lower-level construct that is leveraged by the following components:
 *
 * - [Dialog](/api/dialog/)
 * - [Drawer](/api/drawer/)
 * - [Menu](/api/menu/)
 * - [Popover](/api/popover/)
 *
 * If you are creating a modal dialog, you probably want to use the [Dialog](/api/dialog/) component
 * rather than directly using Modal.
 *
 * This component shares many concepts with [react-overlays](https://react-bootstrap.github.io/react-overlays/#modals).
 */


exports.styles = styles;

var Modal =
/*#__PURE__*/
function (_React$Component) {
  (0, _inherits2.default)(Modal, _React$Component);

  function Modal(props) {
    var _this;

    (0, _classCallCheck2.default)(this, Modal);
    _this = (0, _possibleConstructorReturn2.default)(this, (0, _getPrototypeOf2.default)(Modal).call(this));

    _this.handleOpen = function () {
      var container = getContainer(_this.props.container) || _this.getDoc().body;

      _this.props.manager.add((0, _assertThisInitialized2.default)(_this), container);

      if (_this.modalRef) {
        _this.handleOpened();
      }
    };

    _this.handleRendered = function () {
      if (_this.props.onRendered) {
        _this.props.onRendered();
      }

      if (_this.props.open) {
        _this.handleOpened();
      } else {
        (0, _manageAriaHidden.ariaHidden)(_this.modalRef, true);
      }
    };

    _this.handleOpened = function () {
      _this.props.manager.mount((0, _assertThisInitialized2.default)(_this)); // Fix a bug on Chrome where the scroll isn't initially 0.


      _this.modalRef.scrollTop = 0;
    };

    _this.handleClose = function (reason) {
      var hasTransition = getHasTransition(_this.props);
      /* If the component does not have a transition or is unmounting remove the Modal
      otherwise let the transition handle removing the style, this prevents elements
      moving around when the Modal is closed. */

      if (!(hasTransition && _this.props.closeAfterTransition) || reason === 'unmount') {
        _this.props.manager.remove((0, _assertThisInitialized2.default)(_this));
      }
    };

    _this.handleEnter = function () {
      _this.setState({
        exited: false
      });
    };

    _this.handleExited = function () {
      if (_this.props.closeAfterTransition) {
        _this.props.manager.remove((0, _assertThisInitialized2.default)(_this));
      }

      _this.setState({
        exited: true
      });
    };

    _this.handleBackdropClick = function (event) {
      if (event.target !== event.currentTarget) {
        return;
      }

      if (_this.props.onBackdropClick) {
        _this.props.onBackdropClick(event);
      }

      if (!_this.props.disableBackdropClick && _this.props.onClose) {
        _this.props.onClose(event, 'backdropClick');
      }
    };

    _this.handleKeyDown = function (event) {
      // We don't take event.defaultPrevented into account:
      //
      // event.preventDefault() is meant to stop default behaviours like
      // clicking a checkbox to check it, hitting a button to submit a form,
      // and hitting left arrow to move the cursor in a text input etc.
      // Only special HTML elements have these default behaviors.
      if (event.key !== 'Escape' || !_this.isTopModal()) {
        return;
      } // Swallow the event, in case someone is listening for the escape key on the body.


      event.stopPropagation();

      if (_this.props.onEscapeKeyDown) {
        _this.props.onEscapeKeyDown(event);
      }

      if (!_this.props.disableEscapeKeyDown && _this.props.onClose) {
        _this.props.onClose(event, 'escapeKeyDown');
      }
    };

    _this.handlePortalRef = function (ref) {
      _this.mountNode = ref;
    };

    _this.handleModalRef = function (ref) {
      _this.modalRef = ref;
      (0, _reactHelpers.setRef)(_this.props.innerRef, ref);
    };

    _this.isTopModal = function () {
      return _this.props.manager.isTopModal((0, _assertThisInitialized2.default)(_this));
    };

    _this.getDoc = function () {
      return (0, _ownerDocument.default)(_this.mountNode);
    };

    _this.state = {
      exited: !props.open
    };
    return _this;
  }

  (0, _createClass2.default)(Modal, [{
    key: "componentDidMount",
    value: function componentDidMount() {
      if (this.props.open) {
        this.handleOpen();
      }
    }
  }, {
    key: "componentDidUpdate",
    value: function componentDidUpdate(prevProps) {
      if (prevProps.open && !this.props.open) {
        this.handleClose();
      } else if (!prevProps.open && this.props.open) {
        this.handleOpen();
      }
    }
  }, {
    key: "componentWillUnmount",
    value: function componentWillUnmount() {
      if (this.props.open || getHasTransition(this.props) && !this.state.exited) {
        this.handleClose('unmount');
      }
    }
  }, {
    key: "render",
    value: function render() {
      var _this$props = this.props,
          BackdropComponent = _this$props.BackdropComponent,
          BackdropProps = _this$props.BackdropProps,
          children = _this$props.children,
          closeAfterTransition = _this$props.closeAfterTransition,
          container = _this$props.container,
          disableAutoFocus = _this$props.disableAutoFocus,
          disableBackdropClick = _this$props.disableBackdropClick,
          disableEnforceFocus = _this$props.disableEnforceFocus,
          disableEscapeKeyDown = _this$props.disableEscapeKeyDown,
          disablePortal = _this$props.disablePortal,
          disableRestoreFocus = _this$props.disableRestoreFocus,
          hideBackdrop = _this$props.hideBackdrop,
          innerRef = _this$props.innerRef,
          keepMounted = _this$props.keepMounted,
          manager = _this$props.manager,
          onBackdropClick = _this$props.onBackdropClick,
          onClose = _this$props.onClose,
          onEscapeKeyDown = _this$props.onEscapeKeyDown,
          onRendered = _this$props.onRendered,
          open = _this$props.open,
          theme = _this$props.theme,
          other = (0, _objectWithoutProperties2.default)(_this$props, ["BackdropComponent", "BackdropProps", "children", "closeAfterTransition", "container", "disableAutoFocus", "disableBackdropClick", "disableEnforceFocus", "disableEscapeKeyDown", "disablePortal", "disableRestoreFocus", "hideBackdrop", "innerRef", "keepMounted", "manager", "onBackdropClick", "onClose", "onEscapeKeyDown", "onRendered", "open", "theme"]);
      var exited = this.state.exited;
      var hasTransition = getHasTransition(this.props);

      if (!keepMounted && !open && (!hasTransition || exited)) {
        return null;
      }

      var childProps = {}; // It's a Transition like component

      if (hasTransition) {
        childProps.onEnter = (0, _helpers.createChainedFunction)(this.handleEnter, children.props.onEnter);
        childProps.onExited = (0, _helpers.createChainedFunction)(this.handleExited, children.props.onExited);
      }

      if (children.props.role === undefined) {
        childProps.role = children.props.role || 'document';
      }

      if (children.props.tabIndex === undefined) {
        childProps.tabIndex = children.props.tabIndex || '-1';
      }

      var stylesRender = styles(theme || {
        zIndex: _zIndex.default
      });
      return _react.default.createElement(_Portal.default, {
        ref: this.handlePortalRef,
        container: container,
        disablePortal: disablePortal,
        onRendered: this.handleRendered
      }, _react.default.createElement("div", (0, _extends2.default)({
        ref: this.handleModalRef,
        onKeyDown: this.handleKeyDown,
        role: "presentation"
      }, other, {
        style: (0, _extends2.default)({}, stylesRender.root, !open && exited ? stylesRender.hidden : {}, other.style)
      }), hideBackdrop ? null : _react.default.createElement(BackdropComponent, (0, _extends2.default)({
        open: open,
        onClick: this.handleBackdropClick
      }, BackdropProps)), _react.default.createElement(_TrapFocus.default, {
        disableEnforceFocus: disableEnforceFocus,
        disableAutoFocus: disableAutoFocus,
        disableRestoreFocus: disableRestoreFocus,
        getDoc: this.getDoc,
        isEnabled: this.isTopModal,
        open: open
      }, _react.default.cloneElement(children, childProps))));
    }
  }]);
  return Modal;
}(_react.default.Component);

process.env.NODE_ENV !== "production" ? Modal.propTypes = {
  /**
   * A backdrop component. This property enables custom backdrop rendering.
   */
  BackdropComponent: _propTypes.default.elementType,

  /**
   * Properties applied to the [`Backdrop`](/api/backdrop/) element.
   */
  BackdropProps: _propTypes.default.object,

  /**
   * A single child content element.
   */
  children: _utils.elementAcceptingRef.isRequired,

  /**
   * When set to true the Modal waits until a nested Transition is completed before closing.
   */
  closeAfterTransition: _propTypes.default.bool,

  /**
   * A node, component instance, or function that returns either.
   * The `container` will have the portal children appended to it.
   */
  container: _propTypes.default.oneOfType([_propTypes.default.object, _propTypes.default.func]),

  /**
   * If `true`, the modal will not automatically shift focus to itself when it opens, and
   * replace it to the last focused element when it closes.
   * This also works correctly with any modal children that have the `disableAutoFocus` prop.
   *
   * Generally this should never be set to `true` as it makes the modal less
   * accessible to assistive technologies, like screen readers.
   */
  disableAutoFocus: _propTypes.default.bool,

  /**
   * If `true`, clicking the backdrop will not fire any callback.
   */
  disableBackdropClick: _propTypes.default.bool,

  /**
   * If `true`, the modal will not prevent focus from leaving the modal while open.
   *
   * Generally this should never be set to `true` as it makes the modal less
   * accessible to assistive technologies, like screen readers.
   */
  disableEnforceFocus: _propTypes.default.bool,

  /**
   * If `true`, hitting escape will not fire any callback.
   */
  disableEscapeKeyDown: _propTypes.default.bool,

  /**
   * Disable the portal behavior.
   * The children stay within it's parent DOM hierarchy.
   */
  disablePortal: _propTypes.default.bool,

  /**
   * If `true`, the modal will not restore focus to previously focused element once
   * modal is hidden.
   */
  disableRestoreFocus: _propTypes.default.bool,

  /**
   * If `true`, the backdrop is not rendered.
   */
  hideBackdrop: _propTypes.default.bool,

  /**
   * @ignore
   * from `withForwardRef`
   */
  innerRef: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.object]),

  /**
   * Always keep the children in the DOM.
   * This property can be useful in SEO situation or
   * when you want to maximize the responsiveness of the Modal.
   */
  keepMounted: _propTypes.default.bool,

  /**
   * @ignore
   *
   * A modal manager used to track and manage the state of open
   * Modals. This enables customizing how modals interact within a container.
   */
  manager: _propTypes.default.object,

  /**
   * Callback fired when the backdrop is clicked.
   */
  onBackdropClick: _propTypes.default.func,

  /**
   * Callback fired when the component requests to be closed.
   * The `reason` parameter can optionally be used to control the response to `onClose`.
   *
   * @param {object} event The event source of the callback
   * @param {string} reason Can be:`"escapeKeyDown"`, `"backdropClick"`
   */
  onClose: _propTypes.default.func,

  /**
   * Callback fired when the escape key is pressed,
   * `disableEscapeKeyDown` is false and the modal is in focus.
   */
  onEscapeKeyDown: _propTypes.default.func,

  /**
   * Callback fired once the children has been mounted into the `container`.
   * It signals that the `open={true}` property took effect.
   */
  onRendered: _propTypes.default.func,

  /**
   * If `true`, the modal is open.
   */
  open: _propTypes.default.bool.isRequired,

  /**
   * @ignore
   */
  theme: _propTypes.default.object
} : void 0;
Modal.defaultProps = {
  BackdropComponent: _SimpleBackdrop.default,
  closeAfterTransition: false,
  disableAutoFocus: false,
  disableBackdropClick: false,
  disableEnforceFocus: false,
  disableEscapeKeyDown: false,
  disablePortal: false,
  disableRestoreFocus: false,
  hideBackdrop: false,
  keepMounted: false,
  // Modals don't open on the server so this won't conflict with concurrent requests.
  manager: new _ModalManager.default()
};

var _default = (0, _styles.withTheme)((0, _withForwardedRef.default)(Modal));

exports.default = _default;