"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.EuiSelectable = void 0;
var _react = _interopRequireWildcard(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _classnames = _interopRequireDefault(require("classnames"));
var _services = require("../../services");
var _loading = require("../loading");
var _spacer = require("../spacer");
var _accessibility = require("../accessibility");
var _i18n = require("../i18n");
var _selectable_search = require("./selectable_search");
var _selectable_message = require("./selectable_message");
var _selectable_list = require("./selectable_list");
var _matching_options = require("./matching_options");
var _selectable = require("./selectable.styles");
var _react2 = require("@emotion/react");
var _excluded = ["children", "className", "options", "onChange", "onActiveOptionChange", "searchable", "searchProps", "singleSelection", "isLoading", "listProps", "renderOption", "height", "allowExclusions", "aria-label", "aria-describedby", "loadingMessage", "noMatchesMessage", "emptyMessage", "errorMessage", "selectableScreenReaderText", "isPreFiltered", "optionMatcher"],
  _excluded2 = ["aria-label", "aria-describedby", "onChange", "defaultValue", "inputRef"],
  _excluded3 = ["aria-label", "aria-describedby", "isVirtualized", "rowHeight"];
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
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) { _defineProperty(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; }
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], t.indexOf(o) >= 0 || {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.indexOf(n) >= 0) continue; t[n] = r[n]; } return t; }
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
function _possibleConstructorReturn(t, e) { if (e && ("object" == _typeof(e) || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); }
function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); }
function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); }
function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License
 * 2.0 and the Server Side Public License, v 1; you may not use this file except
 * in compliance with, at your election, the Elastic License 2.0 or the Server
 * Side Public License, v 1.
 */ /**
 * The `searchable` prop has significant implications for a11y. When present, we effectively change from adhering to the
 * - ARIA `listbox` spec (@see https://www.w3.org/TR/wai-aria-practices-1.2/#Listbox)
 * - ARIA `combobox` spec (@see https://www.w3.org/TR/wai-aria-practices-1.2/#combobox)
 *
 * and (re)implement all relevant attributes and keyboard interactions.
 * Take note of logic that relies on `searchable` to ensure that any modifications remain in alignment.
 *
 * `searchProps` can only be specified when `searchable` is `true`.
 */
var EuiSelectable = exports.EuiSelectable = /*#__PURE__*/function (_Component) {
  function EuiSelectable(props) {
    var _searchProps$onChange;
    var _this;
    _classCallCheck(this, EuiSelectable);
    _this = _callSuper(this, EuiSelectable, [props]);
    _defineProperty(_this, "inputRef", null);
    _defineProperty(_this, "containerRef", /*#__PURE__*/(0, _react.createRef)());
    _defineProperty(_this, "optionsListRef", /*#__PURE__*/(0, _react.createRef)());
    _defineProperty(_this, "preventOnFocus", false);
    _defineProperty(_this, "rootId", void 0);
    _defineProperty(_this, "messageContentId", void 0);
    _defineProperty(_this, "listId", void 0);
    _defineProperty(_this, "isFocusOnSearchOrListBox", function (target) {
      var _this$optionsListRef$;
      var searchHasFocus = _this.props.searchable && target === _this.inputRef;
      var listBox = (_this$optionsListRef$ = _this.optionsListRef.current) === null || _this$optionsListRef$ === void 0 || (_this$optionsListRef$ = _this$optionsListRef$.listBoxRef) === null || _this$optionsListRef$ === void 0 ? void 0 : _this$optionsListRef$.parentElement;
      var listBoxContainsFocus = target instanceof Node && (listBox === null || listBox === void 0 ? void 0 : listBox.contains(target));
      var listBoxHasFocus = target === listBox || listBoxContainsFocus;
      return searchHasFocus || listBoxHasFocus;
    });
    _defineProperty(_this, "onMouseDown", function () {
      // Bypass onFocus when a click event originates from this.containerRef.
      // Prevents onFocus from scrolling away from a clicked option and negating the selection event.
      // https://github.com/elastic/eui/issues/4147
      _this.preventOnFocus = true;
    });
    _defineProperty(_this, "onFocus", function (event) {
      if (_this.preventOnFocus) {
        _this.preventOnFocus = false;
        return;
      }
      if (event && _this.props.searchable && event.target === _this.inputRef) {
        _this.setState({
          isFocused: true
        });
        return;
      }
      if (!_this.state.visibleOptions.length || _this.state.activeOptionIndex != null) {
        return;
      }
      if (event && !_this.isFocusOnSearchOrListBox(event.target)) {
        return;
      }
      var firstSelected = _this.state.visibleOptions.findIndex(function (option) {
        return option.checked && !option.disabled && !option.isGroupLabel;
      });
      if (firstSelected > -1) {
        _this.setState({
          activeOptionIndex: firstSelected,
          isFocused: true
        });
      } else {
        _this.setState({
          activeOptionIndex: _this.state.visibleOptions.findIndex(function (option) {
            return !option.disabled && !option.isGroupLabel;
          }),
          isFocused: true
        });
      }
    });
    _defineProperty(_this, "onKeyDown", function (event) {
      var optionsList = _this.optionsListRef.current;

      // Check if the user is interacting with something other than the
      // searchbox or selection list. If so, the user may be attempting to
      // interact with the search clear button or a totally custom button,
      // and listbox keyboard navigation/selection should not be triggered.
      if (!_this.isFocusOnSearchOrListBox(event.target)) {
        _this.setState({
          activeOptionIndex: undefined,
          isFocused: false
        });
        return;
      }
      switch (event.key) {
        case _services.keys.ARROW_UP:
          event.preventDefault();
          event.stopPropagation();
          _this.incrementActiveOptionIndex(-1);
          break;
        case _services.keys.ARROW_DOWN:
          event.preventDefault();
          event.stopPropagation();
          _this.incrementActiveOptionIndex(1);
          break;

        // For non-searchable instances, SPACE interaction should align with
        // the user expectation of selection toggling (e.g., input[type=checkbox]).
        // ENTER is also a valid selection mechanism in this case.
        case _services.keys.ENTER:
        case _services.keys.SPACE:
          if (_this.props.searchable) {
            // For searchable instances, SPACE is reserved as a character for filtering
            // via the input box, and as such only ENTER will toggle selection.
            if (event.target === _this.inputRef && event.key === _services.keys.SPACE) {
              return;
            }
          }
          event.preventDefault();
          event.stopPropagation();
          if (_this.state.activeOptionIndex != null && optionsList) {
            event.persist(); // NOTE: This is needed for React v16 backwards compatibility
            optionsList.onAddOrRemoveOption(_this.state.visibleOptions[_this.state.activeOptionIndex], event);
          }
          break;
        case _services.keys.ALT:
        case _services.keys.SHIFT:
        case _services.keys.CTRL:
        case _services.keys.META:
          break;
        default:
          _this.setState({
            activeOptionIndex: undefined
          }, _this.onFocus);
          break;
      }
    });
    _defineProperty(_this, "incrementActiveOptionIndex", function (amount) {
      // If there are no options available, do nothing.
      if (!_this.state.visibleOptions.length) {
        return;
      }
      _this.setState(function (_ref) {
        var activeOptionIndex = _ref.activeOptionIndex,
          visibleOptions = _ref.visibleOptions;
        var nextActiveOptionIndex;
        if (activeOptionIndex == null) {
          // If this is the beginning of the user's keyboard navigation of the menu, then we'll focus
          // either the first or last item.
          nextActiveOptionIndex = amount < 0 ? visibleOptions.length - 1 : 0;
        } else {
          nextActiveOptionIndex = activeOptionIndex + amount;
          if (nextActiveOptionIndex < 0) {
            nextActiveOptionIndex = visibleOptions.length - 1;
          } else if (nextActiveOptionIndex === visibleOptions.length) {
            nextActiveOptionIndex = 0;
          }
        }

        // Group titles and disabled options are included in option list but are not selectable
        var direction = amount > 0 ? 1 : -1;
        while (visibleOptions[nextActiveOptionIndex].isGroupLabel || visibleOptions[nextActiveOptionIndex].disabled) {
          nextActiveOptionIndex = nextActiveOptionIndex + direction;
          if (nextActiveOptionIndex < 0) {
            nextActiveOptionIndex = visibleOptions.length - 1;
          } else if (nextActiveOptionIndex === visibleOptions.length) {
            nextActiveOptionIndex = 0;
          }
        }
        return {
          activeOptionIndex: nextActiveOptionIndex
        };
      });
    });
    _defineProperty(_this, "onSearchChange", function (searchValue, visibleOptions) {
      var _this$props$searchPro, _this$props$searchPro2;
      _this.setState({
        searchValue: searchValue,
        visibleOptions: visibleOptions,
        activeOptionIndex: undefined
      }, function () {
        if (_this.state.isFocused) {
          _this.onFocus();
        }
      });
      (_this$props$searchPro = _this.props.searchProps) === null || _this$props$searchPro === void 0 || (_this$props$searchPro2 = _this$props$searchPro.onChange) === null || _this$props$searchPro2 === void 0 || _this$props$searchPro2.call(_this$props$searchPro, searchValue, visibleOptions);
    });
    _defineProperty(_this, "onContainerBlur", function (e) {
      // Ignore blur events when moving from search to option to avoid activeOptionIndex conflicts
      if (_this.isFocusOnSearchOrListBox(e.relatedTarget)) {
        return;
      }
      _this.setState({
        activeOptionIndex: undefined,
        isFocused: false
      });
    });
    _defineProperty(_this, "onOptionClick", function (options, event, clickedOption) {
      var _this$props = _this.props,
        isPreFiltered = _this$props.isPreFiltered,
        onChange = _this$props.onChange,
        optionMatcher = _this$props.optionMatcher;
      var searchValue = _this.state.searchValue;
      var visibleOptions = (0, _matching_options.getMatchingOptions)({
        options: options,
        searchValue: searchValue !== null && searchValue !== void 0 ? searchValue : '',
        isPreFiltered: !!isPreFiltered,
        selectedOptions: [],
        optionMatcher: optionMatcher
      });
      _this.setState({
        visibleOptions: visibleOptions
      });
      if (onChange) {
        onChange(options, event, clickedOption);
      }
    });
    _defineProperty(_this, "scrollToItem", function (index, align) {
      var _this$optionsListRef$2;
      (_this$optionsListRef$2 = _this.optionsListRef.current) === null || _this$optionsListRef$2 === void 0 || (_this$optionsListRef$2 = _this$optionsListRef$2.listRef) === null || _this$optionsListRef$2 === void 0 || _this$optionsListRef$2.scrollToItem(index, align);
    });
    _defineProperty(_this, "makeOptionId", function (index) {
      return index != null ? "".concat(_this.listId, "_option-").concat(index) : '';
    });
    _this.rootId = props.id ? function (suffix) {
      return "".concat(props.id).concat(suffix ? "_".concat(suffix) : '');
    } : (0, _services.htmlIdGenerator)();
    _this.listId = _this.rootId('listbox');
    _this.messageContentId = _this.rootId('messageContent');
    var _options = props.options,
      singleSelection = props.singleSelection,
      _isPreFiltered = props.isPreFiltered,
      searchProps = props.searchProps;
    var initialSearchValue = (searchProps === null || searchProps === void 0 ? void 0 : searchProps.value) || String((searchProps === null || searchProps === void 0 ? void 0 : searchProps.defaultValue) || '');
    var _visibleOptions = (0, _matching_options.getMatchingOptions)({
      options: _options,
      searchValue: initialSearchValue,
      isPreFiltered: !!_isPreFiltered,
      selectedOptions: [],
      optionMatcher: props.optionMatcher
    });
    searchProps === null || searchProps === void 0 || (_searchProps$onChange = searchProps.onChange) === null || _searchProps$onChange === void 0 || _searchProps$onChange.call(searchProps, initialSearchValue, _visibleOptions);

    // ensure that the currently selected single option is active if it is in the visibleOptions
    var selectedOptions = _options.filter(function (option) {
      return option.checked;
    });
    var _activeOptionIndex;
    if (singleSelection && selectedOptions.length === 1) {
      if (_visibleOptions.includes(selectedOptions[0])) {
        _activeOptionIndex = _visibleOptions.indexOf(selectedOptions[0]);
      }
    }
    _this.state = {
      activeOptionIndex: _activeOptionIndex,
      searchValue: initialSearchValue,
      visibleOptions: _visibleOptions,
      isFocused: false
    };
    return _this;
  }
  _inherits(EuiSelectable, _Component);
  return _createClass(EuiSelectable, [{
    key: "componentDidUpdate",
    value: function componentDidUpdate(prevProps, prevState) {
      if (prevState.activeOptionIndex !== this.state.activeOptionIndex) {
        var _this$props$onActiveO, _this$props2;
        var activeOption = this.state.activeOptionIndex != null ? this.state.visibleOptions[this.state.activeOptionIndex] : null;
        (_this$props$onActiveO = (_this$props2 = this.props).onActiveOptionChange) === null || _this$props$onActiveO === void 0 || _this$props$onActiveO.call(_this$props2, activeOption);
      }
    }
  }, {
    key: "render",
    value: function render() {
      var _this2 = this;
      var _this$props3 = this.props,
        children = _this$props3.children,
        className = _this$props3.className,
        options = _this$props3.options,
        onChange = _this$props3.onChange,
        onActiveOptionChange = _this$props3.onActiveOptionChange,
        searchable = _this$props3.searchable,
        searchProps = _this$props3.searchProps,
        singleSelection = _this$props3.singleSelection,
        isLoading = _this$props3.isLoading,
        listProps = _this$props3.listProps,
        renderOption = _this$props3.renderOption,
        height = _this$props3.height,
        allowExclusions = _this$props3.allowExclusions,
        ariaLabel = _this$props3['aria-label'],
        ariaDescribedby = _this$props3['aria-describedby'],
        loadingMessage = _this$props3.loadingMessage,
        noMatchesMessage = _this$props3.noMatchesMessage,
        emptyMessage = _this$props3.emptyMessage,
        errorMessage = _this$props3.errorMessage,
        selectableScreenReaderText = _this$props3.selectableScreenReaderText,
        isPreFiltered = _this$props3.isPreFiltered,
        optionMatcher = _this$props3.optionMatcher,
        rest = _objectWithoutProperties(_this$props3, _excluded);
      var _this$state = this.state,
        searchValue = _this$state.searchValue,
        visibleOptions = _this$state.visibleOptions,
        activeOptionIndex = _this$state.activeOptionIndex;

      // Some messy destructuring here to remove aria-label/describedby from searchProps and listProps
      // Made messier by some TS requirements
      // The aria attributes are then used in getAccessibleName() to place them where they need to go
      var unknownAccessibleName = {
        'aria-label': undefined,
        'aria-describedby': undefined
      };
      var _ref2 = searchProps || unknownAccessibleName,
        searchAriaLabel = _ref2['aria-label'],
        searchAriaDescribedby = _ref2['aria-describedby'],
        propsOnChange = _ref2.onChange,
        defaultValue = _ref2.defaultValue,
        inputRef = _ref2.inputRef,
        cleanedSearchProps = _objectWithoutProperties(_ref2, _excluded2);
      var _ref3 = listProps || unknownAccessibleName,
        listAriaLabel = _ref3['aria-label'],
        listAriaDescribedby = _ref3['aria-describedby'],
        isVirtualized = _ref3.isVirtualized,
        rowHeight = _ref3.rowHeight,
        cleanedListProps = _objectWithoutProperties(_ref3, _excluded3);
      var virtualizedProps;
      if (isVirtualized === false) {
        virtualizedProps = {
          isVirtualized: isVirtualized
        };
      } else if (rowHeight != null) {
        virtualizedProps = {
          rowHeight: rowHeight
        };
      }
      var classes = (0, _classnames.default)('euiSelectable', className);
      var cssStyles = [_selectable.euiSelectableStyles.euiSelectable, height === 'full' && _selectable.euiSelectableStyles.fullHeight];

      /** Create message content that replaces the list if no options are available (yet) */
      var messageContent;
      if (errorMessage != null) {
        messageContent = typeof errorMessage === 'string' ? (0, _react2.jsx)("p", null, errorMessage) : errorMessage;
      } else if (isLoading) {
        if (loadingMessage === undefined || typeof loadingMessage === 'string') {
          messageContent = (0, _react2.jsx)(_react.default.Fragment, null, (0, _react2.jsx)(_loading.EuiLoadingSpinner, {
            size: "m"
          }), (0, _react2.jsx)(_spacer.EuiSpacer, {
            size: "xs"
          }), (0, _react2.jsx)("p", null, loadingMessage || (0, _react2.jsx)(_i18n.EuiI18n, {
            token: "euiSelectable.loadingOptions",
            default: "Loading options"
          })));
        } else {
          messageContent = /*#__PURE__*/_react.default.cloneElement(loadingMessage, _objectSpread({
            id: this.messageContentId
          }, loadingMessage.props));
        }
      } else if (searchValue && visibleOptions.length === 0) {
        if (noMatchesMessage === undefined || typeof noMatchesMessage === 'string') {
          messageContent = (0, _react2.jsx)("p", null, noMatchesMessage || (0, _react2.jsx)(_i18n.EuiI18n, {
            token: "euiSelectable.noMatchingOptions",
            default: "{searchValue} doesn't match any options",
            values: {
              searchValue: (0, _react2.jsx)("strong", null, searchValue)
            }
          }));
        } else {
          messageContent = /*#__PURE__*/_react.default.cloneElement(noMatchesMessage, _objectSpread({
            id: this.messageContentId
          }, noMatchesMessage.props));
        }
      } else if (!options.length) {
        if (emptyMessage === undefined || typeof emptyMessage === 'string') {
          messageContent = (0, _react2.jsx)("p", null, emptyMessage || (0, _react2.jsx)(_i18n.EuiI18n, {
            token: "euiSelectable.noAvailableOptions",
            default: "No options available"
          }));
        } else {
          messageContent = /*#__PURE__*/_react.default.cloneElement(emptyMessage, _objectSpread({
            id: this.messageContentId
          }, emptyMessage.props));
        }
      }

      /**
       * There are lots of ways to add an accessible name
       * Usually we want the same name for the input and the listbox (which is added by aria-label/describedby)
       * But you can always override it using searchProps or listProps
       * This finds the correct name to use
       *
       * TODO: This doesn't handle being labelled (<label for="idOfInput">)
       */
      var getAccessibleName = function getAccessibleName(props, messageContentId) {
        if (props && props['aria-label']) {
          return {
            'aria-label': props['aria-label']
          };
        }
        var messageContentIdString = messageContentId ? " ".concat(messageContentId) : '';
        if (props && props['aria-describedby']) {
          return {
            'aria-describedby': "".concat(props['aria-describedby']).concat(messageContentIdString)
          };
        }
        if (ariaLabel) {
          return {
            'aria-label': ariaLabel
          };
        }
        if (ariaDescribedby) {
          return {
            'aria-describedby': "".concat(ariaDescribedby).concat(messageContentIdString)
          };
        }
        return {};
      };
      var searchAccessibleName = getAccessibleName(searchProps, this.messageContentId);
      var searchHasAccessibleName = Boolean(Object.keys(searchAccessibleName).length);
      var search = searchable ? (0, _react2.jsx)(_i18n.EuiI18n, {
        tokens: ['euiSelectable.screenReaderInstructions', 'euiSelectable.placeholderName'],
        defaults: ['Use the Up and Down arrow keys to move focus over options. Press Enter to select. Press Escape to collapse options.', 'Filter options']
      }, function (_ref4) {
        var _ref5 = _slicedToArray(_ref4, 2),
          screenReaderInstructions = _ref5[0],
          placeholderName = _ref5[1];
        return (0, _react2.jsx)(_react.default.Fragment, null, (0, _react2.jsx)(_selectable_search.EuiSelectableSearch, _extends({
          "aria-describedby": listAriaDescribedbyId,
          key: "listSearch",
          options: options,
          value: searchValue,
          onChange: _this2.onSearchChange,
          listId: _this2.optionsListRef.current ? _this2.listId : undefined // Only pass the listId if it exists on the page
          ,
          "aria-activedescendant": activeOptionIndex != null ? _this2.makeOptionId(activeOptionIndex) : undefined,
          placeholder: placeholderName,
          isPreFiltered: !!isPreFiltered,
          optionMatcher: optionMatcher,
          inputRef: function inputRef(node) {
            var _searchProps$inputRef;
            _this2.inputRef = node;
            searchProps === null || searchProps === void 0 || (_searchProps$inputRef = searchProps.inputRef) === null || _searchProps$inputRef === void 0 || _searchProps$inputRef.call(searchProps, node);
          }
        }, searchHasAccessibleName ? searchAccessibleName : {
          'aria-label': placeholderName
        }, cleanedSearchProps)), (0, _react2.jsx)(_accessibility.EuiScreenReaderOnly, null, (0, _react2.jsx)("p", {
          id: listAriaDescribedbyId
        }, selectableScreenReaderText, " ", screenReaderInstructions)));
      }) : undefined;
      var resultsLength = visibleOptions.filter(function (option) {
        return !option.disabled;
      }).length;
      var listAriaDescribedbyId = this.rootId('instructions');
      var listAccessibleName = getAccessibleName(listProps, listAriaDescribedbyId);
      var listHasAccessibleName = Boolean(Object.keys(listAccessibleName).length);
      var list = (0, _react2.jsx)(_i18n.EuiI18n, {
        token: "euiSelectable.placeholderName",
        default: "Filter options"
      }, function (placeholderName) {
        return (0, _react2.jsx)(_react.default.Fragment, null, searchable && (0, _react2.jsx)(_i18n.EuiI18n, {
          token: "euiSelectable.searchResults",
          default: function _default(_ref6) {
            var resultsLength = _ref6.resultsLength;
            return "".concat(resultsLength, " result").concat(resultsLength === 1 ? '' : 's', " available");
          },
          values: {
            resultsLength: resultsLength
          }
        }, function (searchResults) {
          return (0, _react2.jsx)(_accessibility.EuiScreenReaderLive, {
            isActive: messageContent != null || activeOptionIndex != null
          }, messageContent || searchResults);
        }), messageContent ? (0, _react2.jsx)(_selectable_message.EuiSelectableMessage, {
          "data-test-subj": "euiSelectableMessage",
          id: _this2.messageContentId,
          bordered: listProps && listProps.bordered
        }, messageContent) : (0, _react2.jsx)(_selectable_list.EuiSelectableList, _extends({
          "data-test-subj": "euiSelectableList",
          key: "list",
          options: options,
          visibleOptions: visibleOptions,
          searchValue: searchValue,
          isPreFiltered: isPreFiltered,
          activeOptionIndex: activeOptionIndex,
          setActiveOptionIndex: function setActiveOptionIndex(index, cb) {
            _this2.setState({
              activeOptionIndex: index
            }, cb);
          },
          onOptionClick: _this2.onOptionClick,
          singleSelection: singleSelection,
          ref: _this2.optionsListRef,
          renderOption: renderOption,
          height: height,
          allowExclusions: allowExclusions,
          searchable: searchable,
          makeOptionId: _this2.makeOptionId,
          listId: _this2.listId
        }, listHasAccessibleName ? listAccessibleName : searchable && {
          'aria-label': placeholderName
        }, cleanedListProps, virtualizedProps)));
      });
      return (0, _react2.jsx)("div", _extends({
        ref: this.containerRef,
        css: cssStyles,
        className: classes,
        onKeyDown: this.onKeyDown,
        onBlur: this.onContainerBlur,
        onFocus: this.onFocus,
        onMouseDown: this.onMouseDown
      }, rest), children && children(list, search));
    }
  }], [{
    key: "getDerivedStateFromProps",
    value: function getDerivedStateFromProps(nextProps, prevState) {
      var _stateUpdate$searchVa;
      var options = nextProps.options,
        isPreFiltered = nextProps.isPreFiltered,
        searchProps = nextProps.searchProps,
        optionMatcher = nextProps.optionMatcher;
      var activeOptionIndex = prevState.activeOptionIndex,
        searchValue = prevState.searchValue;
      var stateUpdate = {
        searchValue: searchValue,
        activeOptionIndex: activeOptionIndex
      };
      if ((searchProps === null || searchProps === void 0 ? void 0 : searchProps.value) != null && searchProps.value !== searchValue) {
        stateUpdate.searchValue = searchProps.value;
      }
      stateUpdate.visibleOptions = (0, _matching_options.getMatchingOptions)({
        options: options,
        searchValue: (_stateUpdate$searchVa = stateUpdate.searchValue) !== null && _stateUpdate$searchVa !== void 0 ? _stateUpdate$searchVa : '',
        isPreFiltered: !!isPreFiltered,
        selectedOptions: [],
        optionMatcher: optionMatcher
      });
      if (activeOptionIndex != null && activeOptionIndex >= stateUpdate.visibleOptions.length) {
        stateUpdate.activeOptionIndex = -1;
      }
      return stateUpdate;
    }
  }]);
}(_react.Component);
_defineProperty(EuiSelectable, "defaultProps", {
  options: [],
  singleSelection: false,
  searchable: false,
  isPreFiltered: false,
  optionMatcher: (0, _matching_options.createPartialStringEqualityOptionMatcher)()
});
EuiSelectable.propTypes = {
  className: _propTypes.default.string,
  "aria-label": _propTypes.default.string,
  "data-test-subj": _propTypes.default.string,
  css: _propTypes.default.any,
  /**
       * Hooks up a search box to filter the list (boolean)
       */
  searchable: _propTypes.default.oneOfType([_propTypes.default.oneOf([false]).isRequired, _propTypes.default.oneOf([true]).isRequired]).isRequired,
  /**
       * Passes props down to the `EuiFieldSearch`.
       * {@link EuiSelectableSearchProps}
       */
  searchProps: _propTypes.default.any,
  /**
       * Function that takes the `list` node and then
       * the `search` node (if `searchable` is applied)
       */
  children: _propTypes.default.func,
  /**
       * Array of EuiSelectableOption objects. See {@link EuiSelectableOption}
       */
  options: _propTypes.default.arrayOf(_propTypes.default.shape({
    /**
       * Optional `boolean`.
       * Set to `true` to indicate object is just a grouping label, not a selectable item
       */
    isGroupLabel: _propTypes.default.oneOfType([_propTypes.default.oneOf([true]).isRequired, _propTypes.default.oneOf([false])]),
    className: _propTypes.default.string,
    "aria-label": _propTypes.default.string,
    "data-test-subj": _propTypes.default.string,
    css: _propTypes.default.any,
    /**
       * Visible label of option.
       * Must be unique across items if `key` is not supplied
       */
    label: _propTypes.default.string,
    /**
       * Optionally change the searchable term by passing a different string other than the `label`.
       * Best used when creating a custom `optionRender` to separate the label from metadata but allowing to search on both
       */
    searchableLabel: _propTypes.default.string,
    /**
       * Must be unique across items.
       * Will be used to match options instead of `label`
       */
    key: _propTypes.default.string,
    /**
       * Leave `undefined` to indicate not selected. Pass a string of
       * 'on' to indicate inclusion, 'off' to indicate exclusion,
       * or 'mixed' to indicate inclusion for some.
       */
    checked: _propTypes.default.any,
    disabled: _propTypes.default.bool,
    /**
       * Node to add between the selection icon and the label
       */
    prepend: _propTypes.default.node,
    /**
       * Node to add to the far right of the item
       */
    append: _propTypes.default.node,
    ref: _propTypes.default.func,
    /**
       * Option data to pass through to the `renderOptions` element.
       * Bypass `EuiSelectableItem` and avoid DOM attribute warnings.
       */
    data: _propTypes.default.shape({}),
    /**
       * How to handle long text within the item.
       * Wrapping only works if `isVirtualization` is false.
       * @default 'truncate'
       */
    textWrap: _propTypes.default.oneOf(["truncate", "wrap"]),
    /**
       * If textWrap is set to `truncate`, you can pass a custom truncation configuration
       * that accepts any [EuiTextTruncate](/#/utilities/text-truncation) prop except for
       * `text` and `children`.
       *
       * Note: when searching, custom truncation props are ignored. The highlighted search
       * text will always take precedence.
       */
    truncationProps: _propTypes.default.any,
    /**
       * Optional custom tooltip content for the button
       */
    toolTipContent: _propTypes.default.node,
    /**
       * Optional props to pass to the underlying **[EuiToolTip](/#/display/tooltip)**
       */
    toolTipProps: _propTypes.default.any
  }).isRequired).isRequired,
  /**
       * Passes back the altered `options` array with selected options having `checked: 'on'`.
       * Also passes back the React click/keyboard event as a second argument,
       * and the option that triggered the onChange event as a third argument.
       */
  onChange: _propTypes.default.func,
  /**
       * Passes back the current active option whenever the user changes the currently
       * highlighted option via keyboard navigation or searching.
       */
  onActiveOptionChange: _propTypes.default.func,
  /**
       * Sets the single selection policy of
       * `false`: allows multiple selection
       * `true`: only allows one selection
       * `always`: can and must have only one selection
       * @default false
       */
  singleSelection: _propTypes.default.oneOfType([_propTypes.default.oneOf(["always"]), _propTypes.default.bool.isRequired]),
  /**
       * Allows marking options as `checked='off'` as well as `'on'`
       */
  allowExclusions: _propTypes.default.bool,
  /**
       * Show an loading indicator while you load and hook up your data
       */
  isLoading: _propTypes.default.bool,
  /**
       * Sets the max height in pixels or pass `full` to allow
       * the whole group to fill the height of its container and
       * allows the list grow as well
       */
  height: _propTypes.default.oneOfType([_propTypes.default.number.isRequired, _propTypes.default.oneOf(["full"])]),
  /**
       * See {@link EuiSelectableOptionsListPropsWithDefaults}
       */
  listProps: _propTypes.default.any,
  /**
       * Custom render function for each option.
       * Returns `(option, searchValue)`
       */
  renderOption: _propTypes.default.func,
  /**
       * Customize the loading message. Pass a string to simply change the text,
       * or a node to replace the whole content.
       */
  loadingMessage: _propTypes.default.oneOfType([_propTypes.default.element.isRequired, _propTypes.default.string.isRequired]),
  /**
       * Customize the no matches message. Pass a string to simply change the text,
       * or a node to replace the whole content.
       */
  noMatchesMessage: _propTypes.default.oneOfType([_propTypes.default.element.isRequired, _propTypes.default.string.isRequired]),
  /**
       * Customize the empty message. Pass a string to simply change the text,
       * or a node to replace the whole content.
       */
  emptyMessage: _propTypes.default.oneOfType([_propTypes.default.element.isRequired, _propTypes.default.string.isRequired]),
  /**
       * Add an error message.
       * The message will be shown when the value is not `null` or `undefined`.
       * Pass a string to simply change the text, or a node to replace the whole content.
       *
       * `errorMessage={hasErrors ? 'My error message' : null}`
       */
  errorMessage: _propTypes.default.oneOfType([_propTypes.default.element.isRequired, _propTypes.default.string.isRequired, _propTypes.default.oneOf([null])]),
  /**
       * Control whether or not options get filtered internally (i.e., whether filtering is
       * handled by EUI or by you, the consumer).
       * If set to `true`, all passed `options` will be displayed regardless of the user's
       * search input.
       *
       * Additionally allows passing a configuration object which enables turning off
       * search highlighting if needed.
       *
       * @default false
       */
  isPreFiltered: _propTypes.default.oneOfType([_propTypes.default.bool.isRequired, _propTypes.default.shape({
    highlightSearch: _propTypes.default.bool
  }).isRequired]),
  /**
       * Optional screen reader instructions to announce upon focus/interaction. This text is read out
       * after the `EuiSelectable` label and a brief pause, but before the default keyboard instructions for
       * interacting with a selectable are read out.
       */
  selectableScreenReaderText: _propTypes.default.string,
  /**
       * Optional custom option matcher function
       *
       * @example
       * const exactEqualityMatcher: EuiSelectableOptionMatcher = ({ option, searchValue }) => {
       *   return option.label === searchValue;
       * }
       */
  optionMatcher: _propTypes.default.func
};