UNPKG

@elastic/eui

Version:

Elastic UI Component Library

768 lines (755 loc) 36.3 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.EuiComboBox = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _classnames = _interopRequireDefault(require("classnames")); var _services = require("../../services"); var _global_styling = require("../../global_styling"); var _popover = require("../popover"); var _i18n = require("../i18n"); var _form = require("../form/form.styles"); var _matching_options = require("./matching_options"); var _combo_box_input = require("./combo_box_input/combo_box_input"); var _combo_box_options_list = require("./combo_box_options_list"); var _combo_box = require("./combo_box.styles"); var _react2 = require("@emotion/react"); var _excluded = ["data-test-subj", "async", "className", "compressed", "customOptionText", "fullWidth", "id", "inputRef", "isCaseSensitive", "isClearable", "isDisabled", "isInvalid", "isLoading", "noSuggestions", "onBlur", "onChange", "onCreateOption", "onSearchChange", "options", "placeholder", "renderOption", "rowHeight", "selectedOptions", "singleSelection", "prepend", "sortMatchesBy", "delimiter", "append", "autoFocus", "truncationProps", "inputPopoverProps", "optionMatcher", "aria-label", "aria-labelledby"]; 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 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; } function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!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. */ /** * Elements within EuiComboBox which would normally be tabbable (inputs, buttons) have been removed * from the tab order with tabindex={-1} so that we can control the keyboard navigation interface. */ /** * Because of how TypeScript's LibraryManagedAttributes is designed to handle defaultProps (https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html#support-for-defaultprops-in-jsx) * we can't directly export the above Props definitions, as the defaulted values are not made optional * as it isn't processed by LibraryManagedAttributes. To get around this, we: * - remove the props which have default values applied * - additionally re-define `options` and `selectedOptions` defaults, necessary as static members can't access generics and become never[] * - export (Props - Defaults) & Partial<Defaults> */ var initialSearchValue = ''; var EuiComboBox = exports.EuiComboBox = /*#__PURE__*/function (_Component) { function EuiComboBox() { var _this; (0, _classCallCheck2.default)(this, EuiComboBox); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _callSuper(this, EuiComboBox, [].concat(args)); (0, _defineProperty2.default)(_this, "state", { activeOptionIndex: -1, hasFocus: false, isListOpen: false, matchingOptions: (0, _matching_options.getMatchingOptions)({ options: _this.props.options, selectedOptions: _this.props.selectedOptions, searchValue: initialSearchValue, optionMatcher: _this.props.optionMatcher, isCaseSensitive: _this.props.isCaseSensitive, isPreFiltered: _this.props.async, showPrevSelected: Boolean(_this.props.singleSelection), sortMatchesBy: _this.props.sortMatchesBy }), searchValue: initialSearchValue }); (0, _defineProperty2.default)(_this, "rootId", (0, _services.htmlIdGenerator)()); // Refs (0, _defineProperty2.default)(_this, "comboBoxRefInstance", null); (0, _defineProperty2.default)(_this, "comboBoxRefCallback", function (ref) { _this.comboBoxRefInstance = ref; }); (0, _defineProperty2.default)(_this, "searchInputRefInstance", null); (0, _defineProperty2.default)(_this, "searchInputRefCallback", function (ref) { var _this$props$inputRef, _this$props; _this.searchInputRefInstance = ref; (_this$props$inputRef = (_this$props = _this.props).inputRef) === null || _this$props$inputRef === void 0 || _this$props$inputRef.call(_this$props, ref); }); (0, _defineProperty2.default)(_this, "listRefInstance", null); (0, _defineProperty2.default)(_this, "listRefCallback", function (ref) { _this.listRefInstance = ref; }); (0, _defineProperty2.default)(_this, "openList", function () { _this.setState({ isListOpen: true }); }); (0, _defineProperty2.default)(_this, "closeList", function () { _this.clearActiveOption(); _this.setState({ isListOpen: false }); }); (0, _defineProperty2.default)(_this, "incrementActiveOptionIndex", function (amount) { // If there are no options available, do nothing. if (!_this.state.matchingOptions.length) { return; } _this.setState(function (_ref) { var activeOptionIndex = _ref.activeOptionIndex, matchingOptions = _ref.matchingOptions; var nextActiveOptionIndex; if (activeOptionIndex < 0) { // 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 ? matchingOptions.length - 1 : 0; } else { nextActiveOptionIndex = activeOptionIndex + amount; if (nextActiveOptionIndex < 0) { nextActiveOptionIndex = matchingOptions.length - 1; } else if (nextActiveOptionIndex === matchingOptions.length) { nextActiveOptionIndex = 0; } } // Group titles are included in option list but are not selectable // Skip group title options var direction = amount > 0 ? 1 : -1; while (matchingOptions[nextActiveOptionIndex].isGroupLabelOption) { nextActiveOptionIndex = nextActiveOptionIndex + direction; if (nextActiveOptionIndex < 0) { nextActiveOptionIndex = matchingOptions.length - 1; } else if (nextActiveOptionIndex === matchingOptions.length) { nextActiveOptionIndex = 0; } } return { activeOptionIndex: nextActiveOptionIndex }; }); }); (0, _defineProperty2.default)(_this, "hasActiveOption", function () { return _this.state.activeOptionIndex > -1 && _this.state.activeOptionIndex < _this.state.matchingOptions.length; }); (0, _defineProperty2.default)(_this, "clearActiveOption", function () { _this.setState({ activeOptionIndex: -1 }); }); (0, _defineProperty2.default)(_this, "clearSearchValue", function () { _this.onSearchChange(''); }); (0, _defineProperty2.default)(_this, "addCustomOption", function (isContainerBlur, searchValue) { var _this$props2 = _this.props, isCaseSensitive = _this$props2.isCaseSensitive, onCreateOption = _this$props2.onCreateOption, options = _this$props2.options, selectedOptions = _this$props2.selectedOptions, singleSelection = _this$props2.singleSelection; var matchedOption = _this.doesSearchMatchOnlyOption(); if (matchedOption) { return _this.onAddOption(matchedOption, isContainerBlur); } if (!onCreateOption) { return; } // Don't bother trying to create an option if the user hasn't typed anything. if (!searchValue) { return; } // Don't create the value if it's already been selected. if ((0, _matching_options.getSelectedOptionForSearchValue)({ isCaseSensitive: isCaseSensitive, searchValue: searchValue, selectedOptions: selectedOptions })) { return; } // Add new custom pill if this is custom input, even if it partially matches an option. var isOptionCreated = onCreateOption(searchValue, (0, _matching_options.flattenOptionGroups)(options)); // Expect the consumer to be explicit in rejecting a custom option. if (isOptionCreated === false) { return; } _this.clearSearchValue(); if (Boolean(singleSelection)) { // Adding a custom option to a single select that does not appear in the list of options _this.closeList(); } }); (0, _defineProperty2.default)(_this, "doesSearchMatchOnlyOption", function () { var isCaseSensitive = _this.props.isCaseSensitive; var _this$state = _this.state, matchingOptions = _this$state.matchingOptions, searchValue = _this$state.searchValue; if (!matchingOptions.length) return; var isMatchWithGroup = matchingOptions[0].isGroupLabelOption; var isOnlyOption = matchingOptions.length === (isMatchWithGroup ? 2 : 1); if (!isOnlyOption) return; var matchedOption = matchingOptions[isMatchWithGroup ? 1 : 0]; var normalizedSearchSubject = (0, _matching_options.transformForCaseSensitivity)(matchedOption.label, isCaseSensitive); var normalizedSearchValue = (0, _matching_options.transformForCaseSensitivity)(searchValue, isCaseSensitive); if (normalizedSearchSubject === normalizedSearchValue) { return matchedOption; } }); (0, _defineProperty2.default)(_this, "areAllOptionsSelected", function () { var _this$props3 = _this.props, options = _this$props3.options, selectedOptions = _this$props3.selectedOptions, async = _this$props3.async, isCaseSensitive = _this$props3.isCaseSensitive; // Assume if this is async then there could be infinite options. if (async) { return false; } var flattenOptions = (0, _matching_options.flattenOptionGroups)(options).map(function (option) { return _objectSpread(_objectSpread({}, option), {}, { label: (0, _matching_options.transformForCaseSensitivity)(option.label.trim(), isCaseSensitive) }); }); var numberOfSelectedOptions = 0; selectedOptions.forEach(function (_ref2) { var label = _ref2.label; var trimmedLabel = (0, _matching_options.transformForCaseSensitivity)(label.trim(), isCaseSensitive); if (flattenOptions.findIndex(function (option) { return option.label === trimmedLabel; }) !== -1) numberOfSelectedOptions += 1; }); return flattenOptions.length === numberOfSelectedOptions; }); (0, _defineProperty2.default)(_this, "onComboBoxFocus", function (event) { var _this$props$onFocus, _this$props4; (_this$props$onFocus = (_this$props4 = _this.props).onFocus) === null || _this$props$onFocus === void 0 || _this$props$onFocus.call(_this$props4, event); _this.openList(); _this.setState({ hasFocus: true }); }); (0, _defineProperty2.default)(_this, "setCustomOptions", function (isContainerBlur) { var searchValue = _this.state.searchValue; var delimiter = _this.props.delimiter; if (delimiter) { searchValue.split(delimiter).forEach(function (option) { if (option.length > 0) _this.addCustomOption(isContainerBlur, option); }); } else { _this.addCustomOption(isContainerBlur, searchValue); } }); (0, _defineProperty2.default)(_this, "onContainerBlur", function (event) { // close the options list, unless the user clicked on an option var relatedTarget = event.relatedTarget; var focusedInOptionsList = relatedTarget && _this.listRefInstance && _this.listRefInstance.contains(relatedTarget); var focusedInInput = relatedTarget && _this.comboBoxRefInstance && _this.comboBoxRefInstance.contains(relatedTarget); if (!focusedInOptionsList && !focusedInInput) { var _this$props$onBlur, _this$props5; (_this$props$onBlur = (_this$props5 = _this.props).onBlur) === null || _this$props$onBlur === void 0 || _this$props$onBlur.call(_this$props5, event); _this.closeList(); _this.setState({ hasFocus: false }); // If the user tabs away or changes focus to another element, take whatever input they've // typed and convert it into a pill, to prevent the combo box from looking like a text input. if (!_this.hasActiveOption()) { _this.setCustomOptions(true); } } else if (focusedInOptionsList) { // https://github.com/elastic/eui/issues/5179 // need to restore focus to the input box when clicking non-interactive elements // firefox doesn't support calling .focus() during a blur event // https://bugzilla.mozilla.org/show_bug.cgi?id=53579 requestAnimationFrame(function () { var _this$searchInputRefI; (_this$searchInputRefI = _this.searchInputRefInstance) === null || _this$searchInputRefI === void 0 || _this$searchInputRefI.focus(); }); } }); (0, _defineProperty2.default)(_this, "onKeyDown", function (event) { var _this$props$onKeyDown, _this$props6; if (_this.props.isDisabled) return; event.persist(); // TODO: Remove once React 16 support is dropped switch (event.key) { case _services.keys.ARROW_UP: event.preventDefault(); event.stopPropagation(); if (_this.state.isListOpen) { _this.incrementActiveOptionIndex(-1); } else { _this.openList(); } break; case _services.keys.ARROW_DOWN: event.preventDefault(); event.stopPropagation(); if (_this.state.isListOpen) { _this.incrementActiveOptionIndex(1); } else { _this.openList(); } break; case _services.keys.ESCAPE: if (_this.state.isListOpen) { event.preventDefault(); event.stopPropagation(); _this.closeList(); } break; case _services.keys.ENTER: event.preventDefault(); event.stopPropagation(); if (_this.hasActiveOption()) { _this.onAddOption(_this.state.matchingOptions[_this.state.activeOptionIndex]); } else { _this.setCustomOptions(false); } break; case _services.keys.TAB: // Disallow tabbing when the user is navigating the options. if (_this.hasActiveOption() && _this.state.isListOpen) { event.preventDefault(); event.stopPropagation(); } break; default: (_this$props$onKeyDown = (_this$props6 = _this.props).onKeyDown) === null || _this$props$onKeyDown === void 0 || _this$props$onKeyDown.call(_this$props6, event); } }); (0, _defineProperty2.default)(_this, "onOptionEnterKey", function (option) { _this.onAddOption(option); }); (0, _defineProperty2.default)(_this, "onOptionClick", function (option) { _this.onAddOption(option); }); (0, _defineProperty2.default)(_this, "onAddOption", function (addedOption, isContainerBlur) { if (addedOption.disabled) { return; } var _this$props7 = _this.props, onChange = _this$props7.onChange, selectedOptions = _this$props7.selectedOptions, singleSelectionProp = _this$props7.singleSelection; var singleSelection = Boolean(singleSelectionProp); var changeOptions = singleSelection ? [addedOption] : selectedOptions.concat(addedOption); onChange === null || onChange === void 0 || onChange(changeOptions); _this.clearSearchValue(); _this.clearActiveOption(); if (!isContainerBlur) { var _this$searchInputRefI2; (_this$searchInputRefI2 = _this.searchInputRefInstance) === null || _this$searchInputRefI2 === void 0 || _this$searchInputRefI2.focus(); } if (singleSelection) { requestAnimationFrame(function () { return _this.closeList(); }); } else { _this.setState({ activeOptionIndex: _this.state.matchingOptions.indexOf(addedOption) }); } }); (0, _defineProperty2.default)(_this, "onRemoveOption", function (removedOption) { var _this$props8 = _this.props, onChange = _this$props8.onChange, selectedOptions = _this$props8.selectedOptions; onChange === null || onChange === void 0 || onChange(selectedOptions.filter(function (option) { return option !== removedOption; })); _this.clearActiveOption(); }); (0, _defineProperty2.default)(_this, "clearSelectedOptions", function () { var _this$props$onChange, _this$props9, _this$searchInputRefI3; (_this$props$onChange = (_this$props9 = _this.props).onChange) === null || _this$props$onChange === void 0 || _this$props$onChange.call(_this$props9, []); // Clicking the clear button will also cause it to disappear. This would result in focus // shifting unexpectedly to the body element so we set it to the input which is more reasonable, (_this$searchInputRefI3 = _this.searchInputRefInstance) === null || _this$searchInputRefI3 === void 0 || _this$searchInputRefI3.focus(); if (!_this.state.isListOpen) { _this.openList(); } }); (0, _defineProperty2.default)(_this, "onComboBoxClick", function () { var _this$searchInputRefI4; // When the user clicks anywhere on the box, enter the interaction state. (_this$searchInputRefI4 = _this.searchInputRefInstance) === null || _this$searchInputRefI4 === void 0 || _this$searchInputRefI4.focus(); // If the user does this from a state in which an option has focus, then we need to reset it or clear it. if (Boolean(_this.props.singleSelection) && _this.props.selectedOptions.length === 1) { var selectedOptionIndex = _this.state.matchingOptions.findIndex(function (option) { return option.label === _this.props.selectedOptions[0].label && option.key === _this.props.selectedOptions[0].key; }); _this.setState({ activeOptionIndex: selectedOptionIndex }); } else { _this.clearActiveOption(); } }); (0, _defineProperty2.default)(_this, "onOpenListClick", function () { var _this$searchInputRefI5; (_this$searchInputRefI5 = _this.searchInputRefInstance) === null || _this$searchInputRefI5 === void 0 || _this$searchInputRefI5.focus(); if (!_this.state.isListOpen) { _this.openList(); } }); (0, _defineProperty2.default)(_this, "onOptionListScroll", function () { var _this$searchInputRefI6; (_this$searchInputRefI6 = _this.searchInputRefInstance) === null || _this$searchInputRefI6 === void 0 || _this$searchInputRefI6.focus(); }); (0, _defineProperty2.default)(_this, "onSearchChange", function (searchValue) { var _this$props10 = _this.props, onSearchChange = _this$props10.onSearchChange, delimiter = _this$props10.delimiter; _this.setState({ searchValue: searchValue }, function () { if (searchValue && _this.state.isListOpen === false) { _this.openList(); } if (onSearchChange) { var hasMatchingOptions = _this.state.matchingOptions.length > 0; onSearchChange(searchValue, hasMatchingOptions); } }); if (delimiter && searchValue.endsWith(delimiter)) { _this.setCustomOptions(false); } }); return _this; } (0, _inherits2.default)(EuiComboBox, _Component); return (0, _createClass2.default)(EuiComboBox, [{ key: "render", value: function render() { var _this2 = this; var _this$props11 = this.props, dataTestSubj = _this$props11['data-test-subj'], async = _this$props11.async, className = _this$props11.className, compressed = _this$props11.compressed, customOptionText = _this$props11.customOptionText, fullWidth = _this$props11.fullWidth, id = _this$props11.id, inputRef = _this$props11.inputRef, isCaseSensitive = _this$props11.isCaseSensitive, isClearable = _this$props11.isClearable, isDisabled = _this$props11.isDisabled, isInvalid = _this$props11.isInvalid, isLoading = _this$props11.isLoading, noSuggestions = _this$props11.noSuggestions, onBlur = _this$props11.onBlur, onChange = _this$props11.onChange, onCreateOption = _this$props11.onCreateOption, onSearchChange = _this$props11.onSearchChange, options = _this$props11.options, placeholder = _this$props11.placeholder, renderOption = _this$props11.renderOption, rowHeight = _this$props11.rowHeight, selectedOptions = _this$props11.selectedOptions, singleSelection = _this$props11.singleSelection, prepend = _this$props11.prepend, sortMatchesBy = _this$props11.sortMatchesBy, delimiter = _this$props11.delimiter, append = _this$props11.append, autoFocus = _this$props11.autoFocus, truncationProps = _this$props11.truncationProps, inputPopoverProps = _this$props11.inputPopoverProps, optionMatcher = _this$props11.optionMatcher, ariaLabel = _this$props11['aria-label'], ariaLabelledby = _this$props11['aria-labelledby'], rest = (0, _objectWithoutProperties2.default)(_this$props11, _excluded); var _this$state2 = this.state, activeOptionIndex = _this$state2.activeOptionIndex, hasFocus = _this$state2.hasFocus, isListOpen = _this$state2.isListOpen, searchValue = _this$state2.searchValue, matchingOptions = _this$state2.matchingOptions; // Make sure we have a valid ID if users don't pass one as a prop var inputId = id !== null && id !== void 0 ? id : this.rootId('_eui-combobox-id'); // Visually indicate the combobox is in an invalid state if it has lost focus but there is text entered in the input. // When custom options are disabled and the user leaves the combo box after entering text that does not match any // options, this tells the user that they've entered invalid input. var markAsInvalid = !!(isInvalid || (hasFocus === false || isListOpen === false) && searchValue); var classes = (0, _classnames.default)('euiComboBox', className, { 'euiComboBox-isDisabled': isDisabled, 'euiComboBox-isInvalid': markAsInvalid, 'euiComboBox-isOpen': isListOpen }); var value = selectedOptions.map(function (selectedOption) { return selectedOption.label; }).join(', '); var optionsList; if (!noSuggestions && isListOpen) { var optionsListDataTestSubj = dataTestSubj ? "".concat(dataTestSubj, "-optionsList") : undefined; optionsList = (0, _react2.jsx)(_i18n.EuiI18n, { token: "euiComboBox.listboxAriaLabel", default: "Choose from the following options" }, function (listboxAriaLabel) { return (0, _react2.jsx)(_combo_box_options_list.EuiComboBoxOptionsList, { activeOptionIndex: _this2.state.activeOptionIndex, areAllOptionsSelected: _this2.areAllOptionsSelected(), customOptionText: customOptionText, "data-test-subj": optionsListDataTestSubj, fullWidth: fullWidth, isCaseSensitive: isCaseSensitive, isLoading: isLoading, listRef: _this2.listRefCallback, matchingOptions: matchingOptions, onCloseList: _this2.closeList, onCreateOption: onCreateOption, onOptionClick: _this2.onOptionClick, onOptionEnterKey: _this2.onOptionEnterKey, onScroll: _this2.onOptionListScroll, options: options, singleSelection: singleSelection, renderOption: renderOption, rootId: _this2.rootId, rowHeight: rowHeight, scrollToIndex: activeOptionIndex, searchValue: searchValue, selectedOptions: selectedOptions, delimiter: delimiter, getSelectedOptionForSearchValue: _matching_options.getSelectedOptionForSearchValue, listboxAriaLabel: listboxAriaLabel, truncationProps: truncationProps }); }); } return ( /** * EuiComboBox follows the WAI-ARIA 1.2 spec for editable comboboxes * with list autocomplete. This pattern is an improvement on the user * experience for screen readers over the WAI-ARIA 1.1 pattern. * * https://www.w3.org/TR/wai-aria-practices-1.2/examples/combobox/combobox-autocomplete-list.html */ (0, _react2.jsx)(_services.RenderWithEuiTheme, null, function (euiTheme) { var cssStyles = [_combo_box.euiComboBoxStyles.euiComboBox, fullWidth ? _combo_box.euiComboBoxStyles.fullWidth : (0, _global_styling.logicalStyle)('max-width', (0, _form.euiFormMaxWidth)(euiTheme))]; return (0, _react2.jsx)("div", (0, _extends2.default)({ css: cssStyles }, rest, { className: classes, "data-test-subj": dataTestSubj, onKeyDown: _this2.onKeyDown, onBlur: _this2.onContainerBlur, ref: _this2.comboBoxRefCallback }), (0, _react2.jsx)(_popover.EuiInputPopover, (0, _extends2.default)({ fullWidth: fullWidth, panelPaddingSize: "none", disableFocusTrap: true, closeOnScroll: true }, inputPopoverProps, { isOpen: isListOpen, closePopover: _this2.closeList, input: (0, _react2.jsx)(_combo_box_input.EuiComboBoxInput, { compressed: compressed, focusedOptionId: _this2.hasActiveOption() ? _this2.rootId("_option-".concat(_this2.state.activeOptionIndex)) : undefined, fullWidth: fullWidth, hasSelectedOptions: selectedOptions.length > 0, id: inputId, inputRef: _this2.searchInputRefCallback, isDisabled: isDisabled, isListOpen: isListOpen, noIcon: !!noSuggestions, onChange: _this2.onSearchChange, onClear: isClearable && !isDisabled ? _this2.clearSelectedOptions : undefined, onClick: _this2.onComboBoxClick, onCloseListClick: _this2.closeList, onFocus: _this2.onComboBoxFocus, onOpenListClick: _this2.onOpenListClick, onRemoveOption: _this2.onRemoveOption, placeholder: placeholder, rootId: _this2.rootId, searchValue: searchValue, selectedOptions: selectedOptions, singleSelection: singleSelection, value: value, append: singleSelection ? append : undefined, prepend: singleSelection ? prepend : undefined, isLoading: isLoading, isInvalid: markAsInvalid, autoFocus: autoFocus, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby }) }), optionsList)); }) ); } }], [{ key: "getDerivedStateFromProps", value: function getDerivedStateFromProps(nextProps, prevState) { var async = nextProps.async, isCaseSensitive = nextProps.isCaseSensitive, options = nextProps.options, selectedOptions = nextProps.selectedOptions, singleSelection = nextProps.singleSelection, sortMatchesBy = nextProps.sortMatchesBy, optionMatcher = nextProps.optionMatcher; var activeOptionIndex = prevState.activeOptionIndex, searchValue = prevState.searchValue; // Calculate and cache the options which match the searchValue, because we use this information // in multiple places and it would be expensive to calculate repeatedly. var matchingOptions = (0, _matching_options.getMatchingOptions)({ options: options, selectedOptions: selectedOptions, searchValue: searchValue, isCaseSensitive: isCaseSensitive, isPreFiltered: async, showPrevSelected: Boolean(singleSelection), sortMatchesBy: sortMatchesBy, optionMatcher: optionMatcher }); var stateUpdate = { matchingOptions: matchingOptions }; if (activeOptionIndex >= matchingOptions.length) { stateUpdate.activeOptionIndex = -1; } return stateUpdate; } }]); }(_react.Component); (0, _defineProperty2.default)(EuiComboBox, "defaultProps", { async: false, compressed: false, fullWidth: false, isClearable: true, options: [], selectedOptions: [], singleSelection: false, prepend: undefined, append: undefined, sortMatchesBy: 'none', optionMatcher: (0, _matching_options.createPartialStringEqualityOptionMatcher)() }); EuiComboBox.propTypes = { "data-test-subj": _propTypes.default.string, /** * Updates the list of options asynchronously */ async: _propTypes.default.bool.isRequired, className: _propTypes.default.string, /** * When `true` creates a shorter height input */ compressed: _propTypes.default.bool.isRequired, /** * When `true` expands to the entire width available */ fullWidth: _propTypes.default.bool.isRequired, id: _propTypes.default.string, inputRef: _propTypes.default.any, /** * Shows a button that quickly clears any input */ isClearable: _propTypes.default.bool.isRequired, /** * Disables the input */ isDisabled: _propTypes.default.bool, isInvalid: _propTypes.default.bool, /** * Swaps the dropdown options for a loading spinner */ isLoading: _propTypes.default.bool, /** * Doesn't show the suggestions list/dropdown */ noSuggestions: _propTypes.default.bool, onBlur: _propTypes.default.any, /** * Called every time the query in the combo box is parsed */ onChange: _propTypes.default.func, onFocus: _propTypes.default.any, onKeyDown: _propTypes.default.any, /** * Called every time the text query in the search box is parsed */ onSearchChange: _propTypes.default.func, /** * Sets the placeholder of the input */ placeholder: _propTypes.default.string, /** * Every option must be the same height and must be explicitly set if using a custom render */ rowHeight: _propTypes.default.number, /** * When `true` only allows the user to select a single option. Set to `{ asPlainText: true }` to not render input selection as pills */ singleSelection: _propTypes.default.oneOfType([_propTypes.default.bool.isRequired, _propTypes.default.shape({ asPlainText: _propTypes.default.bool }).isRequired]).isRequired, /** * Display matching options by: * `startsWith`: moves items that start with search value to top of the list; * `none`: don't change the sort order of initial object */ sortMatchesBy: _propTypes.default.oneOf(["none", "startsWith"]).isRequired, /** * Whether to match options with case sensitivity. */ isCaseSensitive: _propTypes.default.bool, /** * Optional custom option matcher function * * @example * const exactEqualityMatcher: EuiComboBoxOptionMatcher = ({ option, searchValue }) => { * return option.label === searchValue; * } */ optionMatcher: _propTypes.default.func, /** * Creates an input group with element(s) coming before input. It won't show if `singleSelection` is set to `false`. * `string` | `ReactElement` or an array of these */ prepend: _propTypes.default.any, /** * Creates an input group with element(s) coming after input. It won't show if `singleSelection` is set to `false`. * `string` | `ReactElement` or an array of these */ append: _propTypes.default.any, /** * A special character to use as a value separator. Typically a comma `,` */ delimiter: _propTypes.default.string, /** * Specifies that the input should have focus when the component loads */ autoFocus: _propTypes.default.bool, /** * Required when rendering without a visible label from [EuiFormRow](/#/forms/form-layouts). */ "aria-label": _propTypes.default.string, /** * Reference ID of a text element containing the visible label for the combo box when not * supplied by `aria-label` or from [EuiFormRow](/#/forms/form-layouts). */ "aria-labelledby": _propTypes.default.string, /** * By default, EuiComboBox will truncate option labels at the end of * the string. You can use pass in 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, /** * Allows customizing the underlying EuiInputPopover component * (except for props that control state). */ inputPopoverProps: _propTypes.default.any, css: _propTypes.default.any };