@itwin/core-react
Version:
A react component library of iTwin.js UI general purpose components
171 lines • 8.47 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
* @module AutoSuggest
*/
import "./AutoSuggest.scss";
import * as React from "react";
import { Logger } from "@itwin/core-bentley";
import { Input } from "@itwin/itwinui-react";
import ReactAutosuggest from "react-autosuggest";
import { Key } from "ts-key-enum";
import { UiCore } from "../UiCore.js";
/** Auto Suggest React component. Uses the react-autosuggest component internally.
* @public
* @deprecated in 4.16.0. Use {@link https://itwinui.bentley.com/ iTwinUI components} instead.
*/
export class AutoSuggest extends React.PureComponent {
constructor(props) {
super(props);
this._isMounted = false;
this._onChange = (e) => {
let newValue = "";
if (e.target.tagName === "LI" && e.target.textContent)
newValue = e.target.textContent;
else if (e.target.value)
newValue = e.target.value;
this.setState({
inputValue: newValue,
});
};
this._onFocus = (e) => {
if (this.props.onInputFocus)
this.props.onInputFocus(e);
};
/** Autosuggest will call this function every time you need to update suggestions. */
this._onSuggestionsFetchRequested = async (request) => {
const value = request.value;
const suggestions = await this._getSuggestions(value);
if (this._isMounted)
this.setState({ suggestions });
};
/** Autosuggest will call this function every time you need to clear suggestions. */
this._onSuggestionsClearRequested = () => {
this.setState({ suggestions: [] });
this.props.onSuggestionsClearRequested &&
this.props.onSuggestionsClearRequested();
};
this._onSuggestionSelected = (_event, data) => {
this.props.onSuggestionSelected(data.suggestion);
};
/** Teach Autosuggest how to calculate suggestions for any given input value. */
this._getSuggestions = async (value) => {
if (typeof this.props.options === "function")
return Promise.resolve(this.props.options(value));
if (this.props.getSuggestions)
return this.props.getSuggestions(value);
if (this.props.options === undefined) {
Logger.logError(UiCore.loggerCategory("AutoSuggest"), `props.options or props.getSuggestions should be provided`);
return Promise.resolve([]);
}
const inputValue = value.trim().toLowerCase();
const inputLength = inputValue.length;
return Promise.resolve(inputLength === 0
? []
: this.props.options.filter((data) => {
return (data.label.toLowerCase().includes(inputValue) ||
data.value.toLowerCase().includes(inputValue));
}));
};
/** When suggestion is clicked, Autosuggest needs to populate the input based on the clicked suggestion. */
this._getSuggestionValue = (suggestion) => suggestion.label;
/** Render each suggestion. */
this._renderSuggestion = (suggestion) => (React.createElement("span", null, suggestion.label));
this._handleKeyDown = (e) => {
switch (e.key) {
case Key.Enter.valueOf():
if (this.props.onPressEnter)
this.props.onPressEnter(e);
break;
case Key.Escape.valueOf():
if (this.props.onPressEscape)
this.props.onPressEscape(e);
break;
case Key.Tab.valueOf():
if (this.props.onPressTab)
this.props.onPressTab(e);
break;
}
};
this._theme = {
container: "uicore-autosuggest__container",
containerOpen: "uicore-autosuggest__container--open",
input: "uicore-autosuggest__input",
inputOpen: "uicore-autosuggest__input--open",
inputFocused: "uicore-autosuggest__input--focused",
suggestionsContainer: "uicore-autosuggest__suggestions-container",
suggestionsContainerOpen: "uicore-autosuggest__suggestions-container--open",
suggestionsList: "uicore-autosuggest__suggestions-list",
suggestion: "uicore-autosuggest__suggestion",
suggestionFirst: "uicore-autosuggest__suggestion--first",
suggestionHighlighted: "uicore-autosuggest__suggestion--highlighted",
sectionContainer: "uicore-autosuggest__section-container",
sectionContainerFirst: "uicore-autosuggest__section-container--first",
sectionTitle: "uicore-autosuggest__section-title",
};
// Autosuggest is a controlled component.
// This means that you need to provide an input value
// and an onChange handler that updates this value (see below).
// Suggestions also need to be provided to the Autosuggest,
// and they are initially empty because the Autosuggest is closed.
this.state = {
inputValue: this.getLabel(props.value),
suggestions: [],
};
}
componentDidMount() {
this._isMounted = true;
}
componentWillUnmount() {
this._isMounted = false;
}
/** @internal */
componentDidUpdate(prevProps) {
if (this.props.value !== prevProps.value ||
this.props.options !== prevProps.options) {
this.setState((_prevState, props) => ({
inputValue: this.getLabel(props.value),
}));
}
}
getLabel(value) {
let label = "";
if (this.props.getLabel) {
label = this.props.getLabel(value);
}
else if (this.props.options instanceof Array) {
const entry = this.props.options.find((data) => data.value === value);
if (entry)
label = entry.label;
}
else {
Logger.logError(UiCore.loggerCategory("AutoSuggest"), `props.getLabel should be provided when props.options is a function`);
}
return label;
}
render() {
const { inputValue, suggestions } = this.state;
const { value, onChange, placeholder, options, onSuggestionSelected, setFocus, alwaysRenderSuggestions, onPressEnter, onPressEscape, onPressTab, onInputFocus, getLabel, getSuggestions, renderInputComponent, renderSuggestionsContainer, onSuggestionsClearRequested, ...props } = this.props;
const inputPlaceholder = !inputValue ? placeholder : undefined;
const inputProps = {
...props,
value: inputValue,
onChange: this._onChange,
onFocus: this._onFocus,
placeholder: inputPlaceholder,
autoFocus: setFocus,
};
const defaultRenderInputComponent = (renderInputProps) => {
const { size, ...other } = renderInputProps;
return React.createElement(Input, { ...other });
};
return (
// The onKeyDown event handler is only being used to capture bubbled events
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
React.createElement("div", { className: this.props.className, style: this.props.style, onKeyDown: this._handleKeyDown },
React.createElement(ReactAutosuggest, { theme: this._theme, suggestions: suggestions, onSuggestionsFetchRequested: this._onSuggestionsFetchRequested, onSuggestionsClearRequested: this._onSuggestionsClearRequested, getSuggestionValue: this._getSuggestionValue, renderSuggestion: this._renderSuggestion, inputProps: inputProps, onSuggestionSelected: this._onSuggestionSelected, alwaysRenderSuggestions: alwaysRenderSuggestions, renderInputComponent: renderInputComponent || defaultRenderInputComponent, renderSuggestionsContainer: renderSuggestionsContainer })));
}
}
//# sourceMappingURL=AutoSuggest.js.map