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 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], -1 === t.indexOf(o) && {}.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 (-1 !== e.indexOf(n)) 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 _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 _createSuper(t) { var r = _isNativeReflectConstruct(); return function () { var e, o = _getPrototypeOf(t); if (r) { var s = _getPrototypeOf(this).constructor; e = Reflect.construct(o, arguments, s); } else e = o.apply(this, arguments); return _possibleConstructorReturn(this, 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 _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); }
/*
 * SPDX-License-Identifier: Apache-2.0
 *
 * The OpenSearch Contributors require contributions made to
 * this file be licensed under the Apache-2.0 license or a
 * compatible open source license.
 *
 * Modifications Copyright OpenSearch Contributors. See
 * GitHub history for details.
 */

/*
 * Licensed to Elasticsearch B.V. under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch B.V. licenses this file to you under
 * the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import React, { Component, createRef } from 'react';
import PropTypes from "prop-types";
import classNames from 'classnames';
import { EuiSelectableSearch } from './selectable_search';
import { EuiSelectableMessage } from './selectable_message';
import { EuiSelectableList } from './selectable_list';
import { EuiLoadingSpinner } from '../loading';
import { EuiSpacer } from '../spacer';
import { getMatchingOptions } from './matching_options';
import { keys, htmlIdGenerator } from '../../services';
import { EuiI18n } from '../i18n';

// `searchProps` can only be specified when `searchable` is true

export var EuiSelectable = /*#__PURE__*/function (_Component) {
  _inherits(EuiSelectable, _Component);
  var _super = _createSuper(EuiSelectable);
  function EuiSelectable(props) {
    var _this;
    _classCallCheck(this, EuiSelectable);
    _this = _super.call(this, props);
    _defineProperty(_assertThisInitialized(_this), "containerRef", /*#__PURE__*/createRef());
    _defineProperty(_assertThisInitialized(_this), "optionsListRef", /*#__PURE__*/createRef());
    _defineProperty(_assertThisInitialized(_this), "rootId", htmlIdGenerator());
    _defineProperty(_assertThisInitialized(_this), "hasActiveOption", function () {
      return _this.state.activeOptionIndex != null;
    });
    _defineProperty(_assertThisInitialized(_this), "onFocus", function () {
      if (!_this.state.visibleOptions.length || _this.state.activeOptionIndex) {
        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(_assertThisInitialized(_this), "onKeyDown", function (event) {
      var optionsList = _this.optionsListRef.current;
      switch (event.key) {
        case keys.ARROW_UP:
          event.preventDefault();
          event.stopPropagation();
          _this.incrementActiveOptionIndex(-1);
          break;
        case keys.ARROW_DOWN:
          event.preventDefault();
          event.stopPropagation();
          _this.incrementActiveOptionIndex(1);
          break;
        case keys.ENTER:
          event.preventDefault();
          event.stopPropagation();
          if (_this.state.activeOptionIndex != null && optionsList) {
            optionsList.onAddOrRemoveOption(_this.state.visibleOptions[_this.state.activeOptionIndex]);
          }
          break;
        default:
          _this.setState({
            activeOptionIndex: undefined
          }, _this.onFocus);
          break;
      }
    });
    _defineProperty(_assertThisInitialized(_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(_assertThisInitialized(_this), "onSearchChange", function (visibleOptions, searchValue) {
      _this.setState({
        visibleOptions: visibleOptions,
        searchValue: searchValue,
        activeOptionIndex: undefined
      }, function () {
        if (_this.state.isFocused) {
          _this.onFocus();
        }
      });
      if (_this.props.searchProps && _this.props.searchProps.onSearch) {
        _this.props.searchProps.onSearch(searchValue);
      }
    });
    _defineProperty(_assertThisInitialized(_this), "onContainerBlur", function (e) {
      // Ignore blur events when moving from search to option to avoid activeOptionIndex conflicts
      if (_this.containerRef.current.contains(e.relatedTarget)) return;
      _this.setState({
        activeOptionIndex: undefined,
        isFocused: false
      });
    });
    _defineProperty(_assertThisInitialized(_this), "onOptionClick", function (options) {
      var _this$props = _this.props,
        isPreFiltered = _this$props.isPreFiltered,
        onChange = _this$props.onChange,
        searchProps = _this$props.searchProps;
      var searchValue = _this.state.searchValue;
      var visibleOptions = getMatchingOptions(options, searchValue, isPreFiltered);
      _this.setState({
        visibleOptions: visibleOptions
      });
      if (onChange) {
        onChange(options);
      }
      if (searchProps && searchProps.onChange) {
        searchProps.onChange(visibleOptions, searchValue);
      }
    });
    _defineProperty(_assertThisInitialized(_this), "scrollToItem", function (index, align) {
      var _this$optionsListRef$, _this$optionsListRef$2;
      (_this$optionsListRef$ = _this.optionsListRef.current) === null || _this$optionsListRef$ === void 0 ? void 0 : (_this$optionsListRef$2 = _this$optionsListRef$.listRef) === null || _this$optionsListRef$2 === void 0 ? void 0 : _this$optionsListRef$2.scrollToItem(index, align);
    });
    var _options = props.options,
      singleSelection = props.singleSelection,
      _isPreFiltered = props.isPreFiltered;
    var initialSearchValue = '';
    var _visibleOptions = getMatchingOptions(_options, initialSearchValue, _isPreFiltered);

    // 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;
  }
  _createClass(EuiSelectable, [{
    key: "render",
    value: function render() {
      var _this2 = this;
      var _this$props2 = this.props,
        id = _this$props2.id,
        children = _this$props2.children,
        className = _this$props2.className,
        options = _this$props2.options,
        onChange = _this$props2.onChange,
        searchable = _this$props2.searchable,
        searchProps = _this$props2.searchProps,
        singleSelection = _this$props2.singleSelection,
        isLoading = _this$props2.isLoading,
        listProps = _this$props2.listProps,
        renderOption = _this$props2.renderOption,
        height = _this$props2.height,
        allowExclusions = _this$props2.allowExclusions,
        ariaLabel = _this$props2['aria-label'],
        ariaDescribedby = _this$props2['aria-describedby'],
        loadingMessage = _this$props2.loadingMessage,
        noMatchesMessage = _this$props2.noMatchesMessage,
        emptyMessage = _this$props2.emptyMessage,
        isPreFiltered = _this$props2.isPreFiltered,
        rest = _objectWithoutProperties(_this$props2, ["id", "children", "className", "options", "onChange", "searchable", "searchProps", "singleSelection", "isLoading", "listProps", "renderOption", "height", "allowExclusions", "aria-label", "aria-describedby", "loadingMessage", "noMatchesMessage", "emptyMessage", "isPreFiltered"]);
      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,
        onSearch = _ref2.onSearch,
        cleanedSearchProps = _objectWithoutProperties(_ref2, ["aria-label", "aria-describedby", "onChange", "onSearch"]);
      var _ref3 = listProps || unknownAccessibleName,
        listAriaLabel = _ref3['aria-label'],
        listAriaDescribedby = _ref3['aria-describedby'],
        cleanedListProps = _objectWithoutProperties(_ref3, ["aria-label", "aria-describedby"]);
      var classes = classNames('euiSelectable', {
        'euiSelectable-fullHeight': height === 'full'
      }, className);

      /** Create Id's */
      var messageContentId = this.rootId('messageContent');
      var listId = this.rootId('listbox');
      var makeOptionId = function makeOptionId(index) {
        if (typeof index === 'undefined') {
          return '';
        }
        return "".concat(listId, "_option-").concat(index);
      };

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

      /**
       * 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, messageContentId);
      var searchHasAccessibleName = Boolean(Object.keys(searchAccessibleName).length);
      var search = searchable ? /*#__PURE__*/React.createElement(EuiI18n, {
        token: "euiSelectable.placeholderName",
        default: "Filter options"
      }, function (placeholderName) {
        return /*#__PURE__*/React.createElement(EuiSelectableSearch, _extends({
          key: "listSearch",
          options: options,
          onChange: _this2.onSearchChange,
          listId: _this2.optionsListRef.current ? listId : undefined // Only pass the listId if it exists on the page
          ,
          "aria-activedescendant": makeOptionId(activeOptionIndex) // the current faux-focused option
          ,
          placeholder: placeholderName,
          isPreFiltered: isPreFiltered !== null && isPreFiltered !== void 0 ? isPreFiltered : false
        }, searchHasAccessibleName ? searchAccessibleName : {
          'aria-label': placeholderName
        }, cleanedSearchProps));
      }) : undefined;
      var listAccessibleName = getAccessibleName(listProps);
      var listHasAccessibleName = Boolean(Object.keys(listAccessibleName).length);
      var list = messageContent ? /*#__PURE__*/React.createElement(EuiSelectableMessage, {
        id: messageContentId,
        bordered: listProps && listProps.bordered
      }, messageContent) : /*#__PURE__*/React.createElement(EuiI18n, {
        token: "euiSelectable.placeholderName",
        default: "Filter options"
      }, function (placeholderName) {
        return /*#__PURE__*/React.createElement(EuiSelectableList, _extends({
          key: "list",
          options: options,
          visibleOptions: visibleOptions,
          searchValue: searchValue,
          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: makeOptionId,
          listId: listId
        }, listHasAccessibleName ? listAccessibleName : searchable && {
          'aria-label': placeholderName
        }, cleanedListProps));
      });
      return /*#__PURE__*/React.createElement("div", _extends({
        ref: this.containerRef,
        className: classes,
        onKeyDown: this.onKeyDown,
        onBlur: this.onContainerBlur,
        onFocus: this.onFocus
      }, rest), children && children(list, search));
    }
  }], [{
    key: "getDerivedStateFromProps",
    value: function getDerivedStateFromProps(nextProps, prevState) {
      var options = nextProps.options,
        isPreFiltered = nextProps.isPreFiltered;
      var activeOptionIndex = prevState.activeOptionIndex,
        searchValue = prevState.searchValue;
      var matchingOptions = getMatchingOptions(options, searchValue, isPreFiltered);
      var stateUpdate = {
        visibleOptions: matchingOptions,
        activeOptionIndex: activeOptionIndex
      };
      if (activeOptionIndex != null && activeOptionIndex >= matchingOptions.length) {
        stateUpdate.activeOptionIndex = -1;
      }
      return stateUpdate;
    }
  }]);
  return EuiSelectable;
}(Component);
_defineProperty(EuiSelectable, "defaultProps", {
  options: [],
  singleSelection: false,
  searchable: false,
  isPreFiltered: false
});
EuiSelectable.propTypes = {
  className: PropTypes.string,
  "aria-label": PropTypes.string,
  "data-test-subj": PropTypes.string,
  /**
       * Hooks up a search box to filter the list (boolean)
       */
  searchable: PropTypes.oneOfType([PropTypes.oneOf([false]).isRequired, PropTypes.oneOf([true]).isRequired]).isRequired,
  /**
       * Passes props down to the `EuiFieldSearch`
       */
  searchProps: PropTypes.any,
  /**
       * Function that takes the `list` node and then
       * the `search` node (if `searchable` is applied)
       */
  children: PropTypes.func,
  /**
       * Array of EuiSelectableOption objects. See #EuiSelectableOptionProps
       */
  options: PropTypes.arrayOf(PropTypes.shape({
    /**
       * Optional `boolean`.
       * Set to `true` to indicate object is just a grouping label, not a selectable item
       */
    isGroupLabel: PropTypes.oneOfType([PropTypes.oneOf([true]).isRequired, PropTypes.oneOf([false])]),
    className: PropTypes.string,
    "aria-label": PropTypes.string,
    "data-test-subj": PropTypes.string,
    /**
       * Visible label of option.
       * Must be unique across items if `key` is not supplied
       */
    label: PropTypes.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.string,
    /**
       * Must be unique across items.
       * Will be used to match options instead of `label`
       */
    key: PropTypes.string,
    /**
       * Leave `undefined` to indicate not selected,
       * 'on' to indicate inclusion and
       * 'off' to indicate exclusion
       */
    checked: PropTypes.oneOf(["on", "off", undefined]),
    disabled: PropTypes.bool,
    /**
       * Node to add between the selection icon and the label
       */
    prepend: PropTypes.node,
    /**
       * Node to add to the far right of the item
       */
    append: PropTypes.node,
    ref: PropTypes.func
  }).isRequired).isRequired,
  /**
       * Passes back the altered `options` array with selected options as
       */
  onChange: PropTypes.func,
  /**
       * Sets the single selection policy of
       * `false`: allows multiple selection
       * `true`: only allows one selection
       * `always`: can and must have only one selection
       */
  singleSelection: PropTypes.oneOfType([PropTypes.oneOf(["always"]), PropTypes.bool.isRequired]),
  /**
       * Allows marking options as `checked='off'` as well as `'on'`
       */
  allowExclusions: PropTypes.bool,
  /**
       * Show an loading indicator while you load and hook up your data
       */
  isLoading: PropTypes.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.oneOfType([PropTypes.number.isRequired, PropTypes.oneOf(["full"])]),
  /**
       * See #EuiSelectableOptionsList
       */
  listProps: PropTypes.any,
  /**
       * Custom render function for each option.
       * Returns `(option, searchValue)`
       */
  renderOption: PropTypes.func,
  /**
       * Customize the loading message. Pass a string to simply change the text,
       * or a node to replace the whole content.
       */
  loadingMessage: PropTypes.oneOfType([PropTypes.element.isRequired, PropTypes.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.oneOfType([PropTypes.element.isRequired, PropTypes.string.isRequired]),
  /**
       * Customize the empty message. Pass a string to simply change the text,
       * or a node to replace the whole content.
       */
  emptyMessage: PropTypes.oneOfType([PropTypes.element.isRequired, PropTypes.string.isRequired]),
  /**
       * Control whether or not options get filtered internally or if consumer will filter
       * Default: false
       */
  isPreFiltered: PropTypes.bool
};