-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEditableSelect.jsx
100 lines (97 loc) · 3.58 KB
/
EditableSelect.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/**
* Copyright 2020-2021 Sourcepole AG
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
import React from 'react';
import PropTypes from 'prop-types';
import Icon from '../Icon';
import InputContainer from '../InputContainer';
import MiscUtils from '../../utils/MiscUtils';
import './style/EditableSelect.css';
export default class EditableSelect extends React.Component {
static propTypes = {
onChange: PropTypes.func,
onSubmit: PropTypes.func,
options: PropTypes.array,
placeholder: PropTypes.string,
readOnly: PropTypes.bool
};
static defaultProps = {
onSubmit: () => {}
};
state = {
textValue: "",
selectedOption: null,
focused: false
};
render() {
return (
<div className="EditableSelect">
<InputContainer className="editable-select-inputcontainer">
<input
onBlur={() => this.setState({focused: false})}
onChange={this.valueChanged}
onClick={() => this.setState({focused: true})}
onKeyPress={this.onKeyPress}
placeholder={this.state.selectedOption ? "" : this.props.placeholder}
readOnly={this.props.readOnly}
ref={el => { this.input = el; }}
role="input"
type="text"
value={this.state.textValue} />
<Icon icon="clear" onClick={this.clear} role="suffix" />
</InputContainer>
{this.state.selectedOption !== null ? this.renderSelectedOption() : null}
{this.state.focused && !this.props.readOnly ? this.renderOptions() : null}
</div>
);
}
optionLabel = (option) => {
return typeof option === 'string' ? option : option.label;
};
optionValue = (option) => {
return typeof option === 'string' ? option : option.value;
};
renderOptions = () => {
return (
<div className="editable-select-dropdown">
{this.props.options.map((option, idx) => {
const label = this.optionLabel(option);
if (this.state.textValue && !label.toLowerCase().startsWith(this.state.textValue.toLowerCase())) {
return null;
}
return (
<div key={"opt" + idx} onClick={() => this.optionSelected(option)} onMouseDown={MiscUtils.killEvent}>{this.optionLabel(option)}</div>
);
})}
</div>
);
};
renderSelectedOption = () => {
return (
<div className="editable-select-selopt">
<span>{this.optionLabel(this.state.selectedOption)}</span>
</div>
);
};
valueChanged = (ev) => {
this.setState({textValue: ev.target.value, selectedOption: null});
this.props.onChange(ev.target.value.trim());
};
optionSelected = (option) => {
this.setState({textValue: "", selectedOption: option, focused: false});
this.props.onChange(this.optionValue(option.value));
};
clear = () => {
this.setState({textValue: "", selectedOption: null, focused: false});
this.props.onChange("");
};
onKeyPress = (ev) => {
if (!ev.target.readOnly && ev.key === 'Enter') {
this.props.onSubmit();
}
};
}