azure-devops-ui
Version:
React components for building web UI in Azure DevOps
88 lines (87 loc) • 3.76 kB
JavaScript
import "../../CommonImports";
import "../../Core/core.css";
import * as React from "react";
import { TextField } from "../TextField/TextField";
import { ObservableLike } from '../../Core/Observable';
import { css, KeyCode } from '../../Util';
export class TypeAhead extends React.Component {
constructor() {
super(...arguments);
this.textFieldRef = React.createRef();
this.autofillEnabled = true;
this.select = () => {
this.textFieldRef.current.select();
};
this.onKeyDown = (event) => {
this.props.onKeyDown && this.props.onKeyDown(event);
if (event.isDefaultPrevented()) {
return;
}
const suggestedValue = this.props.suggestedValue && ObservableLike.getValue(this.props.suggestedValue);
const typedValue = this.props.value && ObservableLike.getValue(this.props.value);
switch (event.which) {
case KeyCode.tab:
if (suggestedValue && typedValue !== suggestedValue && this.autofillEnabled && this.props.onAutoComplete) {
this.props.onAutoComplete(suggestedValue);
event.preventDefault();
}
break;
case KeyCode.backspace:
case KeyCode.delete:
this.autofillEnabled = false;
break;
default:
this.autofillEnabled = true;
break;
}
};
}
// We have to use this paradigm because otherwise componentDidUpdate won't get called
subscribeAll(props) {
ObservableLike.subscribe(props.value, () => this.forceUpdate());
ObservableLike.subscribe(props.suggestedValue, () => this.forceUpdate());
}
unsubscribeAll(props) {
ObservableLike.unsubscribe(props.value, () => this.forceUpdate());
ObservableLike.unsubscribe(props.suggestedValue, () => this.forceUpdate());
}
componentDidMount() {
this.subscribeAll(this.props);
}
componentWillUnmount() {
this.unsubscribeAll(this.props);
}
UNSAFE_componentWillReceiveProps(newProps) {
this.unsubscribeAll(this.props);
this.subscribeAll(newProps);
}
focus() {
this.textFieldRef.current.focus();
}
get selectionEnd() {
return this.textFieldRef.current.selectionEnd;
}
get selectionStart() {
return this.textFieldRef.current.selectionStart;
}
setSelectionRange(start, end, direction) {
this.textFieldRef.current.setSelectionRange(start, end, direction);
}
render() {
const { value, suggestedValue, className } = this.props;
const renderValue = this.autofillEnabled ? suggestedValue : value;
return (React.createElement(TextField, Object.assign({}, this.props, { className: css(className, "bolt-typeahead"), onKeyDown: this.onKeyDown, ref: this.textFieldRef, value: renderValue })));
}
componentDidUpdate() {
const suggestedValue = this.props.suggestedValue && ObservableLike.getValue(this.props.suggestedValue);
const typedValue = this.props.value && ObservableLike.getValue(this.props.value);
if (suggestedValue && this.autofillEnabled) {
if (typedValue && suggestedValue.startsWith(typedValue)) {
this.textFieldRef.current.setSelectionRange(typedValue.length, suggestedValue.length, "backward");
}
else if (!typedValue) {
this.textFieldRef.current.setSelectionRange(0, suggestedValue.length);
}
}
}
}