"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.default = exports.DropdownLayout = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
var _react = _interopRequireWildcard(require("react"));
var _Loader = _interopRequireDefault(require("../Loader/Loader"));
var _InfiniteScroll = _interopRequireDefault(require("../utils/InfiniteScroll"));
var _scrollIntoView = _interopRequireDefault(require("../utils/scrollIntoView"));
var _DataAttr = require("./DataAttr");
var _DropdownLayoutSt = require("./DropdownLayout.st.css.js");
var _filterObject = require("../utils/filterObject");
var _ListItemSection = require("../ListItemSection");
var _ListItemSelect = require("../ListItemSelect");
var _ListItemAction = require("../ListItemAction");
var _StringUtils = require("../utils/StringUtils");
var _withOverlayScrollbar = require("./withOverlayScrollbar");
var _DropdownLayout2 = require("./DropdownLayout.constants");
var _forkRef = require("../utils/forkRef");
var _excluded = ["id", "value", "disabled", "disabledDescription", "optionTitle", "title"];
var _jsxFileName = "/home/builduser/work/57e038ea7326c1ec/packages/wix-design-system/dist/cjs/DropdownLayout/DropdownLayout.tsx";
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
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; }
var modulus = (n, m) => (n % m + m) % m;
var getUnit = value => (0, _StringUtils.isString)(value) ? value : "".concat(value, "px");
class DropdownLayout extends _react.PureComponent {
  constructor(props) {
    super(props);
    this.setScrollElement = node => {
      this.setState({
        scrollElement: node
      });
    };
    this.containerRef = /*#__PURE__*/_react.default.createRef();
    this.optionsRef = /*#__PURE__*/_react.default.createRef();
    this.loadedWithUndefinedOptions = false;
    this._boundEvents = [];
    this.focusableItemsIdsList = [];
    this.savedOnClicks = [];
    this.children = {};
    this.selectedOption = null;
    this._isDialogMode = () => {
      /** This component has two modes:
       *  1. Menu mode: when fixedHeader or fixedFooter is not present - https://www.w3.org/WAI/ARIA/apg/patterns/menubar/
       *  2. Dialog mode: when fixedHeader or fixedFooter is present - https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/
       */
      var {
        fixedHeader,
        fixedFooter
      } = this.props;
      return Boolean(fixedHeader || fixedFooter);
    };
    /** @deprecated */
    this._onMouseEventsHandler = e => {
      if (!this._checkIfEventOnElements(e, [this.containerRef.current])) {
        this._onClickOutside(e);
      }
    };
    this._onClickOutside = event => {
      var {
        visible,
        onClickOutside
      } = this.props;
      if (visible && onClickOutside) {
        onClickOutside(event);
      }
    };
    this._onSelect = (index, e) => {
      var {
        onSelect,
        listType
      } = this.props;
      var options = this.props.options || [];
      if (listType !== _DropdownLayout2.ListType.select) {
        e.stopPropagation();
        this._onClose();
        return;
      }
      var chosenOption = options[index];
      if (chosenOption) {
        var sameOptionWasPicked = chosenOption.id === this.state.selectedId;
        if (onSelect) {
          e.stopPropagation();
          onSelect(
          // casting to avoid breaking changes after TS conversion
          chosenOption, sameOptionWasPicked);
        }
      }
      if (!this._isControlled()) {
        this.setState({
          selectedId: chosenOption && chosenOption.id
        });
      }
      return !!onSelect && chosenOption;
    };
    this._onActionClick = e => {
      var _this$savedOnClicks$f;
      var onClick = (_this$savedOnClicks$f = this.savedOnClicks.find(_ref => {
        var {
          id
        } = _ref;
        return id === e.id;
      })) == null ? void 0 : _this$savedOnClicks$f.onClick;
      onClick && onClick(e);
    };
    this._saveOnClicks = () => {
      var options = this.props.options || [];
      this.savedOnClicks = options.map(_ref2 => {
        var {
          id,
          // only builder options have onClick
          // @ts-expect-error
          onClick
        } = _ref2;
        return {
          id,
          onClick
        };
      });
    };
    this._onMouseEnter = index => {
      var {
        options = []
      } = this.props;
      if (this._isSelectableOption(options[index])) {
        var _this$props$onOptions, _this$props;
        var markedOption = options[index];
        (_this$props$onOptions = (_this$props = this.props).onOptionsNavigate) == null || _this$props$onOptions.call(_this$props, markedOption);
        this._markOption(index);
      }
    };
    this._onMouseLeave = () => {
      this._markOption(_DropdownLayout2.NOT_HOVERED_INDEX);
    };
    this._onContainerMouseLeave = e => {
      var _this$props$onOptions2, _this$props2;
      (_this$props$onOptions2 = (_this$props2 = this.props).onOptionsNavigate) == null || _this$props$onOptions2.call(_this$props2, null);
      this._markOption(_DropdownLayout2.NOT_HOVERED_INDEX);
      if (this.props.onMouseLeave) {
        this.props.onMouseLeave(e);
      }
    };
    this._focusOnOption = () => {
      var {
        focusOnOption
      } = this.props;
      var options = this.props.options || [];
      var markedIndex = options.findIndex(option => option.id === focusOnOption);
      if (markedIndex !== -1) {
        this._markOptionAtIndex(markedIndex);
      } else {
        // Remove focus
        this._markOption(markedIndex);
      }
    };
    this._markOptionAtIndex = markedIndex => {
      this._markOption(markedIndex);
      this._scrollIntoViewByIndex(markedIndex);
    };
    this._scrollIntoViewByIndex = index => {
      var _this$optionsRef$curr, _this$optionsRef$curr2;
      var {
        infiniteScroll
      } = this.props;
      var menuElement = this.optionsRef.current;
      var hoveredElement = infiniteScroll ? (_this$optionsRef$curr = this.optionsRef.current) == null ? void 0 : _this$optionsRef$curr.childNodes[0].childNodes[index] : (_this$optionsRef$curr2 = this.optionsRef.current) == null ? void 0 : _this$optionsRef$curr2.childNodes[index];
      (0, _scrollIntoView.default)(menuElement, hoveredElement);
    };
    /**
     * Handle keydown events for the DropdownLayout, mostly for accessibility
     *
     * @param event - The keydown event triggered by React
     * @returns Whether the event was handled by the component
     */
    this._onSelectListKeyDown = event => {
      if (!this.props.visible ||
      // such prop does not exist but let's avoid potential breaking change
      // @ts-expect-error
      this.props.isComposing || this.props.listType !== _DropdownLayout2.ListType.select) {
        return false;
      }
      switch (event.key) {
        case _DropdownLayout2.KEY.arrowDown:
          {
            if (this._isArrowNavigationDisabled(event)) {
              return false;
            }
            this._markNextStep(1);
            event.preventDefault();
            event.stopPropagation();
            return true;
          }
        case _DropdownLayout2.KEY.arrowUp:
          {
            if (this._isArrowNavigationDisabled(event)) {
              return false;
            }
            this._markNextStep(-1);
            event.preventDefault();
            event.stopPropagation();
            return true;
          }
        case _DropdownLayout2.KEY.space:
        case _DropdownLayout2.KEY.enter:
          {
            // If event is from fixedHeader/fixedFooter, let it bubble naturally
            var isFromFixedRegion = this._isEventFromFixedRegion(event);
            if (isFromFixedRegion) {
              // Don't preventDefault, don't stopPropagation - let button handle it completely
              return false;
            }

            // Otherwise, handle as option selection (when options container is focused)
            if (this.state.hovered !== _DropdownLayout2.NOT_HOVERED_INDEX) {
              this._onSelect(this.state.hovered, event);
              if (this.props.closeOnSelect) {
                this._onClose();
              }
              return true;
            }
            // If no option is hovered, return false to allow manual input handling
            return false;
          }
        case _DropdownLayout2.KEY.tab:
          {
            var _event$target;
            // Dialog mode: let natural Tab navigation work within dialog
            if (this._isDialogMode()) {
              return false;
            }

            // Menu mode: handle Tab key behavior
            // If an option is hovered, select it first (similar to Enter/Space)
            if (this.state.hovered !== _DropdownLayout2.NOT_HOVERED_INDEX) {
              event.preventDefault();
              this._onSelect(this.state.hovered, event);
              if (this.props.closeOnSelect) {
                this._onClose();
              }
              return true;
            }

            // No hovered option: close dropdown and determine if parent should handle Tab
            this._onClose();

            // Check if Tab originated from an input field with text
            // If so, return false to allow parent component (e.g., InputWithOptions)
            // to handle Tab and trigger onManuallyInput callback
            // Otherwise, return true to indicate we handled it (prevents DropdownBase double-closing)
            var inputValue = (_event$target = event.target) == null || (_event$target = _event$target.value) == null ? void 0 : _event$target.trim();
            var hasInputText = Boolean(inputValue);

            // Return false to allow parent handling, true to indicate we handled it
            return !hasInputText;
          }
        case _DropdownLayout2.KEY.arrowRight:
          {
            // Delegate to the component-level onDrillIn callback so the consumer
            // can move focus into an interactive child element (e.g. an actions menu).
            if (this.state.hovered === _DropdownLayout2.NOT_HOVERED_INDEX) {
              return false;
            }
            var {
              onDrillIn
            } = this.props;
            if (typeof onDrillIn === 'function') {
              var _this$props$options;
              var options = (_this$props$options = this.props.options) !== null && _this$props$options !== void 0 ? _this$props$options : [];
              var hoveredOption = options[this.state.hovered];
              onDrillIn(hoveredOption);
              event.preventDefault();
              event.stopPropagation();
              return true;
            }
            return false;
          }
        case _DropdownLayout2.KEY.escape:
          {
            this._onClose();
            event.stopPropagation();
            return true;
          }
        default:
          {
            return false;
          }
      }
    };
    this._focus = (focusedItemId, e) => {
      e && e.preventDefault();
      var element = this.children[focusedItemId];
      if (!element) {
        return;
      }
      var native = element.focus;
      var focusableHOC = element.wrappedComponentRef;
      var callback = native ? element.focus : focusableHOC ? focusableHOC.innerComponentRef.focus : () => ({});
      this.setState({
        focusedItemId
      }, () => callback == null ? void 0 : callback());
    };
    this._handleActionListNavigation = (event, id) => {
      var length = this.focusableItemsIdsList.length;
      var focusedItemId = this.state.focusedItemId;
      var {
        key
      } = event;
      var currentMenuItemIndex = this.focusableItemsIdsList.indexOf(id);
      var firstMenuItem = this.focusableItemsIdsList[0];
      var lastMenuItem = this.focusableItemsIdsList[length - 1];
      if (key === _DropdownLayout2.KEY.arrowLeft || key === _DropdownLayout2.KEY.arrowUp) {
        focusedItemId = id === 0 ? lastMenuItem : this.focusableItemsIdsList[currentMenuItemIndex - 1];
      }
      if (key === _DropdownLayout2.KEY.arrowRight || key === _DropdownLayout2.KEY.arrowDown) {
        focusedItemId = currentMenuItemIndex === length - 1 ? firstMenuItem : this.focusableItemsIdsList[currentMenuItemIndex + 1];
      }
      if (key === _DropdownLayout2.KEY.home) {
        focusedItemId = firstMenuItem;
      }
      if (key === _DropdownLayout2.KEY.end) {
        focusedItemId = lastMenuItem;
      }
      if (focusedItemId !== this.state.focusedItemId) {
        this._focus(focusedItemId, event);
        this._scrollIntoViewByIndex(focusedItemId);
      }
    };
    this._onActionListKeyDown = (event, id) => {
      // Action lists use direct focus on each item, so they have their own
      // keyboard handling that must run first.
      if (this.props.listType === _DropdownLayout2.ListType.action) {
        var {
          key: _key
        } = event;
        if (_key === _DropdownLayout2.KEY.space || _key === _DropdownLayout2.KEY.enter) {
          event.preventDefault();
          this._onActionClick({
            id: this.state.focusedItemId
          });
          this._onClose();
        } else if (_key === _DropdownLayout2.KEY.escape || _key === _DropdownLayout2.KEY.tab) {
          this._onClose();
        } else {
          this._handleActionListNavigation(event, id);
        }
        event.stopPropagation();
        return;
      }

      // For non-action lists: when focus is on an interactive child element
      // (e.g. a button the user drilled into via ArrowRight), handle keyboard
      // navigation back to the options container.
      var optionEl = event.currentTarget;
      var activeEl = document.activeElement;
      var containsFocusedElement = optionEl.contains(activeEl) && activeEl !== optionEl;
      if (!containsFocusedElement) {
        return;
      }
      var {
        key
      } = event;
      var restoreFocusToList = () => {
        if (this.props.onDrillOut) {
          this.props.onDrillOut();
        } else if (this.optionsRef.current) {
          this.optionsRef.current.focus();
        }
      };
      if (key === _DropdownLayout2.KEY.escape || key === _DropdownLayout2.KEY.arrowLeft) {
        event.preventDefault();
        event.stopPropagation();
        restoreFocusToList();
      }
      if (key === _DropdownLayout2.KEY.enter || key === _DropdownLayout2.KEY.space) {
        event.stopPropagation();
      }
      if (key === _DropdownLayout2.KEY.arrowDown || key === _DropdownLayout2.KEY.arrowUp) {
        event.preventDefault();
        event.stopPropagation();
      }
    };
    this._onClose = () => {
      var _this$props$onOptions3, _this$props3;
      (_this$props$onOptions3 = (_this$props3 = this.props).onOptionsNavigate) == null || _this$props$onOptions3.call(_this$props3, null);
      this._markOption(_DropdownLayout2.NOT_HOVERED_INDEX);
      if (this.props.onClose) {
        this.props.onClose();
      }
    };
    this._onFixedRegionFocus = () => {
      // Clear the highlighted/active list item when focus moves to header/footer button
      if (this.state.hovered !== _DropdownLayout2.NOT_HOVERED_INDEX) {
        this._markOption(_DropdownLayout2.NOT_HOVERED_INDEX);
      }
    };
    this._wrapWithInfiniteScroll = scrollableElement => {
      if (!this.optionsRef.current) {
        this.loadedWithUndefinedOptions = true;
      }
      return /*#__PURE__*/_react.default.createElement(_InfiniteScroll.default, {
        useWindow: true,
        dataHook: _DataAttr.DATA_HOOKS.INFINITE_SCROLL_CONTAINER,
        scrollElement: this.state.scrollElement,
        loadMore: this.props.loadMore,
        hasMore: this.props.hasMore,
        data: this.props.options,
        loader: /*#__PURE__*/_react.default.createElement("div", {
          className: _DropdownLayoutSt.classes.loader,
          __self: this,
          __source: {
            fileName: _jsxFileName,
            lineNumber: 857,
            columnNumber: 11
          }
        }, /*#__PURE__*/_react.default.createElement(_Loader.default, {
          dataHook: _DataAttr.DROPDOWN_LAYOUT_LOADER,
          size: "small",
          __self: this,
          __source: {
            fileName: _jsxFileName,
            lineNumber: 858,
            columnNumber: 13
          }
        })),
        __self: this,
        __source: {
          fileName: _jsxFileName,
          lineNumber: 849,
          columnNumber: 7
        }
      }, scrollableElement);
    };
    /** for testing purposes only */
    this._getDataAttributes = () => {
      var {
        visible,
        dropDirectionUp
      } = this.props;
      var {
        selectedId
      } = this.state;
      return (0, _filterObject.filterObject)({
        'data-hook': _DataAttr.DATA_HOOKS.CONTENT_CONTAINER,
        [_DataAttr.DATA_SHOWN]: visible,
        [_DataAttr.DATA_SELECTED_OPTION_ID]: selectedId === 0 ? "".concat(selectedId) : selectedId,
        [_DataAttr.DATA_DIRECTION]: dropDirectionUp ? _DataAttr.DROPDOWN_LAYOUT_DIRECTIONS.UP : _DataAttr.DROPDOWN_LAYOUT_DIRECTIONS.DOWN
      }, (_, value) => !!value);
    };
    // For testing purposes only
    this._getItemDataAttr = _ref3 => {
      var {
        hovered,
        selected,
        disabled
      } = _ref3;
      var {
        itemHeight,
        selectedHighlight
      } = this.props;
      return (0, _filterObject.filterObject)({
        [_DataAttr.DATA_OPTION.DISABLED]: disabled,
        [_DataAttr.DATA_OPTION.SELECTED]: selected && selectedHighlight,
        [_DataAttr.DATA_OPTION.HOVERED]: hovered,
        /* deprecated */
        [_DataAttr.DATA_OPTION.SIZE]: itemHeight
      }, (_, value) => !!value);
    };
    this._isSelectableOption = option => {
      if (!option) {
        return false;
      }
      if (this._isDivider(option)) {
        return false;
      }

      // only DropdownLayoutValueOption type has title prop, which is deprecated
      // therefore expecting error instead of dealing with it
      // @ts-expect-error
      var hasTitle = option.title;
      return !this._isDivider(option) && !option.disabled && !hasTitle;
    };
    this.state = {
      hovered: _DropdownLayout2.NOT_HOVERED_INDEX,
      selectedId: props.selectedId,
      scrollElement: null,
      focusedItemId: null
    };
  }
  componentDidMount() {
    if (this.loadedWithUndefinedOptions && this.optionsRef.current) {
      this.forceUpdate();
    }
    var {
      focusOnSelectedOption,
      scrollToOption,
      autoFocus
    } = this.props;
    if (focusOnSelectedOption) {
      this._focusOnSelectedOption();
    } else if (this.props.hasOwnProperty('focusOnOption')) {
      this._focusOnOption();
    }
    if (scrollToOption) {
      this._scrollToOption();
    }
    this._markOptionByProperty(this.props);

    /** @deprecated */
    _DropdownLayout2.MOUSE_EVENTS_SUPPORTED.forEach(eventName => {
      document.addEventListener(eventName, this._onMouseEventsHandler, true);
    });
    this._boundEvents = _DropdownLayout2.MOUSE_EVENTS_SUPPORTED;
    if (!this._isDialogMode() && autoFocus) {
      this._focusFirstOption();
    }
  }
  componentWillUnmount() {
    if (this._boundEvents && typeof document !== 'undefined') {
      this._boundEvents.forEach(eventName => {
        document.removeEventListener(eventName, this._onMouseEventsHandler, true);
      });
    }
  }
  componentDidUpdate(prevProps) {
    var {
      focusOnOption
    } = this.props;
    if (prevProps.focusOnOption !== focusOnOption) {
      this._focusOnOption();
    }
  }
  UNSAFE_componentWillReceiveProps(nextProps) {
    var options = this.props.options || [];
    var nextOptions = nextProps.options || [];
    if (this.props.visible !== nextProps.visible) {
      this._markOption(_DropdownLayout2.NOT_HOVERED_INDEX);
    }
    if (this.props.selectedId !== nextProps.selectedId) {
      this.setState({
        selectedId: nextProps.selectedId
      });
    }

    // make sure the same item is hovered if options changed
    if (this.state.hovered !== _DropdownLayout2.NOT_HOVERED_INDEX && (!nextOptions[this.state.hovered] || options[this.state.hovered].id !== nextOptions[this.state.hovered].id)) {
      var _nextProps$options;
      this._markOption(this._findIndex((_nextProps$options = nextProps.options) !== null && _nextProps$options !== void 0 ? _nextProps$options : [], item => item.id === options[this.state.hovered].id));
    }
    this._markOptionByProperty(nextProps);
  }
  _getOptionElementId(optionIndex) {
    return "dropdown-item-".concat(optionIndex);
  }
  _focusFirstOption() {
    this._focus(this.focusableItemsIdsList[0]);
  }

  /** @deprecated */
  _checkIfEventOnElements(e, elem) {
    var current = e.target;
    while (current.parentNode) {
      if (elem.indexOf(current) > -1) {
        return true;
      }
      current = current.parentNode;
    }
    return current !== document;
  }
  /** @deprecated */
  _renderTopArrow() {
    var {
      withArrow,
      visible
    } = this.props;
    return withArrow && visible ? /*#__PURE__*/_react.default.createElement("div", {
      "data-hook": _DataAttr.DATA_HOOKS.TOP_ARROW,
      className: _DropdownLayoutSt.classes.arrow,
      __self: this,
      __source: {
        fileName: _jsxFileName,
        lineNumber: 257,
        columnNumber: 7
      }
    }) : null;
  }
  _convertOptionToListItemSectionBuilder(_ref4) {
    var {
      option,
      idx
    } = _ref4;
    if (this._isDivider(option)) {
      return (0, _ListItemSection.listItemSectionBuilder)({
        dataHook: _DataAttr.OPTION_DATA_HOOKS.DIVIDER,
        id: option.id || idx,
        type: 'divider'
      });
    } else if (option.title) {
      return (0, _ListItemSection.listItemSectionBuilder)({
        dataHook: _DataAttr.OPTION_DATA_HOOKS.TITLE,
        id: option.id,
        type: 'subheader',
        title: option.value
      });
    } else {
      // This should never happen but let's make TS happy
      return undefined;
    }
  }
  _convertOptionToListItemActionBuilder(_ref5) {
    var {
      option,
      idx
    } = _ref5;
    var {
        id,
        value,
        disabled,
        disabledDescription,
        optionTitle,
        title
      } = option,
      rest = (0, _objectWithoutProperties2.default)(option, _excluded);
    var {
      size
    } = this.props;
    return (0, _ListItemAction.listItemActionBuilder)(_objectSpread({
      id: id !== undefined ? id : idx,
      ref: _ref6 => this.children[id] = _ref6,
      tabIndex: id === this.state.focusedItemId && !disabled ? '0' : '-1',
      disabled,
      disabledDescription,
      title: optionTitle,
      role: 'menuitem',
      size
    }, rest));
  }
  _isControlled() {
    return typeof this.props.selectedId !== 'undefined' && typeof this.props.onSelect !== 'undefined';
  }
  _focusOnSelectedOption() {
    if (this.selectedOption && this.optionsRef.current) {
      this.optionsRef.current.scrollTop = Math.max(this.selectedOption.offsetTop - this.selectedOption.offsetHeight, 0);
    }
  }
  _setSelectedOptionNode(optionNode, option) {
    if (option.id === this.state.selectedId) {
      this.selectedOption = optionNode;
    }
  }
  _markOption(index, options) {
    var {
      onOptionMarked
    } = this.props;
    options = options || this.props.options || [];
    this.setState({
      hovered: index
    });
    if (onOptionMarked) {
      var markedOption = options[index] || null;
      var markedOptionElementId = index === _DropdownLayout2.NOT_HOVERED_INDEX ? undefined : this._getOptionElementId(index);

      // the type declaration was incorrect, casting to avoid breaking changes after TS conversion
      onOptionMarked(markedOption, markedOptionElementId);
    }
  }
  _getMarkedIndex() {
    var options = this.props.options || [];
    var useHoverIndex = this.state.hovered > _DropdownLayout2.NOT_HOVERED_INDEX;
    var useSelectedIdIndex = typeof this.state.selectedId !== 'undefined';
    var markedIndex;
    if (useHoverIndex) {
      markedIndex = this.state.hovered;
    } else if (useSelectedIdIndex) {
      markedIndex = options.findIndex(option => option.id === this.state.selectedId);
    } else {
      markedIndex = _DropdownLayout2.NOT_HOVERED_INDEX;
    }
    return markedIndex;
  }
  getActiveDescendentElementId() {
    var options = this.props.options || [];
    var markedIndex = this._getMarkedIndex();
    if (markedIndex === _DropdownLayout2.NOT_HOVERED_INDEX) {
      markedIndex = options.findIndex(this._isSelectableOption);
    }
    return markedIndex === _DropdownLayout2.NOT_HOVERED_INDEX ? undefined : this._getOptionElementId(markedIndex);
  }
  _markNextStep(step) {
    var {
      onOptionsNavigate,
      options = []
    } = this.props;
    if (!options.some(this._isSelectableOption)) {
      return;
    }
    var markedIndex = this._getMarkedIndex();
    do {
      markedIndex = modulus(Math.max(markedIndex + step, -1), options.length);
    } while (!this._isSelectableOption(options[markedIndex]));
    var markedOption = options[markedIndex];
    onOptionsNavigate == null || onOptionsNavigate(markedOption);
    this._markOptionAtIndex(markedIndex);
  }
  _scrollToOption() {
    var _this$optionsRef$curr3;
    var {
      scrollToOption
    } = this.props;
    var options = this.props.options || [];
    var optionIndex = options.findIndex(option => option.id === scrollToOption);
    var optionNode = (_this$optionsRef$curr3 = this.optionsRef.current) == null ? void 0 : _this$optionsRef$curr3.childNodes[optionIndex];
    if (!optionNode || !this.optionsRef.current) {
      return;
    }
    this.optionsRef.current.scrollTop = Math.max(optionNode.offsetTop - optionNode.offsetHeight, 0);
  }
  _isEventFromFixedRegion(event) {
    var target = event.target;
    var region = target.closest('[data-dropdown-region]');
    if (!region) {
      return false;
    }
    var regionValue = region.getAttribute('data-dropdown-region');
    return regionValue === 'header' || regionValue === 'footer';
  }
  _isArrowNavigationDisabled(event) {
    // Disable arrow navigation only when event originates from fixed header/footer region
    return this._isEventFromFixedRegion(event);
  }
  _renderNode(node, region) {
    if (!node) return null;
    return /*#__PURE__*/_react.default.createElement("div", {
      "data-dropdown-region": region,
      onFocus: this._onFixedRegionFocus,
      __self: this,
      __source: {
        fileName: _jsxFileName,
        lineNumber: 830,
        columnNumber: 7
      }
    }, node);
  }
  _convertCustomOptionToBuilder(_ref7) {
    var {
      option
    } = _ref7;
    var {
      value: _value,
      id,
      disabled,
      disabledDescription,
      overrideOptionStyle,
      overrideStyle
    } = option;
    if (overrideStyle) {
      return {
        id,
        disabled,
        disabledDescription,
        overrideStyle,
        value: () => /*#__PURE__*/_react.default.createElement("div", {
          className: _DropdownLayoutSt.classes.dropdownOption,
          "data-hook": _DataAttr.DATA_HOOKS.OPTION,
          __self: this,
          __source: {
            fileName: _jsxFileName,
            lineNumber: 907,
            columnNumber: 11
          }
        }, _value)
      };
    }
    if (overrideOptionStyle) {
      return {
        id,
        disabled,
        disabledDescription,
        overrideOptionStyle,
        value: () => /*#__PURE__*/_react.default.createElement("div", {
          className: _DropdownLayoutSt.classes.dropdownOption,
          "data-hook": _DataAttr.DATA_HOOKS.OPTION,
          __self: this,
          __source: {
            fileName: _jsxFileName,
            lineNumber: 921,
            columnNumber: 11
          }
        }, _value)
      };
    } else {
      // This should never happen but let's make TS happy
      return undefined;
    }
  }
  _convertOptionToListItemSelectBuilder(_ref8) {
    var {
      option
    } = _ref8;
    var {
      value,
      id,
      disabled,
      disabledDescription
    } = option;
    var {
      selectedId
    } = this.state;
    var {
      itemHeight,
      selectedHighlight,
      size
    } = this.props;
    return (0, _ListItemSelect.listItemSelectBuilder)({
      id,
      title: /*#__PURE__*/_react.default.createElement("div", {
        "data-hook": _DataAttr.DATA_HOOKS.OPTION,
        __self: this,
        __source: {
          fileName: _jsxFileName,
          lineNumber: 943,
          columnNumber: 9
        }
      }, value),
      disabled,
      disabledDescription,
      size,
      selected: id === selectedId && selectedHighlight,
      className: (0, _DropdownLayoutSt.st)(_DropdownLayoutSt.classes.selectableOption, {
        itemHeight
      })
    });
  }
  _isBuilderOption(option) {
    var {
      value
    } = option;
    return typeof value === 'function';
  }
  _isCustomOption(option) {
    var {
      overrideOptionStyle,
      overrideStyle
    } = option;
    return overrideOptionStyle || overrideStyle;
  }
  _isActionOption(option) {
    return 'value' in option && option.value === _DropdownLayout2.ListType.action;
  }
  _isItemSection(option) {
    // only DropdownLayoutValueOption type has title prop, which is deprecated
    // therefore expecting error instead of dealing with it
    // @ts-expect-error
    var {
      title: isTitle
    } = option;
    return this._isDivider(option) || isTitle;
  }
  _isDivider(opt) {
    return opt.value === _DropdownLayout2.DIVIDER_OPTION_VALUE;
  }
  _convertOptionToBuilder(option, idx) {
    if (this._isBuilderOption(option)) {
      return option;
    } else if (this._isActionOption(option)) {
      return this._convertOptionToListItemActionBuilder({
        option,
        idx
      });
    } else if (this._isItemSection(option)) {
      return this._convertOptionToListItemSectionBuilder({
        option,
        idx
      });
    } else if (this._isCustomOption(option)) {
      return this._convertCustomOptionToBuilder({
        option
      });
    } else {
      return this._convertOptionToListItemSelectBuilder({
        option
      });
    }
  }
  _renderOption(_ref9) {
    var {
      option,
      idx
    } = _ref9;
    var isValueOption = opt => 'id' in opt && 'value' in opt && typeof opt.value !== 'function';
    var builderOption = this._convertOptionToBuilder(option, idx);
    var hasLink = isValueOption(option) && !!option.linkTo;
    var content = this._renderOptionContent({
      option: builderOption,
      idx,
      hasLink
    });
    var isActionItem = this.props.listType === _DropdownLayout2.ListType.action;
    return hasLink ? /*#__PURE__*/_react.default.createElement("a", {
      className: _DropdownLayoutSt.classes.linkItem,
      key: idx,
      "data-hook": _DataAttr.DATA_HOOKS.LINK_ITEM,
      href: option.linkTo,
      role: isActionItem ? undefined : 'option',
      "aria-selected": isActionItem || option.disabled ? undefined : option.id === this.state.selectedId,
      "aria-hidden": option.disabled,
      __self: this,
      __source: {
        fileName: _jsxFileName,
        lineNumber: 1025,
        columnNumber: 7
      }
    }, content) : content;
  }
  _renderOptionContent(_ref0) {
    var {
      option,
      idx,
      hasLink
    } = _ref0;
    if (!option) {
      return undefined;
    }
    var {
      itemHeight,
      selectedHighlight,
      listType
    } = this.props;
    var {
      selectedId,
      hovered
    } = this.state;
    var {
      id,
      disabled,
      // Only ListItemAction and ListItemSelect have disabledDescription prop
      // @ts-expect-error
      disabledDescription,
      // only ConvertedCustomOption type has overrideStyle prop, which is deprecated
      // therefore expecting error instead of dealing with it
      // @ts-expect-error
      overrideStyle,
      overrideOptionStyle
    } = option;
    var optionState = {
      selected: id === selectedId,
      hovered: idx === hovered,
      disabled,
      size: this.props.size
    };
    var isDisabledWithTooltip = disabled && !!disabledDescription;
    if (!disabled || isDisabledWithTooltip) {
      this.focusableItemsIdsList = [...this.focusableItemsIdsList, id];
    }
    var isActionItem = listType === _DropdownLayout2.ListType.action;
    return /*#__PURE__*/_react.default.createElement("div", (0, _extends2.default)({
      "aria-selected": hasLink || isActionItem || disabled ? undefined : optionState.selected,
      "aria-hidden": disabled
    }, this._getItemDataAttr(_objectSpread({}, optionState)), {
      role: hasLink || isActionItem ? undefined : 'option',
      className: overrideOptionStyle ? null : (0, _DropdownLayoutSt.st)(_DropdownLayoutSt.classes.option, _objectSpread(_objectSpread({}, optionState), {}, {
        selected: optionState.selected && selectedHighlight,
        itemHeight,
        overrideStyle
      })),
      id: this._getOptionElementId(idx),
      ref: node => this._setSelectedOptionNode(node, option),
      onClick: !disabled ? e => this._onSelect(idx, e) : undefined,
      key: idx,
      onMouseEnter: () => this._onMouseEnter(idx),
      onMouseLeave: this._onMouseLeave,
      "data-hook": "dropdown-item-".concat(id),
      onKeyDown: e => this._onActionListKeyDown(e, id),
      __self: this,
      __source: {
        fileName: _jsxFileName,
        lineNumber: 1112,
        columnNumber: 7
      }
    }), option == null ? void 0 : option.value(optionState));
  }
  _markOptionByProperty(props) {
    var options = props.options || [];
    if (this.state.hovered === _DropdownLayout2.NOT_HOVERED_INDEX && props.markedOption) {
      var selectableOptions = options.filter(this._isSelectableOption);
      if (selectableOptions.length) {
        var idToMark = props.markedOption === true ? selectableOptions[0].id : props.markedOption;
        var foundIndex = this._findIndex(options, item => item.id === idToMark);
        if (foundIndex !== -1) {
          this._markOption(foundIndex, props.options);
        }
      }
    }
  }
  _findIndex(arr, predicate) {
    return (Array.isArray(arr) ? arr : []).findIndex(predicate);
  }
  _renderOptions() {
    this.focusableItemsIdsList = [];
    this._saveOnClicks();
    var options = this.props.options || [];
    return options.map((option, idx) => this._renderOption({
      option,
      idx
    }));
  }
  render() {
    var _this$props$options2;
    var {
      className,
      visible,
      dropDirectionUp,
      onMouseEnter,
      onMouseDown,
      fixedHeader,
      withArrow,
      fixedFooter,
      inContainer,
      overflow,
      maxHeightPixels = 260,
      minWidthPixels,
      infiniteScroll,
      dataHook,
      listType,
      overlayScrollbarProps,
      listboxId
    } = this.props;
    var renderedOptions = this._renderOptions();
    var OverlayScrollbarHostElement = overlayScrollbarProps == null ? void 0 : overlayScrollbarProps.OverlayScrollbarHostElement;
    var OverlayScrollbarContentElement = overlayScrollbarProps == null ? void 0 : overlayScrollbarProps.OverlayScrollbarContentElement;
    var optionsContainerProps = {
      style: {
        maxHeight: getUnit(parseInt(String(maxHeightPixels), 10) - 35),
        overflow
      },
      'data-hook': _DataAttr.DATA_HOOKS.DROPDOWN_LAYOUT_OPTIONS,
      role: listType === _DropdownLayout2.ListType.select ? 'listbox' : 'menu',
      id: listboxId,
      // Make options container focusable as a focus stop in Modal Dialog pattern
      tabIndex: this._isDialogMode() ? 0 : -1,
      // Use aria-activedescendant pattern (W3C standard)
      'aria-activedescendant': this.state.hovered !== _DropdownLayout2.NOT_HOVERED_INDEX ? this._getOptionElementId(this.state.hovered) : undefined
    };
    var options = infiniteScroll ? this._wrapWithInfiniteScroll(renderedOptions) : renderedOptions;
    var optionsContainer = this.props.scrollbar === _DropdownLayout2.Scrollbar.OVERLAY && OverlayScrollbarHostElement && OverlayScrollbarContentElement ? /*#__PURE__*/_react.default.createElement(OverlayScrollbarHostElement, (0, _extends2.default)({
      className: _DropdownLayoutSt.classes.options
    }, optionsContainerProps, {
      __self: this,
      __source: {
        fileName: _jsxFileName,
        lineNumber: 1250,
        columnNumber: 9
      }
    }), /*#__PURE__*/_react.default.createElement(OverlayScrollbarContentElement, {
      className: _DropdownLayoutSt.classes.optionsContent,
      ref: (0, _forkRef.forkRef)(this.optionsRef, this.setScrollElement),
      __self: this,
      __source: {
        fileName: _jsxFileName,
        lineNumber: 1254,
        columnNumber: 11
      }
    }, options)) : /*#__PURE__*/_react.default.createElement("div", (0, _extends2.default)({
      className: (0, _DropdownLayoutSt.st)(_DropdownLayoutSt.classes.options, _DropdownLayoutSt.classes.optionsContent),
      ref: (0, _forkRef.forkRef)(this.optionsRef, this.setScrollElement)
    }, optionsContainerProps, {
      __self: this,
      __source: {
        fileName: _jsxFileName,
        lineNumber: 1265,
        columnNumber: 9
      }
    }), options);
    var isEmpty = !fixedHeader && !fixedFooter && !((_this$props$options2 = this.props.options) != null && _this$props$options2.length) && (!this.props.infiniteScroll || !this.props.hasMore);
    return /*#__PURE__*/_react.default.createElement("div", {
      "data-list-type": listType,
      "data-hook": dataHook,
      className: (0, _DropdownLayoutSt.st)(_DropdownLayoutSt.classes.root, {
        hidden: isEmpty,
        visible,
        withArrow,
        direction: dropDirectionUp ? _DataAttr.DROPDOWN_LAYOUT_DIRECTIONS.UP : _DataAttr.DROPDOWN_LAYOUT_DIRECTIONS.DOWN,
        containerStyles: !inContainer
      }, className),
      onKeyDown: this._onSelectListKeyDown,
      onMouseEnter: onMouseEnter,
      onMouseLeave: this._onContainerMouseLeave,
      onMouseDown: onMouseDown,
      ref: this.containerRef,
      __self: this,
      __source: {
        fileName: _jsxFileName,
        lineNumber: 1281,
        columnNumber: 7
      }
    }, /*#__PURE__*/_react.default.createElement("div", (0, _extends2.default)({}, this._getDataAttributes(), {
      className: _DropdownLayoutSt.classes.contentContainer,
      style: {
        overflow,
        maxHeight: maxHeightPixels ? getUnit(maxHeightPixels) : undefined,
        minWidth: minWidthPixels ? getUnit(minWidthPixels) : undefined
      },
      __self: this,
      __source: {
        fileName: _jsxFileName,
        lineNumber: 1303,
        columnNumber: 9
      }
    }), this._renderNode(fixedHeader, 'header'), optionsContainer, this._renderNode(fixedFooter, 'footer')), this._renderTopArrow());
  }
}
exports.DropdownLayout = DropdownLayout;
DropdownLayout.defaultProps = {
  options: [],
  tabIndex: 0,
  maxHeightPixels: 260,
  closeOnSelect: true,
  itemHeight: 'small',
  selectedHighlight: true,
  inContainer: false,
  infiniteScroll: false,
  loadMore: undefined,
  hasMore: false,
  markedOption: false,
  overflow: 'auto',
  listType: _DropdownLayout2.ListType.select,
  scrollbar: 'fixed'
};
DropdownLayout.displayName = 'DropdownLayout';
DropdownLayout.NONE_SELECTED_ID = _DropdownLayout2.NOT_HOVERED_INDEX;
var _default = exports.default = (0, _withOverlayScrollbar.withOverlayScrollbar)(DropdownLayout);
//# sourceMappingURL=DropdownLayout.js.map