Create chips input
[arvados-workbench2.git] / src / components / chips-input / chips-input.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import * as React from 'react';
6 import { Chips } from '~/components/chips/chips';
7 import { Input } from '@material-ui/core';
8
9 interface ChipsInputProps<Value> {
10     values: Value[];
11     getLabel?: (value: Value) => string;
12     onChange: (value: Value[]) => void;
13     createNewValue: (value: string) => Value;
14 }
15
16 export class ChipsInput<Value> extends React.Component<ChipsInputProps<Value>> {
17
18     state = {
19         text: '',
20     };
21
22     filler = React.createRef<HTMLDivElement>();
23     timeout = -1;
24
25     setText = (event: React.ChangeEvent<HTMLInputElement>) => {
26         this.setState({ text: event.target.value });
27     }
28
29     handleKeyPress = ({ key }: React.KeyboardEvent<HTMLInputElement>) => {
30         if (key === 'Enter') {
31             this.createNewValue();
32         } else if (key === 'Backspace') {
33             this.deleteLastValue();
34         }
35     }
36
37     createNewValue = () => {
38         if (this.state.text) {
39             const newValue = this.props.createNewValue(this.state.text);
40             this.setState({ text: '' });
41             this.props.onChange([...this.props.values, newValue]);
42         }
43     }
44
45     deleteLastValue = () => {
46         if (this.state.text.length === 0 && this.props.values.length > 0) {
47             this.props.onChange(this.props.values.slice(0, -1));
48         }
49     }
50
51     updateStyles = () => {
52         if(this.timeout){
53             clearTimeout(this.timeout);
54         }
55         this.timeout = setTimeout(() => this.forceUpdate());
56     }
57
58     render() {
59         this.updateStyles();
60         return <>
61             <div style={{ minHeight: '40px', zIndex: 1, position: 'relative' }}>
62                 <Chips {...this.props} filler={<div ref={this.filler} />} />
63             </div>
64             <Input
65                 value={this.state.text}
66                 onChange={this.setText}
67                 onKeyDown={this.handleKeyPress}
68                 style={{ top: '-24px' }}
69                 inputProps={{ style: this.getInputStyles(), }}
70                 fullWidth />
71         </>;
72     }
73
74     getInputStyles = (): React.CSSProperties => ({
75         width: this.filler.current
76             ? this.filler.current.offsetWidth + 8
77             : '100%',
78         position: 'relative',
79         right: this.filler.current
80             ? `calc(${this.filler.current.offsetWidth}px - 100%)`
81             : 0,
82         top: '-5px',
83         zIndex: 1,
84     })
85 }