d8c7edeeafa525c0edf0b4640945d1219a3fd314
[arvados-workbench2.git] / src / components / main-app-bar / search-bar / search-bar.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 { IconButton, Paper, StyleRulesCallback, withStyles, WithStyles } from '@material-ui/core';
7 import SearchIcon from '@material-ui/icons/Search';
8
9 interface SearchBarDataProps {
10     value: string;
11 }
12
13 interface SearchBarActionProps {
14     onSearch: (value: string) => any;
15     debounce?: number;
16 }
17
18 type SearchBarProps = SearchBarDataProps & SearchBarActionProps & WithStyles<CssRules>
19
20 interface SearchBarState {
21     value: string;
22 }
23
24 const DEFAULT_SEARCH_DEBOUNCE = 1000;
25
26 class SearchBar extends React.Component<SearchBarProps> {
27
28     state: SearchBarState = {
29         value: ""
30     }
31
32     timeout: NodeJS.Timer;
33
34     render() {
35         const { classes } = this.props
36         return <Paper className={classes.container}>
37             <form onSubmit={this.handleSubmit}>
38                 <input
39                     className={classes.input}
40                     onChange={this.handleChange}
41                     placeholder="Search"
42                     value={this.state.value}
43                 />
44                 <IconButton className={classes.button}>
45                     <SearchIcon />
46                 </IconButton>
47             </form>
48         </Paper>
49     }
50
51     componentWillReceiveProps(nextProps: SearchBarProps) {
52         if (nextProps.value !== this.props.value) {
53             this.setState({ value: nextProps.value });
54         }
55     }
56
57     componentWillUnmount() {
58         clearTimeout(this.timeout);
59     }
60
61     handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
62         event.preventDefault();
63         clearTimeout(this.timeout);
64         this.props.onSearch(this.state.value);
65     }
66
67     handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
68         clearTimeout(this.timeout);
69         this.setState({ value: event.target.value });
70         this.timeout = setTimeout(
71             () => this.props.onSearch(this.state.value),
72             this.props.debounce || DEFAULT_SEARCH_DEBOUNCE
73         );
74
75     }
76
77 }
78
79 type CssRules = 'container' | 'input' | 'button'
80
81 const styles: StyleRulesCallback<CssRules> = theme => {
82     const { unit } = theme.spacing
83     return {
84         container: {
85             position: 'relative',
86             width: '100%'
87         },
88         input: {
89             border: 'none',
90             borderRadius: unit / 4,
91             boxSizing: 'border-box',
92             padding: unit,
93             paddingRight: unit * 4,
94             width: '100%',
95         },
96         button: {
97             position: 'absolute',
98             top: unit / 2,
99             right: unit / 2,
100             width: unit * 3,
101             height: unit * 3
102         }
103     }
104 }
105
106 export default withStyles(styles)(SearchBar)