1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | import React, { ChangeEventHandler } from 'react';
|
9 |
|
10 | import debounce from '../../utility/debounce';
|
11 |
|
12 | type OnSearchFn = (value: string) => void;
|
13 |
|
14 | type SearchBoxProps = {
|
15 | value?: string;
|
16 | placeholder: string;
|
17 | onSearch: OnSearchFn;
|
18 | };
|
19 |
|
20 | type SearchBoxState = {
|
21 | value: string;
|
22 | };
|
23 |
|
24 | export default class SearchBox extends React.Component<
|
25 | SearchBoxProps,
|
26 | SearchBoxState
|
27 | > {
|
28 | debouncedOnSearch: OnSearchFn;
|
29 |
|
30 | constructor(props: SearchBoxProps) {
|
31 | super(props);
|
32 | this.state = { value: props.value || '' };
|
33 | this.debouncedOnSearch = debounce(200, this.props.onSearch);
|
34 | }
|
35 |
|
36 | render() {
|
37 | return (
|
38 | <label className="search-box">
|
39 | <div className="search-box-icon" aria-hidden="true">
|
40 | {'\u26b2'}
|
41 | </div>
|
42 | <input
|
43 | value={this.state.value}
|
44 | onChange={this.handleChange}
|
45 | type="text"
|
46 | placeholder={this.props.placeholder}
|
47 | aria-label={this.props.placeholder}
|
48 | />
|
49 | {this.state.value && (
|
50 | <button
|
51 | className="search-box-clear"
|
52 | onClick={this.handleClear}
|
53 | aria-label="Clear search input"
|
54 | >
|
55 | {'\u2715'}
|
56 | </button>
|
57 | )}
|
58 | </label>
|
59 | );
|
60 | }
|
61 |
|
62 | handleChange: ChangeEventHandler<HTMLInputElement> = event => {
|
63 | const value = event.currentTarget.value;
|
64 | this.setState({ value });
|
65 | this.debouncedOnSearch(value);
|
66 | };
|
67 |
|
68 | handleClear = () => {
|
69 | this.setState({ value: '' });
|
70 | this.props.onSearch('');
|
71 | };
|
72 | }
|