import _objectSpread from "@babel/runtime/helpers/esm/objectSpread";
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
import _createClass from "@babel/runtime/helpers/esm/createClass";
import _possibleConstructorReturn from "@babel/runtime/helpers/esm/possibleConstructorReturn";
import _getPrototypeOf from "@babel/runtime/helpers/esm/getPrototypeOf";
import _assertThisInitialized from "@babel/runtime/helpers/esm/assertThisInitialized";
import _inherits from "@babel/runtime/helpers/esm/inherits";
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";

/**
 * box.jsx
 *
 * 为 modal、poptip、tooltip 提供基础支持
 * @Author: jruif
 * @Date: 2017/7/10 上午10:48
 */
import '../util/closest';
import React, { Fragment, isValidElement, cloneElement, Component } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import addEventListener from '../util/addEventListener';
import keyboardKey from '../util/keyboardKey'; // import Trigger from './trigger';
// let clickOnChildBox = false;

var Box =
/*#__PURE__*/
function (_Component) {
  _inherits(Box, _Component);

  function Box(props, context) {
    var _this;

    _classCallCheck(this, Box);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(Box).call(this, props, context));

    _defineProperty(_assertThisInitialized(_this), "handleDocumentClick", function (e) {
      var isCloseOnDocumentClick = _this.props.isCloseOnDocumentClick;

      if (!_this.rootNode || // not mounted
      !_this.BoxNode || // no Box
      _this.triggerNode && _this.triggerNode.contains(e.target) || // event happened in trigger (delegate to trigger handlers)
      _this.rootNode && _this.rootNode.contains(e.target) // || // event happened in the box
      // this.clickOnChildBox
      ) {
          // this.clickOnChildBox = false;
          return;
        }

      if (isCloseOnDocumentClick && !_this.rootNode.contains(e.target)) {
        _this.close(e);
      }
    });

    _defineProperty(_assertThisInitialized(_this), "handleEscape", function (e) {
      if (!_this.props.isCloseOnEscape) return;
      if (keyboardKey.getCode(e) !== keyboardKey.name.Escape) return;

      _this.close(e);
    });

    _defineProperty(_assertThisInitialized(_this), "handleBoxMouseLeave", function (e) {
      var _this$props = _this.props,
          isCloseOnBoxMouseLeave = _this$props.isCloseOnBoxMouseLeave,
          mouseLeaveDelay = _this$props.mouseLeaveDelay; // debugger;

      var didFocusTrigger = _this.triggerNode && e.relatedTarget !== window && _this.triggerNode.contains(e.relatedTarget);

      if (!isCloseOnBoxMouseLeave || didFocusTrigger) return;
      _this.mouseLeaveTimer = _this.closeWithTimeout(e, mouseLeaveDelay);
    });

    _defineProperty(_assertThisInitialized(_this), "handleBoxMouseEnter", function () {
      var isCloseOnBoxMouseLeave = _this.props.isCloseOnBoxMouseLeave;
      if (!isCloseOnBoxMouseLeave) return;
      clearTimeout(_this.mouseLeaveTimer);
    });

    _defineProperty(_assertThisInitialized(_this), "handleTriggerFocus", function (e) {
      var _this$props2 = _this.props,
          trigger = _this$props2.trigger,
          isOpenOnTriggerFocus = _this$props2.isOpenOnTriggerFocus; // 调用原生事件

      trigger.props.onFocus && trigger.props.onFocus(e);
      if (!isOpenOnTriggerFocus) return; // react销毁了事件对象的所有属性
      // 所以有些事件的属性(e.g currentTarget)请求到却是null，所有这里我们直接clone

      _this.open(_objectSpread({}, e));
    });

    _defineProperty(_assertThisInitialized(_this), "handleTriggerBlur", function (e) {
      var _this$props3 = _this.props,
          trigger = _this$props3.trigger,
          isCloseOnTriggerBlur = _this$props3.isCloseOnTriggerBlur; // 调用原生事件

      trigger.props.onBlur && trigger.props.onBlur(e); // 焦点是否在box中

      var didFocusBox = _this.rootNode && _this.rootNode.contains(e.relatedTarget);

      if (!isCloseOnTriggerBlur || didFocusBox) return;

      _this.close(e);
    });

    _defineProperty(_assertThisInitialized(_this), "handleTriggerClick", function (e) {
      var _this$props4 = _this.props,
          trigger = _this$props4.trigger,
          isCloseOnTriggerClick = _this$props4.isCloseOnTriggerClick,
          isOpenOnTriggerClick = _this$props4.isOpenOnTriggerClick,
          isOpen = _this$props4.isOpen; // e.stopPropagation();
      // 调用原生事件

      trigger.props.onClick && trigger.props.onClick(e);

      if (isOpen && isCloseOnTriggerClick) {
        _this.close(e);
      } else if (!isOpen && isOpenOnTriggerClick) {
        _this.open(_objectSpread({}, e));
      }
    });

    _defineProperty(_assertThisInitialized(_this), "handleTriggerMouseLeave", function (e) {
      clearTimeout(_this.mouseEnterTimer);
      var _this$props5 = _this.props,
          trigger = _this$props5.trigger,
          isCloseOnTriggerMouseLeave = _this$props5.isCloseOnTriggerMouseLeave,
          mouseLeaveDelay = _this$props5.mouseLeaveDelay;
      trigger.props.onMouseLeave && trigger.props.onMouseLeave(e);
      if (!isCloseOnTriggerMouseLeave) return;
      _this.mouseLeaveTimer = _this.closeWithTimeout(e, mouseLeaveDelay);
    });

    _defineProperty(_assertThisInitialized(_this), "handleTriggerMouseEnter", function (e) {
      clearTimeout(_this.mouseLeaveTimer);
      var _this$props6 = _this.props,
          trigger = _this$props6.trigger,
          mouseEnterDelay = _this$props6.mouseEnterDelay,
          isOpenOnTriggerMouseEnter = _this$props6.isOpenOnTriggerMouseEnter; // Call original event handler

      trigger.props.onMouseEnter && trigger.props.onMouseEnter(_this.handleTriggerMouseEnter);
      if (!isOpenOnTriggerMouseEnter) return;
      _this.mouseEnterTimer = _this.openWithTimeout(e, mouseEnterDelay);
    });

    _defineProperty(_assertThisInitialized(_this), "open", function (e) {
      var _this$props7 = _this.props,
          onOpen = _this$props7.onOpen,
          disabled = _this$props7.disabled; // 打开的时候更新实例zIndex，设置为最高层

      if (!disabled) {
        _this.zIndex = Box.zIndex++;
        Promise.resolve(e).then(function (e) {
          if (onOpen) {
            onOpen(e, _this.props);
          }
        });
      }
    });

    _defineProperty(_assertThisInitialized(_this), "openWithTimeout", function (e, delay) {
      // react销毁了事件对象的所有属性，并且如果你需要异步使用事件建议使用e.persist()，
      // 所以有些事件的属性(e.g currentTarget)请求到却是null，所有这里我们直接clone
      var eventClone = _objectSpread({}, e);

      return setTimeout(function () {
        return _this.open(eventClone);
      }, delay || 0);
    });

    _defineProperty(_assertThisInitialized(_this), "close", function (e) {
      var _this$props8 = _this.props,
          onClose = _this$props8.onClose,
          isOpen = _this$props8.isOpen;
      Promise.resolve(e).then(function (e) {
        if (onClose, isOpen) {
          onClose(e, _this.props);
        }
      });
    });

    _defineProperty(_assertThisInitialized(_this), "closeWithTimeout", function (e, delay) {
      // react消除了所有的事件对象，并且如果你需要异步使用事件建议使用e.persist()，
      // 然而有些事件属性(e.g. currentTarget)请求到却是null，所有这里我们直接clone
      var eventClone = _objectSpread({}, e);

      return setTimeout(function () {
        _this.close(eventClone);
      }, delay || 0);
    });

    _defineProperty(_assertThisInitialized(_this), "mountBox", function () {
      if (_this.rootNode) return;
      var _this$props9 = _this.props,
          prepend = _this$props9.prepend,
          mountNode = _this$props9.mountNode,
          onMount = _this$props9.onMount;
      _this.rootNode = document.createElement('div');

      if (prepend) {
        mountNode.insertBefore(_this.rootNode, mountNode.firstElementChild);
      } else {
        mountNode.appendChild(_this.rootNode);
      } // 添加事件监听


      _this.handleDocumentClickListener = addEventListener(document.body, 'click', _this.handleDocumentClick);
      _this.handleEscapeListener = addEventListener(document.body, 'keydown', _this.handleEscape);
      if (onMount) onMount(null, _this.props);
    });

    _defineProperty(_assertThisInitialized(_this), "unmountBox", function () {
      if (!_this.rootNode) return; // let rs = ReactDOM.unmountComponentAtNode(this.rootNode);

      _this.rootNode.parentNode.removeChild(_this.rootNode); // 移除事件监听


      _this.handleDocumentClickListener.remove();

      _this.handleEscapeListener.remove();

      _this.handleDocumentClickListener = null;
      _this.handleEscapeListener = null; // Clean up timers

      clearTimeout(_this.mouseEnterTimer);
      clearTimeout(_this.mouseLeaveTimer);
      _this.rootNode = null;
      _this.BoxNode = null;
      var onUnmount = _this.props.onUnmount;
      if (onUnmount) onUnmount(null, _this.props);
    });

    _defineProperty(_assertThisInitialized(_this), "handleTriggerRef", function (c) {
      var _this$props10 = _this.props,
          triggerRef = _this$props10.triggerRef,
          trigger = _this$props10.trigger;
      _this.triggerNode = ReactDOM.findDOMNode(c);

      if (triggerRef) {
        triggerRef(_this.triggerNode);
      }

      trigger.props.ref && trigger.props.ref(c);
    });

    _defineProperty(_assertThisInitialized(_this), "renderBox", function () {
      var _this$props11 = _this.props,
          children = _this$props11.children,
          className = _this$props11.className;

      _this.mountBox();

      _this.rootNode.className = className || '';
      var ChildCopy = React.cloneElement(children, {
        ref: function ref(instance) {
          var ref = children.ref;
          _this.BoxNode = instance;
          ref && ref(instance);
        },
        // onClick: this.handleBoxClick,
        onMouseEnter: _this.handleBoxMouseEnter,
        onMouseLeave: _this.handleBoxMouseLeave,
        className: classnames('box-content', children.props.className),
        style: Object.assign({
          zIndex: _this.zIndex
        }, children.props.style)
      });
      return ReactDOM.createPortal(ChildCopy, _this.rootNode, 'box-children');
    });

    _this.portalNode = null;
    _this.rootNode = null;
    _this.clickOnChildBox = false; // 初始化的时候设置实例zIndex
    // 不直接使用静态属性，为防止一个实例更新时导致所有实例都更新
    // 只有再次执行open方法都时候执行更新

    _this.zIndex = Box.zIndex++;
    return _this;
  }

  _createClass(Box, [{
    key: "componentWillReceiveProps",
    value: function componentWillReceiveProps(nextProps) {
      if (!nextProps.trigger && nextProps.isOpen && !this.props.isOpen) {
        this.open({});
      }
    }
  }, {
    key: "componentWillUnmount",
    value: function componentWillUnmount() {
      var onUnmount = this.props.onUnmount;
      this.unmountBox();

      if (onUnmount) {
        onUnmount(null, this.props);
      }
    } // --------------------
    // Document事件
    // ---------------------

  }, {
    key: "render",
    value: function render() {
      var trigger = this.props.trigger;
      return React.createElement(Fragment, null, isValidElement(trigger) && cloneElement(trigger, {
        ref: this.handleTriggerRef,
        onBlur: this.handleTriggerBlur,
        onClick: this.handleTriggerClick,
        onFocus: this.handleTriggerFocus,
        onMouseLeave: this.handleTriggerMouseLeave,
        onMouseEnter: this.handleTriggerMouseEnter,
        className: classnames('box-trigger', trigger.props.className)
      }), this.renderBox());
    }
  }]);

  return Box;
}(Component);

_defineProperty(Box, "zIndex", 10);

_defineProperty(Box, "propTypes", {
  /** 主要内容 */
  children: PropTypes.node.isRequired,

  /** 额外样式 */
  className: PropTypes.string,

  /** 点击document是否关闭 */
  isCloseOnDocumentClick: PropTypes.bool,

  /** 按ESC键是否关闭 */
  isCloseOnEscape: PropTypes.bool,

  /**
   * Controls whether or not the box should close when mousing out of the box.
   * NOTE: This will prevent `closeOnTriggerMouseLeave` when mousing over the
   * gap from the trigger to the box.
   */
  isCloseOnBoxMouseLeave: PropTypes.bool,

  /** 在trigger上失焦是否关闭 */
  isCloseOnTriggerBlur: PropTypes.bool,

  /** 在trigger上点击是否关闭 */
  isCloseOnTriggerClick: PropTypes.bool,

  /** 在trigger上Mouse Leave是否关闭 */
  isCloseOnTriggerMouseLeave: PropTypes.bool,
  // defaultOpen: PropTypes.bool,

  /** 挂载节点 */
  mountNode: PropTypes.any,

  /** mouse over 时打开需要延迟时间（毫秒） */
  mouseEnterDelay: PropTypes.number,

  /** mouse leave 时打开需要延迟时间（毫秒） */
  mouseLeaveDelay: PropTypes.number,

  /**
   * 关闭的时候回调
   *
   * @param {SyntheticEvent} event - React's original SyntheticEvent.
   * @param {object} data - 所有 props.
   */
  onClose: PropTypes.func,
  disabled: PropTypes.bool,

  /**
   * 被挂载在DOM中时候回调
   *
   * @param {null}
   * @param {object} data - 所有 props.
   */
  onMount: PropTypes.func,

  /**
   * 当显示当时候回调
   *
   * @param {SyntheticEvent} event - React's original SyntheticEvent.
   * @param {object} data - 所有 props.
   */
  onOpen: PropTypes.func,

  /**
   * 从DOM中卸载的时候调用
   *
   * @param {null}
   * @param {object} data - 所有 props.
   */
  onUnmount: PropTypes.func,

  /** 是否显示 */
  isOpen: PropTypes.bool,

  /** 当trigger被点击时，是否打开 */
  isOpenOnTriggerClick: PropTypes.bool,

  /** 当trigger被focus时，是否打开 */
  isOpenOnTriggerFocus: PropTypes.bool,

  /** 当trigger被Mouse Enter时，是否打开 */
  isOpenOnTriggerMouseEnter: PropTypes.bool,

  /** 提示框等会用 */
  trigger: PropTypes.node
});

_defineProperty(Box, "defaultProps", {
  isOpen: false,
  disabled: false,
  isCloseOnDocumentClick: false,
  isCloseOnEscape: true,
  isCloseOnRootNodeClick: false,
  isCloseOnBoxMouseLeave: false,
  isCloseOnTriggerBlur: true,
  isCloseOnTriggerClick: true,
  isCloseOnTriggerMouseLeave: false,
  isPrepend: false,
  isOpenOnTriggerClick: false,
  isOpenOnTriggerFocus: false,
  isOpenOnTriggerMouseEnter: false,
  isCacheInNodeTree: false,
  mouseEnterDelay: 0,
  mouseLeaveDelay: 0,
  mountNode: document.body
});

export default Box;