1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import * as React from 'react';
6 import { Chips } from '~/components/chips/chips';
7 import { Input, withStyles, WithStyles } from '@material-ui/core';
8 import { StyleRulesCallback } from '@material-ui/core/styles';
10 interface ChipsInputProps<Value> {
12 getLabel?: (value: Value) => string;
13 onChange: (value: Value[]) => void;
14 createNewValue: (value: string) => Value;
17 type CssRules = 'chips' | 'input' | 'inputContainer';
19 const styles: StyleRulesCallback = () => ({
35 export const ChipsInput = withStyles(styles)(
36 class ChipsInput<Value> extends React.Component<ChipsInputProps<Value> & WithStyles<CssRules>> {
42 filler = React.createRef<HTMLDivElement>();
45 setText = (event: React.ChangeEvent<HTMLInputElement>) => {
46 this.setState({ text: event.target.value });
49 handleKeyPress = ({ key }: React.KeyboardEvent<HTMLInputElement>) => {
50 if (key === 'Enter') {
51 this.createNewValue();
52 } else if (key === 'Backspace') {
53 this.deleteLastValue();
57 createNewValue = () => {
58 if (this.state.text) {
59 const newValue = this.props.createNewValue(this.state.text);
60 this.setState({ text: '' });
61 this.props.onChange([...this.props.values, newValue]);
65 deleteLastValue = () => {
66 if (this.state.text.length === 0 && this.props.values.length > 0) {
67 this.props.onChange(this.props.values.slice(0, -1));
71 updateCursorPosition = () => {
73 clearTimeout(this.timeout);
75 this.timeout = setTimeout(() => this.forceUpdate());
79 this.updateCursorPosition();
81 <div className={this.props.classes.chips}>
82 <Chips {...this.props} filler={<div ref={this.filler} />} />
85 value={this.state.text}
86 onChange={this.setText}
87 onKeyDown={this.handleKeyPress}
89 className: this.props.classes.input,
90 style: this.getInputStyles(),
93 className={this.props.classes.inputContainer} />
97 getInputStyles = (): React.CSSProperties => ({
98 width: this.filler.current
99 ? this.filler.current.offsetWidth + 8
101 right: this.filler.current
102 ? `calc(${this.filler.current.offsetWidth}px - 100%)`