"use strict";

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

var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");

exports.__esModule = true;
exports.default = void 0;

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

var _elementResizeEvent = _interopRequireWildcard(require("element-resize-event"));

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

var _classnames = _interopRequireDefault(require("classnames"));

var _DOMHelper = _interopRequireDefault(require("../DOMHelper"));

var _positionUtils = _interopRequireDefault(require("./positionUtils"));

var _utils = require("../utils");

var defaultProps = {
  containerPadding: 0,
  placement: 'right'
};

var usePosition = function usePosition(props, ref) {
  var placement = props.placement,
      preventOverflow = props.preventOverflow,
      containerPadding = props.containerPadding,
      container = props.container,
      triggerTarget = props.triggerTarget;
  var containerRef = (0, _react.useRef)();
  var lastTargetRef = (0, _react.useRef)();
  var defaultPosition = {
    positionLeft: 0,
    positionTop: 0,
    arrowOffsetLeft: null,
    arrowOffsetTop: null
  };

  var _useState = (0, _react.useState)(defaultPosition),
      position = _useState[0],
      setPosition = _useState[1];

  var utils = (0, _react.useMemo)(function () {
    return (0, _positionUtils.default)({
      placement: placement,
      preventOverflow: preventOverflow,
      padding: containerPadding
    });
  }, [placement, preventOverflow, containerPadding]);
  var updatePosition = (0, _react.useCallback)(
  /**
   * @param placementChanged  Whether the placement has changed
   * @param forceUpdateDOM Whether to update the DOM directly
   * @returns void
   */
  function (placementChanged, forceUpdateDOM) {
    if (placementChanged === void 0) {
      placementChanged = true;
    }

    if (!(triggerTarget === null || triggerTarget === void 0 ? void 0 : triggerTarget.current)) {
      return;
    }

    var targetElement = (0, _utils.getDOMNode)(triggerTarget);

    if (!_DOMHelper.default.isElement(targetElement)) {
      throw new Error('`target` should return an HTMLElement');
    } //  If the target and placement do not change, the position is not updated.


    if (targetElement === lastTargetRef.current && !placementChanged) {
      return;
    }

    var overlay = (0, _utils.getDOMNode)(ref.current);

    var containerElement = _DOMHelper.default.getContainer(typeof container === 'function' ? container() : container, _DOMHelper.default.ownerDocument(ref.current).body);

    var posi = utils.calcOverlayPosition(overlay, targetElement, containerElement);

    if (forceUpdateDOM && overlay) {
      var _overlay$className, _overlay$className$ma;

      var preClassName = overlay === null || overlay === void 0 ? void 0 : (_overlay$className = overlay.className) === null || _overlay$className === void 0 ? void 0 : (_overlay$className$ma = _overlay$className.match(/(placement-\S+)/)) === null || _overlay$className$ma === void 0 ? void 0 : _overlay$className$ma[0];

      _DOMHelper.default.removeClass(overlay, preClassName);

      _DOMHelper.default.addClass(overlay, posi.positionClassName);

      _DOMHelper.default.addStyle(overlay, {
        left: posi.positionLeft + "px",
        top: posi.positionTop + "px"
      });
    } else {
      setPosition(posi);
    }

    containerRef.current = containerElement;
    lastTargetRef.current = targetElement;
  }, [container, ref, triggerTarget, utils]);
  (0, _react.useEffect)(function () {
    updatePosition(false);
    var overlay = (0, _utils.getDOMNode)(ref.current);
    var containerScrollListener;

    if (containerRef.current && preventOverflow) {
      var _containerRef$current;

      // Update the overlay position when the container scroll bar is scrolling
      containerScrollListener = _DOMHelper.default.on(((_containerRef$current = containerRef.current) === null || _containerRef$current === void 0 ? void 0 : _containerRef$current.tagName) === 'BODY' ? window : containerRef.current, 'scroll', function () {
        return updatePosition(true, true);
      });
    } // Update the position when the window size changes


    var resizeListener = _DOMHelper.default.on(window, 'resize', function () {
      return updatePosition(true, true);
    });

    if (overlay) {
      // Update the position when the size of the overlay changes
      (0, _elementResizeEvent.default)(overlay, function () {
        return updatePosition(true, true);
      });
    }

    return function () {
      var _containerScrollListe;

      lastTargetRef.current = null;
      (_containerScrollListe = containerScrollListener) === null || _containerScrollListe === void 0 ? void 0 : _containerScrollListe.off();
      resizeListener === null || resizeListener === void 0 ? void 0 : resizeListener.off();

      if (overlay) {
        (0, _elementResizeEvent.unbind)(overlay);
      }
    };
  }, [preventOverflow, ref, updatePosition]);
  (0, _utils.useUpdateEffect)(function () {
    return updatePosition();
  }, [updatePosition, placement]);
  return [position, updatePosition];
};

var Position = /*#__PURE__*/_react.default.forwardRef(function (props, ref) {
  var children = props.children,
      className = props.className;

  var childRef = _react.default.useRef();

  var _usePosition = usePosition(props, childRef),
      position = _usePosition[0],
      updatePosition = _usePosition[1];

  var positionClassName = position.positionClassName,
      arrowOffsetLeft = position.arrowOffsetLeft,
      arrowOffsetTop = position.arrowOffsetTop,
      positionLeft = position.positionLeft,
      positionTop = position.positionTop;
  (0, _react.useImperativeHandle)(ref, function () {
    return {
      get child() {
        return childRef.current;
      },

      updatePosition: updatePosition
    };
  });

  if (typeof children === 'function') {
    var childProps = {
      className: (0, _classnames.default)(className, positionClassName),
      arrowOffsetLeft: arrowOffsetLeft,
      arrowOffsetTop: arrowOffsetTop,
      left: positionLeft,
      top: positionTop
    };
    return children(childProps, childRef);
  }

  return children;
});

Position.displayName = 'Position';
Position.defaultProps = defaultProps;
Position.propTypes = {
  className: _propTypes.default.string,
  children: _propTypes.default.func,
  container: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.any]),
  containerPadding: _propTypes.default.number,
  placement: _propTypes.default.any,
  preventOverflow: _propTypes.default.bool,
  triggerTarget: _propTypes.default.any
};
var _default = Position;
exports.default = _default;