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