aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/ui/SearchInput.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/ui/SearchInput.tsx')
-rw-r--r--src/components/ui/SearchInput.tsx116
1 files changed, 116 insertions, 0 deletions
diff --git a/src/components/ui/SearchInput.tsx b/src/components/ui/SearchInput.tsx
new file mode 100644
index 000000000..af55b0e11
--- /dev/null
+++ b/src/components/ui/SearchInput.tsx
@@ -0,0 +1,116 @@
1import { ChangeEvent, Component } from 'react';
2import { observer } from 'mobx-react';
3import classnames from 'classnames';
4import { debounce } from 'lodash';
5
6type Props = {
7 value: string;
8 placeholder: string;
9 className: string;
10 onChange: (e: ChangeEvent<HTMLInputElement>) => void;
11 onReset: () => void;
12 name: string;
13 throttle: boolean;
14 throttleDelay: number;
15 autoFocus: boolean;
16};
17
18@observer
19class SearchInput extends Component<Props> {
20 static defaultProps = {
21 value: '',
22 placeholder: '',
23 className: '',
24 name: 'searchInput',
25 throttle: false,
26 throttleDelay: 250,
27 onChange: () => null,
28 onReset: () => null,
29 autoFocus: false,
30 };
31
32 input = null;
33
34 constructor(props: Props) {
35 super(props);
36
37 this.state = {
38 value: props.value,
39 };
40
41 this.throttledOnChange = debounce(
42 this.throttledOnChange,
43 this.props.throttleDelay,
44 );
45 }
46
47 componentDidMount() {
48 const { autoFocus } = this.props;
49
50 if (autoFocus) {
51 // @ts-expect-error Object is possibly 'null'.
52 this.input.focus();
53 }
54 }
55
56 onChange(e: ChangeEvent<HTMLInputElement>) {
57 const { throttle, onChange } = this.props;
58 const { value } = e.target;
59 this.setState({ value });
60
61 if (throttle) {
62 e.persist();
63 // @ts-expect-error Argument of type 'string' is not assignable to parameter of type 'ChangeEvent<HTMLInputElement>'.
64 this.throttledOnChange(value);
65 } else {
66 // @ts-expect-error Argument of type 'string' is not assignable to parameter of type 'ChangeEvent<HTMLInputElement>'.
67 onChange(value);
68 }
69 }
70
71 throttledOnChange(e: ChangeEvent<HTMLInputElement>) {
72 const { onChange } = this.props;
73
74 onChange(e);
75 }
76
77 reset() {
78 const { onReset } = this.props;
79 this.setState({ value: '' });
80
81 onReset();
82 }
83
84 render() {
85 const { className, name, placeholder } = this.props;
86 // @ts-expect-error Property 'value' does not exist on type 'Readonly<{}>'.
87 const { value } = this.state;
88
89 return (
90 <div className={classnames([className, 'search-input'])}>
91 <label htmlFor={name} className="mdi mdi-magnify">
92 <input
93 name={name}
94 id={name}
95 type="text"
96 placeholder={placeholder}
97 value={value}
98 onChange={e => this.onChange(e)}
99 ref={ref => {
100 // @ts-expect-error Type 'HTMLInputElement | null' is not assignable to type 'null'.
101 this.input = ref;
102 }}
103 />
104 </label>
105 {value.length > 0 && (
106 <span
107 className="mdi mdi-close-circle-outline"
108 onClick={() => this.reset()}
109 />
110 )}
111 </div>
112 );
113 }
114}
115
116export default SearchInput;