08ff6b02c7be4f6db6a487fbb18d0cd63248df88
[arvados.git] / src / components / data-table-multiselect-popover / data-table-multiselect-popover.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import React, { useEffect } from "react";
6 import { WithStyles, withStyles, ButtonBase, StyleRulesCallback, Theme, Popover, Card, Tooltip, IconButton } from "@material-ui/core";
7 import classnames from "classnames";
8 import { DefaultTransformOrigin } from "components/popover/helpers";
9 import debounce from "lodash/debounce";
10 import { grey } from "@material-ui/core/colors";
11 import { TCheckedList } from "components/data-table/data-table";
12
13 export type CssRules = "root" | "icon" | "iconButton" | "disabled" | "optionsContainer" | "option";
14
15 const styles: StyleRulesCallback<CssRules> = (theme: Theme) => ({
16     root: {
17         borderRadius: "7px",
18         "&:hover": {
19             backgroundColor: grey[200],
20         },
21         "&:focus": {
22             color: theme.palette.text.primary,
23         },
24     },
25     icon: {
26         cursor: "pointer",
27         fontSize: 20,
28         userSelect: "none",
29         "&:hover": {
30             color: theme.palette.text.primary,
31         },
32         paddingBottom: "5px",
33     },
34     iconButton: {
35         color: theme.palette.text.primary,
36         opacity: 0.6,
37         padding: 1,
38         paddingBottom: 5,
39     },
40     disabled: {
41         color: grey[500],
42     },
43     optionsContainer: {
44         padding: "1rem 0",
45         flex: 1,
46     },
47     option: {
48         cursor: "pointer",
49         display: "flex",
50         padding: "3px 2rem",
51         fontSize: "0.9rem",
52         alignItems: "center",
53         "&:hover": {
54             backgroundColor: "rgba(0, 0, 0, 0.08)",
55         },
56     },
57 });
58
59 export type DataTableMultiselectOption = {
60     name: string;
61     fn: (checkedList) => void;
62 };
63
64 export interface DataTableMultiselectProps {
65     name: string;
66     disabled: boolean;
67     options: DataTableMultiselectOption[];
68     checkedList: TCheckedList;
69 }
70
71 interface DataTableFMultiselectPopState {
72     anchorEl?: HTMLElement;
73 }
74
75 export const DataTableMultiselectPopover = withStyles(styles)(
76     class extends React.Component<DataTableMultiselectProps & WithStyles<CssRules>, DataTableFMultiselectPopState> {
77         state: DataTableFMultiselectPopState = {
78             anchorEl: undefined,
79         };
80         icon = React.createRef<HTMLElement>();
81
82         render() {
83             const { classes, children, options, checkedList, disabled } = this.props;
84             return (
85                 <>
86                     <Tooltip
87                         disableFocusListener
88                         title="Select Options"
89                     >
90                         <ButtonBase
91                             className={classnames(classes.root)}
92                             component="span"
93                             onClick={disabled ? () => {} : this.open}
94                             disableRipple
95                         >
96                             {children}
97                             <IconButton
98                                 component="span"
99                                 classes={{ root: classes.iconButton }}
100                                 tabIndex={-1}
101                             >
102                                 <i
103                                     className={`${classnames(["fas fa-sort-down", classes.icon])}${disabled ? ` ${classes.disabled}` : ""}`}
104                                     data-fa-transform="shrink-3"
105                                     ref={this.icon}
106                                 />
107                             </IconButton>
108                         </ButtonBase>
109                     </Tooltip>
110                     <Popover
111                         anchorEl={this.state.anchorEl}
112                         open={!!this.state.anchorEl}
113                         anchorOrigin={DefaultTransformOrigin}
114                         transformOrigin={DefaultTransformOrigin}
115                         onClose={this.close}
116                     >
117                         <Card>
118                             <div className={classes.optionsContainer}>
119                                 {options.length &&
120                                     options.map((option, i) => (
121                                         <div
122                                             key={i}
123                                             className={classes.option}
124                                             onClick={() => {
125                                                 option.fn(checkedList);
126                                                 this.close();
127                                             }}
128                                         >
129                                             {option.name}
130                                         </div>
131                                     ))}
132                             </div>
133                         </Card>
134                     </Popover>
135                 </>
136             );
137         }
138
139         open = () => {
140             this.setState({ anchorEl: this.icon.current || undefined });
141         };
142
143         close = () => {
144             this.setState(prev => ({
145                 ...prev,
146                 anchorEl: undefined,
147             }));
148         };
149     }
150 );