"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.AutocompleteField = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _eui = require("@elastic/eui"); var _react = _interopRequireDefault(require("react")); var _common = require("@kbn/kibana-react-plugin/common"); var _typed_react = require("../../lib/typed_react"); var _suggestion_item = require("./suggestion_item"); /* * 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; you may not use this file except in compliance with the Elastic License * 2.0. */ class AutocompleteField extends _react.default.Component { constructor(...args) { super(...args); (0, _defineProperty2.default)(this, "state", { areSuggestionsVisible: false, isFocused: false, selectedIndex: null }); (0, _defineProperty2.default)(this, "inputElement", null); (0, _defineProperty2.default)(this, "handleChangeInputRef", element => { this.inputElement = element; }); (0, _defineProperty2.default)(this, "handleChange", evt => { this.changeValue(evt.currentTarget.value); }); (0, _defineProperty2.default)(this, "handleKeyDown", evt => { const { suggestions } = this.props; switch (evt.key) { case 'ArrowUp': evt.preventDefault(); if (suggestions.length > 0) { this.setState((0, _typed_react.composeStateUpdaters)(withSuggestionsVisible, withPreviousSuggestionSelected)); } break; case 'ArrowDown': evt.preventDefault(); if (suggestions.length > 0) { this.setState((0, _typed_react.composeStateUpdaters)(withSuggestionsVisible, withNextSuggestionSelected)); } else { this.updateSuggestions(); } break; case 'Enter': evt.preventDefault(); if (this.state.selectedIndex !== null) { this.applySelectedSuggestion(); } else { this.submit(); } break; case 'Escape': evt.preventDefault(); this.setState(withSuggestionsHidden); break; } }); (0, _defineProperty2.default)(this, "handleKeyUp", evt => { switch (evt.key) { case 'ArrowLeft': case 'ArrowRight': case 'Home': case 'End': this.updateSuggestions(); break; } }); (0, _defineProperty2.default)(this, "handleFocus", () => { this.setState((0, _typed_react.composeStateUpdaters)(withSuggestionsVisible, withFocused)); }); (0, _defineProperty2.default)(this, "handleBlur", () => { this.setState((0, _typed_react.composeStateUpdaters)(withSuggestionsHidden, withUnfocused)); }); (0, _defineProperty2.default)(this, "selectSuggestionAt", index => () => { this.setState(withSuggestionAtIndexSelected(index)); }); (0, _defineProperty2.default)(this, "applySelectedSuggestion", () => { if (this.state.selectedIndex !== null) { this.applySuggestionAt(this.state.selectedIndex)(); } }); (0, _defineProperty2.default)(this, "applySuggestionAt", index => () => { const { value, suggestions } = this.props; const selectedSuggestion = suggestions[index]; if (!selectedSuggestion) { return; } const newValue = value.substr(0, selectedSuggestion.start) + selectedSuggestion.text + value.substr(selectedSuggestion.end); this.setState(withSuggestionsHidden); this.changeValue(newValue); this.focusInputElement(); }); (0, _defineProperty2.default)(this, "changeValue", value => { const { onChange } = this.props; if (onChange) { onChange(value); } }); (0, _defineProperty2.default)(this, "focusInputElement", () => { if (this.inputElement) { this.inputElement.focus(); } }); (0, _defineProperty2.default)(this, "showSuggestions", () => { this.setState(withSuggestionsVisible); }); (0, _defineProperty2.default)(this, "submit", () => { const { isValid, onSubmit, value } = this.props; if (isValid && onSubmit) { onSubmit(value); } this.setState(withSuggestionsHidden); }); (0, _defineProperty2.default)(this, "updateSuggestions", () => { const inputCursorPosition = this.inputElement ? this.inputElement.selectionStart || 0 : 0; this.props.loadSuggestions(this.props.value, inputCursorPosition, 200); }); } render() { const { suggestions, isLoadingSuggestions, isValid, placeholder, value, disabled, 'aria-label': ariaLabel } = this.props; const { areSuggestionsVisible, selectedIndex } = this.state; return /*#__PURE__*/_react.default.createElement(_eui.EuiOutsideClickDetector, { onOutsideClick: this.handleBlur }, /*#__PURE__*/_react.default.createElement(AutocompleteContainer, null, /*#__PURE__*/_react.default.createElement(_eui.EuiFieldSearch, { fullWidth: true, disabled: disabled, inputRef: this.handleChangeInputRef, isLoading: isLoadingSuggestions, isInvalid: !isValid, onChange: this.handleChange, onFocus: this.handleFocus, onKeyDown: this.handleKeyDown, onKeyUp: this.handleKeyUp, onSearch: this.submit, placeholder: placeholder, value: value, "aria-label": ariaLabel }), areSuggestionsVisible && !isLoadingSuggestions && suggestions.length > 0 ? /*#__PURE__*/_react.default.createElement(SuggestionsPanel, null, suggestions.map((suggestion, suggestionIndex) => /*#__PURE__*/_react.default.createElement(_suggestion_item.SuggestionItem, { key: suggestion.text, suggestion: suggestion, isSelected: suggestionIndex === selectedIndex, onMouseEnter: this.selectSuggestionAt(suggestionIndex), onClick: this.applySuggestionAt(suggestionIndex) }))) : null)); } componentDidMount() { if (this.inputElement && this.props.autoFocus) { this.inputElement.focus(); } } componentDidUpdate(prevProps) { const hasNewValue = prevProps.value !== this.props.value; const hasNewSuggestions = prevProps.suggestions !== this.props.suggestions; if (hasNewValue) { this.updateSuggestions(); } if (hasNewValue && this.props.value === '') { this.submit(); } if (hasNewSuggestions && this.state.isFocused) { this.showSuggestions(); } } } exports.AutocompleteField = AutocompleteField; const withPreviousSuggestionSelected = (state, props) => ({ ...state, selectedIndex: props.suggestions.length === 0 ? null : state.selectedIndex !== null ? (state.selectedIndex + props.suggestions.length - 1) % props.suggestions.length : Math.max(props.suggestions.length - 1, 0) }); const withNextSuggestionSelected = (state, props) => ({ ...state, selectedIndex: props.suggestions.length === 0 ? null : state.selectedIndex !== null ? (state.selectedIndex + 1) % props.suggestions.length : 0 }); const withSuggestionAtIndexSelected = suggestionIndex => (state, props) => ({ ...state, selectedIndex: props.suggestions.length === 0 ? null : suggestionIndex >= 0 && suggestionIndex < props.suggestions.length ? suggestionIndex : 0 }); const withSuggestionsVisible = state => ({ ...state, areSuggestionsVisible: true }); const withSuggestionsHidden = state => ({ ...state, areSuggestionsVisible: false, selectedIndex: null }); const withFocused = state => ({ ...state, isFocused: true }); const withUnfocused = state => ({ ...state, isFocused: false }); const AutocompleteContainer = _common.euiStyled.div` position: relative; `; const SuggestionsPanel = (0, _common.euiStyled)(_eui.EuiPanel).attrs(() => ({ paddingSize: 'none', hasShadow: true }))` position: absolute; width: 100%; margin-top: 2px; overflow-x: hidden; overflow-y: scroll; z-index: ${props => props.theme.eui.euiZLevel1}; max-height: 322px; `;