saleor-dashboard/src/components/CardMenu/CardMenu.tsx

141 lines
3.7 KiB
TypeScript
Raw Normal View History

import ClickAwayListener from "@material-ui/core/ClickAwayListener";
import Grow from "@material-ui/core/Grow";
2019-06-19 14:40:52 +00:00
import IconButton from "@material-ui/core/IconButton";
import MenuItem from "@material-ui/core/MenuItem";
import MenuList from "@material-ui/core/MenuList";
import Paper from "@material-ui/core/Paper";
import Popper from "@material-ui/core/Popper";
2019-10-30 14:34:24 +00:00
import { makeStyles } from "@material-ui/core/styles";
2019-06-19 14:40:52 +00:00
import MoreVertIcon from "@material-ui/icons/MoreVert";
2019-08-09 10:26:22 +00:00
import React from "react";
2019-06-19 14:40:52 +00:00
const ITEM_HEIGHT = 48;
export interface CardMenuItem {
disabled?: boolean;
2019-06-19 14:40:52 +00:00
label: string;
testId?: string;
2019-06-19 14:40:52 +00:00
onSelect: () => void;
}
export interface CardMenuProps {
className?: string;
disabled?: boolean;
menuItems: CardMenuItem[];
}
2019-12-03 15:28:40 +00:00
const useStyles = makeStyles(
theme => ({
iconButton: {
background: theme.palette.background.paper,
borderRadius: "100%",
height: 32,
padding: 0,
width: 32
},
paper: {
marginTop: theme.spacing(2),
maxHeight: ITEM_HEIGHT * 4.5
2019-12-03 15:28:40 +00:00
}
}),
{ name: "CardMenu" }
);
2019-06-19 14:40:52 +00:00
2019-10-30 14:34:24 +00:00
const CardMenu: React.FC<CardMenuProps> = props => {
const { className, disabled, menuItems, ...rest } = props;
2019-10-30 14:34:24 +00:00
const classes = useStyles(props);
2019-06-19 14:40:52 +00:00
const anchorRef = React.useRef<HTMLButtonElement | null>(null);
const [open, setOpen] = React.useState(false);
2019-06-19 14:40:52 +00:00
const handleToggle = () => setOpen(prevOpen => !prevOpen);
const handleClose = (event: React.MouseEvent<EventTarget>) => {
if (
anchorRef.current &&
anchorRef.current.contains(event.target as HTMLElement)
) {
return;
}
2019-06-19 14:40:52 +00:00
setOpen(false);
2019-10-30 14:34:24 +00:00
};
2019-06-19 14:40:52 +00:00
const handleListKeyDown = (event: React.KeyboardEvent) => {
if (event.key === "Tab") {
event.preventDefault();
setOpen(false);
}
2019-10-30 14:34:24 +00:00
};
2019-06-19 14:40:52 +00:00
const prevOpen = React.useRef(open);
React.useEffect(() => {
if (prevOpen.current === true && open === false) {
anchorRef.current!.focus();
}
prevOpen.current = open;
}, [open]);
const handleMenuClick = (index: number) => {
menuItems[index].onSelect();
setOpen(false);
};
2019-10-30 14:34:24 +00:00
return (
<div className={className} {...rest}>
2019-10-30 14:34:24 +00:00
<IconButton
aria-label="More"
aria-owns={open ? "long-menu" : null}
aria-haspopup="true"
className={classes.iconButton}
color="primary"
disabled={disabled}
ref={anchorRef}
onClick={handleToggle}
2019-10-30 14:34:24 +00:00
>
<MoreVertIcon />
</IconButton>
<Popper
placement="bottom-end"
2019-10-30 14:34:24 +00:00
open={open}
anchorEl={anchorRef.current}
transition
2019-10-30 14:34:24 +00:00
>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin:
placement === "bottom" ? "right top" : "right bottom"
}}
2019-10-30 14:34:24 +00:00
>
<Paper className={classes.paper}>
<ClickAwayListener onClickAway={handleClose}>
<MenuList
autoFocusItem={open}
id="menu-list-grow"
onKeyDown={handleListKeyDown}
>
{menuItems.map((menuItem, menuItemIndex) => (
<MenuItem
disabled={menuItem.disabled}
onClick={() => handleMenuClick(menuItemIndex)}
key={menuItem.label}
data-test={menuItem.testId}
>
{menuItem.label}
</MenuItem>
))}
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
2019-10-30 14:34:24 +00:00
</div>
);
};
2019-06-19 14:40:52 +00:00
CardMenu.displayName = "CardMenu";
export default CardMenu;