function _extends() { _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; }; return _extends.apply(this, arguments); }

function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }

import React from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';

var EventOverlay =
/*#__PURE__*/
function (_React$Component) {
  _inheritsLoose(EventOverlay, _React$Component);

  function EventOverlay() {
    var _this;

    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
      args[_key] = arguments[_key];
    }

    _this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this;
    _this.state = {
      visibleDirection: _this.props.direction
    };

    _this.componentDidMount = function () {
      _this.addHandlers();
    };

    _this.componentDidUpdate = function (prevProps) {
      if (_this.props.isOpen && prevProps.isOpen !== _this.props.isOpen || prevProps.direction !== _this.props.direction) {
        return _this.forceUpdate(function () {
          return _this.isVisible();
        });
      }
    };

    _this.componentWillUnmount = function () {
      _this.removeHandlers();
    };

    _this.isVisible = function () {
      var _this$props = _this.props,
          direction = _this$props.direction,
          isOpen = _this$props.isOpen,
          anchorNode = _this$props.anchorNode,
          isDynamic = _this$props.isDynamic;
      if (!isOpen) return;
      if (!isDynamic) return _this.setPlacement();
      var element = ReactDOM.findDOMNode(_this.container);
      var elementAnchor = ReactDOM.findDOMNode(anchorNode);
      var side = direction.split('-')[0];
      var alignment = direction.split('-')[1];
      var anchor = elementAnchor && elementAnchor.getBoundingClientRect();
      var elementBoundingRect = element.getBoundingClientRect();
      var elementParent = element.parentElement;
      ['top', 'bottom'].includes(side) ? _this.setVerticalClass(alignment, anchor, elementBoundingRect, elementParent) : _this.setHorizontalClass(alignment, anchor, elementBoundingRect, elementParent);
    };

    _this.findParents = function (ele, tempParentArr) {
      if (tempParentArr === void 0) {
        tempParentArr = [];
      }

      return !ele.parentElement ? tempParentArr : _this.findParents(ele.parentElement, tempParentArr.concat(ele));
    };

    _this.findOverflow = function (node, searchProps) {
      return searchProps.reduce(function (agg, prop) {
        var overflowElement = window.getComputedStyle(ReactDOM.findDOMNode(node))[prop];
        return !overflowElement || agg.includes(overflowElement) ? agg : agg += overflowElement;
      }, '');
    };

    _this.findScrollParent = function (elementParents, searchProps) {
      var overflowElement = null;
      var idx = 0;

      while (!overflowElement && elementParents[idx]) {
        var currentOverflowElement = _this.findOverflow(elementParents[idx], searchProps);

        if (/(auto|scroll|hidden)/.test(currentOverflowElement)) {
          return overflowElement = elementParents[idx];
        }

        idx++;
      }

      return overflowElement ? overflowElement : window;
    };

    _this.setHorizontalClass = function (alignment, anchor, elementBoundingRect, elementParent) {
      var _this$props2 = _this.props,
          showArrow = _this$props2.showArrow,
          checkOverflow = _this$props2.checkOverflow,
          targetOffset = _this$props2.targetOffset;
      var windowRight = window.pageYOffset + window.innerWidth;
      var elementWidth = elementBoundingRect.width;
      var anchorRight = anchor.right;
      var arrowWidth = showArrow ? ReactDOM.findDOMNode(_this.arrow).getBoundingClientRect().width : 0;
      var offsetWidth = targetOffset.horizontal || 0;
      var totalWidth = anchorRight + elementWidth + arrowWidth + offsetWidth;

      var elementParents = _this.findParents(elementParent);

      var scrollParent = _this.findScrollParent(elementParents, ['overflow', 'overflow-x']);

      var parentRight = checkOverflow && !!scrollParent.getBoundingClientRect && scrollParent.getBoundingClientRect().right || windowRight;
      return totalWidth < parentRight && totalWidth < windowRight ? _this.setState({
        visibleDirection: "right-" + alignment
      }, function () {
        return _this.setPlacement();
      }) : _this.setState({
        visibleDirection: "left-" + alignment
      }, function () {
        return _this.setPlacement();
      });
    };

    _this.setVerticalClass = function (alignment, anchor, elementBoundingRect, elementParent) {
      var _this$props3 = _this.props,
          showArrow = _this$props3.showArrow,
          checkOverflow = _this$props3.checkOverflow,
          targetOffset = _this$props3.targetOffset;
      var windowBottom = window.pageXOffset + window.innerHeight;
      var elementHeight = elementBoundingRect.height;
      var anchorBottom = anchor.bottom;
      var arrowHeight = showArrow ? ReactDOM.findDOMNode(_this.arrow).getBoundingClientRect().height : 0;
      var offsetHeight = targetOffset.vertical || 0;
      var totalHeight = anchorBottom + elementHeight + arrowHeight + offsetHeight;

      var elementParents = _this.findParents(elementParent);

      var scrollParent = _this.findScrollParent(elementParents, ['overflow', 'overflow-y']);

      var parentBottom = checkOverflow && !!scrollParent.getBoundingClientRect && scrollParent.getBoundingClientRect().bottom || windowBottom;
      return totalHeight < parentBottom && totalHeight < windowBottom ? _this.setState({
        visibleDirection: "bottom-" + alignment
      }, function () {
        return _this.setPlacement();
      }) : _this.setState({
        visibleDirection: "top-" + alignment
      }, function () {
        return _this.setPlacement();
      });
    };

    _this.addHandlers = function () {
      var _this$props4 = _this.props,
          allowClickAway = _this$props4.allowClickAway,
          closeOnClick = _this$props4.closeOnClick;
      _this.handleResize = _this.isVisible;
      _this.handleScroll = _this.isVisible;
      allowClickAway && document.addEventListener('click', _this.handleAllowClickAway, true) && document.addEventListener('keyup', _this.handleKeyUp, true);
      closeOnClick && document.addEventListener('click', _this.handleCloseOnClick, false);
      window.addEventListener('resize', _this.handleResize, true);
      document.addEventListener('scroll', _this.handleScroll, false);

      _this.isVisible();
    };

    _this.removeHandlers = function () {
      document.removeEventListener('click', _this.handleAllowClickAway, true);
      document.removeEventListener('click', _this.handleCloseOnClick, false);
      window.removeEventListener('resize', _this.handleResize, true);
      document.removeEventListener('scroll', _this.handleScroll, false);
      document.removeEventListener('keyup', _this.handleKeyUp, true);
    };

    _this.handleCloseOnClick = function (e) {
      if (!_this.props.isOpen) return;
      var closeOnClick = _this.props.closeOnClick;
      return closeOnClick && _this.container && ReactDOM.findDOMNode(_this.container).contains(e.target) && _this.handleClickAway(e);
    };

    _this.handleKeyUp = function (e) {
      if (!_this.props.isOpen) return;
      if (e.keyCode === 27) return _this.handleClickAway(e);
      var anchorNode = ReactDOM.findDOMNode(_this.props.anchorNode);
      return _this.container && !anchorNode.contains(document.activeElement) && !ReactDOM.findDOMNode(_this.container).contains(document.activeElement) && _this.handleClickAway(e);
    };

    _this.handleAllowClickAway = function (e) {
      if (!_this.props.isOpen) return;
      var anchorNode = ReactDOM.findDOMNode(_this.props.anchorNode);
      return _this.container && !ReactDOM.findDOMNode(anchorNode).contains(e.target) && !ReactDOM.findDOMNode(_this.container).contains(e.target) && _this.handleClickAway(e);
    };

    _this.getAnchorPosition = function (node) {
      var rect = node.getBoundingClientRect();
      var anchorPosition = {
        top: rect.top,
        left: rect.left,
        width: node.offsetWidth,
        height: node.offsetHeight
      };
      anchorPosition.right = rect.right || anchorPosition.left + anchorPosition.width;
      anchorPosition.bottom = rect.bottom || anchorPosition.top + anchorPosition.height;
      anchorPosition.middle = anchorPosition.left + (anchorPosition.right - anchorPosition.left) / 2;
      anchorPosition.center = anchorPosition.top + (anchorPosition.bottom - anchorPosition.top) / 2;
      return anchorPosition;
    };

    _this.getTargetPosition = function (targetNode) {
      return {
        top: 0,
        center: targetNode.offsetHeight / 2,
        bottom: targetNode.offsetHeight,
        left: 0,
        middle: targetNode.offsetWidth / 2,
        right: targetNode.offsetWidth
      };
    };

    _this.getOrigin = function () {
      var side = _this.state.visibleDirection.split('-')[0];

      var alignment = _this.props.direction.split('-')[1];

      var origin = {
        anchor: {},
        target: {}
      };

      if (side === 'top' || side === 'bottom') {
        origin.anchor.vertical = side;
        origin.anchor.horizontal = alignment === 'center' ? 'middle' : alignment;
        origin.target.vertical = side === 'top' ? 'bottom' : 'top';
        origin.target.horizontal = alignment === 'center' ? 'middle' : alignment;
      }

      if (side === 'left' || side === 'right') {
        origin.anchor.vertical = alignment;
        origin.anchor.horizontal = side;
        origin.target.vertical = alignment;
        origin.target.horizontal = side === 'left' ? 'right' : 'left';
      }

      return origin;
    };

    _this.setArrowPlacement = function (anchor) {
      var arrow = _this.arrow;
      var targetOffset = _this.props.targetOffset;
      var visibleDirection = _this.state.visibleDirection;
      var side = visibleDirection.split('-')[0];
      var verticalOffset = targetOffset.vertical || 0;
      var horizontalOffset = targetOffset.horizontal || 0;

      switch (side) {
        case 'top':
          arrow.style.left = anchor.middle + "px";
          arrow.style.top = anchor.top - verticalOffset + "px";
          break;

        case 'bottom':
          arrow.style.left = anchor.middle + "px";
          arrow.style.top = anchor.bottom + verticalOffset + "px";
          break;

        case 'left':
          arrow.style.left = anchor.left - horizontalOffset + "px";
          arrow.style.top = anchor.center + "px";
          break;

        case 'right':
          arrow.style.left = anchor.right + horizontalOffset + "px";
          arrow.style.top = anchor.center + "px";
          break;
      }
    };

    _this.setPlacement = function () {
      var _this$props5 = _this.props,
          isOpen = _this$props5.isOpen,
          anchorNode = _this$props5.anchorNode,
          targetOffset = _this$props5.targetOffset;
      var visibleDirection = _this.state.visibleDirection;
      if (!isOpen) return;
      var anchorNodeFound = ReactDOM.findDOMNode(anchorNode);
      var side = visibleDirection.split('-')[0];
      var targetNode = _this.container;
      var verticalOffset = targetOffset.vertical || 0;
      var horizontalOffset = targetOffset.horizontal || 0;
      if (!targetNode || !anchorNodeFound) return;
      anchorNodeFound.link = _this.state.id;

      var anchorPosition = _this.getAnchorPosition(anchorNodeFound);

      var targetPosition = _this.getTargetPosition(targetNode);

      var origin = _this.getOrigin();

      var anchorOrigin = origin.anchor;
      var targetOrigin = origin.target;
      var targetNodePosition = {
        top: anchorPosition[anchorOrigin.vertical] - targetPosition[targetOrigin.vertical] + (side === 'top' ? -verticalOffset : verticalOffset),
        left: anchorPosition[anchorOrigin.horizontal] - targetPosition[targetOrigin.horizontal] + (side === 'left' ? -horizontalOffset : horizontalOffset)
      };
      targetNode.style.top = targetNodePosition.top + "px";
      targetNode.style.left = targetNodePosition.left + "px";
      _this.props.showArrow && _this.setArrowPlacement(anchorPosition);
    };

    _this.handleClickAway = function (e) {
      _this.props.close && _this.props.close(e);
    };

    return _this;
  }

  var _proto = EventOverlay.prototype;

  _proto.render = function render() {
    var _this2 = this;

    var _this$props6 = this.props,
        className = _this$props6.className,
        isOpen = _this$props6.isOpen,
        children = _this$props6.children,
        showArrow = _this$props6.showArrow,
        maxHeight = _this$props6.maxHeight,
        maxWidth = _this$props6.maxWidth,
        style = _this$props6.style;
    var side = this.state.visibleDirection.split('-')[0];
    var contentNodes = React.createElement("div", {
      className: 'cui-event-overlay' + ("" + (showArrow && " cui-event-overlay--arrow" || '')) + ("" + (side && " cui-event-overlay--" + side || '')) + ("" + (className && " " + className || ''))
    }, showArrow && React.createElement("div", {
      ref: function ref(_ref) {
        return _this2.arrow = _ref;
      },
      className: "cui-event-overlay__arrow"
    }), React.createElement("div", {
      className: "cui-event-overlay__children",
      ref: function ref(_ref2) {
        return _this2.container = _ref2;
      },
      style: _extends({
        maxWidth: "" + (maxWidth && maxWidth + "px" || 'unset'),
        maxHeight: "" + (maxHeight && maxHeight + "px" || 'unset')
      }, style)
    }, children));
    return isOpen && contentNodes;
  };

  return EventOverlay;
}(React.Component);

EventOverlay.displayName = 'EventOverlay';
export { EventOverlay as default };
EventOverlay.defaultProps = {
  allowClickAway: true,
  anchorNode: null,
  children: null,
  checkOverflow: true,
  className: '',
  close: null,
  isDynamic: false,
  isOpen: false,
  direction: 'bottom-left',
  targetOffset: {
    horizontal: 0,
    vertical: 0
  },
  showArrow: false,
  style: null,
  maxHeight: null,
  maxWidth: null
};
EventOverlay.propTypes = {
  allowClickAway: PropTypes.bool,
  anchorNode: PropTypes.object,
  checkOverflow: PropTypes.bool,
  children: PropTypes.node,
  className: PropTypes.string,
  close: PropTypes.func,
  isDynamic: PropTypes.bool,
  isOpen: PropTypes.bool,
  targetOffset: PropTypes.shape({
    horizontal: PropTypes.number,
    vertical: PropTypes.number
  }),
  direction: PropTypes.oneOf(['top-center', 'left-center', 'right-center', 'bottom-center', 'top-left', 'top-right', 'bottom-left', 'bottom-right', 'left-top', 'left-bottom', 'right-top', 'right-bottom']),
  showArrow: PropTypes.bool,
  style: PropTypes.object,
  closeOnClick: PropTypes.bool,
  maxHeight: PropTypes.number,
  maxWidth: PropTypes.number
};