"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.PopoverCore = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireDefault(require("react"));
var _ReactPortal = _interopRequireDefault(require("../../utils/ReactPortal/ReactPortal"));
var _reactPopper = require("react-popper");
var _reactTransitionGroup = require("react-transition-group");
var _ClickOutside = require("./utils/ClickOutside");
var _modifiers = require("./utils/modifiers");
var _filterDataProps = require("./utils/filter-data-props");
var _uniqueId = _interopRequireDefault(require("lodash/uniqueId"));
var _utils = require("./utils/utils");
var _helpers = require("./utils/helpers");
var _getAppendToElement = require("./utils/getAppendToElement");
var _context = require("../../WixDesignSystemProvider/context");
var _PopoverSt = require("../Popover.st.css.js");
var _mergeRefs = require("../../utils/mergeRefs");
var _ZIndex = require("../../common/ZIndex");
var _jsxFileName = "/home/builduser/work/57e038ea7326c1ec/packages/wix-design-system/dist/cjs/Popover/PopoverCore/PopoverCore.tsx";
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
// This is here and not in the test setup because we don't want consumers to need to run it as well
var testId = '0';
var isTestEnv = process.env.NODE_ENV === 'test';
if (isTestEnv && typeof document !== 'undefined' && !document.createRange) {
  _helpers.popoverTestUtils.createRange();
}
/**
 * Popover
 */
class PopoverCore extends _react.default.Component {
  constructor(props) {
    super(props);
    this.targetRef = void 0;
    this.portalNode = null;
    this.portalClasses = '';
    this.appendToNode = null;
    this.clickOutsideRef = null;
    this.transitionRef = void 0;
    this.popoverContentRef = void 0;
    this.clickOutsideClass = void 0;
    this.contentHook = void 0;
    this.popperScheduleUpdate = void 0;
    // Timer instances for the show/hide delays
    this._hideTimeout = null;
    this._showTimeout = null;
    this._handleClickOutside = event => {
      var {
        onClickOutside: onClickOutsideCallback,
        shown,
        disableClickOutsideWhenClosed = true
      } = this.props;
      if (onClickOutsideCallback && !(disableClickOutsideWhenClosed && !shown)) {
        onClickOutsideCallback(event);
      }
    };
    this._onKeyDown = e => {
      var {
        onEscPress
      } = this.props;
      if (onEscPress && e.key === 'Escape') {
        onEscPress(e);
      }
    };
    /**
     * Checks to see if the focused element is outside the Popover content
     */
    this._onDocumentKeyUp = event => {
      var {
        onTabOut
      } = this.props;
      if (typeof document !== 'undefined' && this.popoverContentRef.current && !this.popoverContentRef.current.contains(document.activeElement)) {
        onTabOut && onTabOut(event);
      }
    };
    this.state = {
      isMounted: false,
      shown: props.shown || false
    };
    if (isTestEnv) {
      testId = _helpers.popoverTestUtils.generateId();
    }
    this.clickOutsideRef = /*#__PURE__*/_react.default.createRef();
    this.transitionRef = /*#__PURE__*/_react.default.createRef();
    this.popoverContentRef = /*#__PURE__*/_react.default.createRef();
    this.clickOutsideClass = (0, _uniqueId.default)('clickOutside');
    this.contentHook = "popover-content-".concat(props.dataHook || '', "-").concat(testId);
  }
  focus() {
    if (this.popoverContentRef.current) {
      this.popoverContentRef.current.focus();
    }
  }
  getPopperContentStructure(childrenObject) {
    var {
      shown
    } = this.state;
    var {
      moveBy,
      appendTo,
      placement,
      showArrow,
      moveArrowTo,
      flip,
      flipModifier,
      fixed,
      customArrow,
      role,
      id,
      zIndex,
      minWidth,
      maxWidth,
      width,
      dynamicWidth,
      onEscPress,
      tabIndex,
      'aria-label': ariaLabel,
      'aria-labelledby': ariaLabelledby,
      'aria-describedby': ariaDescribedBy,
      timeout,
      skin
    } = this.props;
    var shouldAnimate = (0, _utils.shouldAnimatePopover)({
      timeout
    });
    var modifiers = (0, _modifiers.createModifiers)({
      minWidth,
      width,
      dynamicWidth,
      moveBy,
      appendTo,
      shouldAnimate,
      flip,
      flipModifier,
      placement,
      fixed,
      isTestEnv
    });
    var popperWithArrow = /*#__PURE__*/_react.default.createElement(_reactPopper.Popper, {
      modifiers: modifiers,
      placement: placement,
      __self: this,
      __source: {
        fileName: _jsxFileName,
        lineNumber: 169,
        columnNumber: 7
      }
    }, _ref => {
      var {
        ref,
        style: popperStyles,
        placement: popperPlacement,
        arrowProps,
        scheduleUpdate
      } = _ref;
      this.popperScheduleUpdate = scheduleUpdate;
      return /*#__PURE__*/_react.default.createElement("div", {
        "data-hook": "popover-content",
        className: (0, _PopoverSt.st)(this.clickOutsideClass, this.context.newBrandingClass),
        "data-content-element": this.contentHook,
        ref: (0, _mergeRefs.mergeRefs)(ref, this.transitionRef),
        style: _objectSpread(_objectSpread({}, popperStyles), {}, {
          zIndex
        }),
        __self: this,
        __source: {
          fileName: _jsxFileName,
          lineNumber: 180,
          columnNumber: 13
        }
      }, showArrow && this.renderArrow(arrowProps, moveArrowTo, popperPlacement || placement, customArrow), /*#__PURE__*/_react.default.createElement("div", {
        id: id,
        role: role,
        tabIndex: tabIndex,
        ref: this.popoverContentRef,
        style: {
          maxWidth
        },
        className: (0, _PopoverSt.st)(_PopoverSt.classes.content, {
          skin,
          placement: popperPlacement || placement,
          hasArrow: true
        }),
        onKeyDown: shown && onEscPress ? this._onKeyDown : undefined,
        "aria-label": ariaLabel,
        "aria-labelledby": ariaLabelledby,
        "aria-describedby": ariaDescribedBy,
        __self: this,
        __source: {
          fileName: _jsxFileName,
          lineNumber: 197,
          columnNumber: 15
        }
      }, childrenObject.Content));
    });
    var popper = /*#__PURE__*/_react.default.createElement(_reactPopper.Popper, {
      modifiers: modifiers,
      placement: placement,
      __self: this,
      __source: {
        fileName: _jsxFileName,
        lineNumber: 222,
        columnNumber: 7
      }
    }, _ref2 => {
      var {
        ref,
        style: popperStyles,
        placement: popperPlacement,
        scheduleUpdate
      } = _ref2;
      this.popperScheduleUpdate = scheduleUpdate;
      return /*#__PURE__*/_react.default.createElement("div", {
        id: id,
        ref: (0, _mergeRefs.mergeRefs)(ref, this.popoverContentRef, this.transitionRef),
        role: role,
        tabIndex: tabIndex,
        className: (0, _PopoverSt.st)(_PopoverSt.classes.content, {
          skin,
          placement: popperPlacement || placement
        }, this.clickOutsideClass, this.context.newBrandingClass),
        "data-hook": "popover-content",
        style: _objectSpread(_objectSpread({}, popperStyles), {}, {
          zIndex,
          maxWidth
        }),
        "data-content-element": this.contentHook,
        onKeyDown: shown && onEscPress ? this._onKeyDown : undefined,
        "aria-label": ariaLabel,
        "aria-labelledby": ariaLabelledby,
        "aria-describedby": ariaDescribedBy,
        __self: this,
        __source: {
          fileName: _jsxFileName,
          lineNumber: 231,
          columnNumber: 13
        }
      }, childrenObject.Content);
    });
    return this.wrapWithAnimations(showArrow ? popperWithArrow : popper);
  }
  applyStylesToPortaledNode() {
    var {
      shown
    } = this.state;
    var shouldAnimate = (0, _utils.shouldAnimatePopover)(this.props);
    if (shouldAnimate || shown) {
      (0, _utils.attachClasses)(this.portalNode, this.portalClasses);
    } else {
      (0, _utils.detachClasses)(this.portalNode, this.portalClasses);
    }
  }
  wrapWithAnimations(popper) {
    var {
      timeout
    } = this.props;
    var {
      shown
    } = this.state;
    var shouldAnimate = (0, _utils.shouldAnimatePopover)(this.props);
    return shouldAnimate ? /*#__PURE__*/_react.default.createElement(_reactTransitionGroup.CSSTransition, {
      nodeRef: this.transitionRef,
      in: shown,
      timeout: timeout,
      unmountOnExit: true,
      classNames: {
        enter: _PopoverSt.classes.animationEnter,
        enterActive: _PopoverSt.classes.animationEnterActive,
        exit: _PopoverSt.classes.animationExit,
        exitActive: _PopoverSt.classes.animationExitActive
      },
      addEndListener: () => {},
      onExited: () => (0, _utils.detachClasses)(this.portalNode, this.portalClasses),
      __self: this,
      __source: {
        fileName: _jsxFileName,
        lineNumber: 281,
        columnNumber: 7
      }
    }, popper) : popper;
  }
  renderPopperContent(childrenObject) {
    var popper = this.getPopperContentStructure(childrenObject);
    return this.portalNode ? /*#__PURE__*/_react.default.createElement(_ReactPortal.default, {
      node: this.portalNode,
      __self: this,
      __source: {
        fileName: _jsxFileName,
        lineNumber: 306,
        columnNumber: 7
      }
    }, popper) : popper;
  }
  renderArrow(arrowProps, moveArrowTo, placement, customArrow) {
    var {
      skin
    } = this.props;
    var commonProps = {
      ref: arrowProps.ref,
      key: 'popover-arrow',
      'data-hook': 'popover-arrow',
      style: _objectSpread(_objectSpread({}, arrowProps.style), (0, _utils.getArrowShift)(moveArrowTo, placement))
    };
    if (customArrow) {
      return customArrow(placement, commonProps);
    }
    return /*#__PURE__*/_react.default.createElement("div", (0, _extends2.default)({}, commonProps, {
      className: (0, _PopoverSt.st)(_PopoverSt.classes.arrow, {
        skin,
        placement
      }),
      __self: this,
      __source: {
        fileName: _jsxFileName,
        lineNumber: 334,
        columnNumber: 7
      }
    }));
  }
  componentDidMount() {
    var {
      shown,
      onTabOut
    } = this.props;
    this.appendPortalToNode();
    if (onTabOut && shown) {
      this._setBlurByKeyboardListener();
    }
    this.setState({
      isMounted: true
    });
  }
  _setBlurByKeyboardListener() {
    if (typeof document !== 'undefined') {
      document.addEventListener('keyup', this._onDocumentKeyUp, true);
    }
  }
  _removeBlurListener() {
    if (typeof document !== 'undefined') {
      document.removeEventListener('keyup', this._onDocumentKeyUp, true);
    }
  }
  appendPortalToNode() {
    var {
      appendTo
    } = this.props;
    var {
      contextClassName
    } = this.context;
    this.appendToNode = (0, _getAppendToElement.getAppendToElement)(appendTo, this.targetRef);
    if (this.appendToNode) {
      var _this$portalNode;
      (_this$portalNode = this.portalNode) == null || _this$portalNode.remove();
      this.portalNode = document.createElement('div');
      this.portalNode.setAttribute('data-hook', 'popover-portal');
      if (contextClassName) {
        this.portalNode.classList.add(contextClassName);
      }
      /**
       * reset overlay wrapping layer
       * so that styles from copied classnames
       * won't break the overlay:
       * - content is position relative to body
       * - overlay layer is hidden
       */
      Object.assign(this.portalNode.style, {
        position: 'static',
        display: 'block',
        top: 0,
        left: 0,
        width: 0,
        height: 0
      });
      this.appendToNode.appendChild(this.portalNode);
    }
  }
  hidePopover() {
    var {
      isMounted
    } = this.state;
    var {
      hideDelay,
      onTabOut,
      onHide
    } = this.props;
    if (!isMounted || this._hideTimeout) {
      return;
    }
    if (this._showTimeout) {
      clearTimeout(this._showTimeout);
      this._showTimeout = null;
    }
    if (onTabOut) {
      this._removeBlurListener();
    }
    if (hideDelay) {
      this._hideTimeout = setTimeout(() => {
        this.setState({
          shown: false
        });
        onHide == null || onHide();
      }, hideDelay);
    } else {
      this.setState({
        shown: false
      });
      onHide == null || onHide();
    }
  }
  showPopover() {
    var {
      isMounted
    } = this.state;
    var {
      showDelay,
      onTabOut,
      onShow
    } = this.props;
    if (!isMounted || this._showTimeout) {
      return;
    }
    if (this._hideTimeout) {
      clearTimeout(this._hideTimeout);
      this._hideTimeout = null;
    }
    if (onTabOut) {
      this._setBlurByKeyboardListener();
    }
    if (showDelay) {
      this._showTimeout = setTimeout(() => {
        this.setState({
          shown: true
        });
        onShow == null || onShow();
      }, showDelay);
    } else {
      this.setState({
        shown: true
      });
      onShow == null || onShow();
    }
  }
  componentWillUnmount() {
    if (this.portalNode && this.appendToNode && this.appendToNode.children.length) {
      this.appendToNode.removeChild(this.portalNode);
      this.portalNode.remove();
    }
    this.portalNode = null;
    if (this._hideTimeout) {
      clearTimeout(this._hideTimeout);
      this._hideTimeout = null;
    }
    if (this._showTimeout) {
      clearTimeout(this._showTimeout);
      this._showTimeout = null;
    }
  }
  updatePosition() {
    if (this.popperScheduleUpdate) {
      this.popperScheduleUpdate();
    }
  }
  componentDidUpdate(prevProps) {
    var {
      skin,
      className,
      shown
    } = this.props;

    // allows reactive appendTo
    if (prevProps.appendTo !== this.props.appendTo) {
      this.appendPortalToNode();
    }
    if (this.portalNode) {
      // Re-calculate the portal's styles
      this.portalClasses = (0, _PopoverSt.st)(_PopoverSt.classes.root, {
        skin
      }, className);

      // Apply the styles to the portal
      this.applyStylesToPortaledNode();
    }

    // Update popover visibility
    if (prevProps.shown !== shown) {
      if (shown) {
        this.showPopover();
      } else {
        this.hidePopover();
      }
    } else {
      // Update popper's position
      this.updatePosition();
    }
  }
  render() {
    var {
      onMouseEnter,
      onMouseLeave,
      onKeyDown,
      onClick,
      children,
      className,
      style,
      fluid,
      skin,
      dataHook,
      zIndex,
      excludeClass,
      interactive
    } = this.props;
    var {
      isMounted,
      shown
    } = this.state;
    var childrenObject = (0, _utils.buildChildrenObject)(children, {
      Element: null,
      Content: null
    });
    var shouldAnimate = (0, _utils.shouldAnimatePopover)(this.props);
    var shouldRenderPopper = isMounted && (shouldAnimate || shown);
    return /*#__PURE__*/_react.default.createElement(_reactPopper.Manager, {
      __self: this,
      __source: {
        fileName: _jsxFileName,
        lineNumber: 546,
        columnNumber: 7
      }
    }, /*#__PURE__*/_react.default.createElement(_ClickOutside.ClickOutside, {
      rootRef: this.clickOutsideRef,
      onClickOutside: this._handleClickOutside,
      excludeClass: excludeClass ? [this.clickOutsideClass, excludeClass] : this.clickOutsideClass,
      __self: this,
      __source: {
        fileName: _jsxFileName,
        lineNumber: 547,
        columnNumber: 9
      }
    }, /*#__PURE__*/_react.default.createElement("div", (0, _extends2.default)({
      ref: this.clickOutsideRef,
      style: style,
      "data-hook": dataHook,
      "data-content-hook": this.contentHook,
      className: (0, _PopoverSt.st)(_PopoverSt.classes.root, {
        fluid,
        skin
      }, className),
      "data-zindex": zIndex,
      onMouseEnter: interactive ? onMouseEnter : undefined,
      onMouseLeave: interactive ? onMouseLeave : undefined
    }, (0, _filterDataProps.filterDataProps)(this.props), {
      __self: this,
      __source: {
        fileName: _jsxFileName,
        lineNumber: 556,
        columnNumber: 11
      }
    }), /*#__PURE__*/_react.default.createElement(_reactPopper.Reference, {
      innerRef: r => this.targetRef = r,
      __self: this,
      __source: {
        fileName: _jsxFileName,
        lineNumber: 567,
        columnNumber: 13
      }
    }, _ref3 => {
      var {
        ref
      } = _ref3;
      return /*#__PURE__*/_react.default.createElement("div", {
        ref: ref,
        className: _PopoverSt.classes.element,
        "data-hook": "popover-element",
        onClick: onClick,
        onKeyDown: onKeyDown,
        onMouseEnter: interactive ? undefined : onMouseEnter,
        onMouseLeave: interactive ? undefined : onMouseLeave,
        __self: this,
        __source: {
          fileName: _jsxFileName,
          lineNumber: 569,
          columnNumber: 17
        }
      }, childrenObject.Element);
    }), shouldRenderPopper && this.renderPopperContent(childrenObject))));
  }
}
exports.PopoverCore = PopoverCore;
PopoverCore.displayName = 'Popover';
PopoverCore.defaultProps = {
  flip: true,
  fixed: false,
  zIndex: _ZIndex.ZIndex.popover,
  shown: false,
  placement: 'bottom',
  excludeClass: '',
  interactive: true
};
PopoverCore.contextType = _context.WixDesignSystemContext;
PopoverCore.Element = (0, _utils.createComponentThatRendersItsChildren)('Popover.Element');
PopoverCore.Content = (0, _utils.createComponentThatRendersItsChildren)('Popover.Content');
//# sourceMappingURL=PopoverCore.js.map