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