forked from mui/material-ui
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Menu.tsx
87 lines (81 loc) · 2.27 KB
/
Menu.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import * as React from 'react';
import JoyMenu, { MenuUnstyledActions } from '@mui/joy/Menu';
import MenuItem from '@mui/joy/MenuItem';
function Menu({
control,
menus,
id,
}: {
control: React.ReactElement;
id: string;
menus: Array<{ label: string } & { [k: string]: any }>;
}) {
const [anchorEl, setAnchorEl] = React.useState<HTMLButtonElement | null>(null);
const isOpen = Boolean(anchorEl);
const buttonRef = React.useRef<HTMLButtonElement>(null);
const menuActions = React.useRef<MenuUnstyledActions>(null);
const handleButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
if (isOpen) {
setAnchorEl(null);
} else {
setAnchorEl(event.currentTarget);
}
};
const handleButtonKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>) => {
if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
event.preventDefault();
setAnchorEl(event.currentTarget);
if (event.key === 'ArrowUp') {
menuActions.current?.highlightLastItem();
}
}
};
const close = () => {
setAnchorEl(null);
buttonRef.current!.focus();
};
return (
<React.Fragment>
{React.cloneElement(control, {
type: 'button',
onClick: handleButtonClick,
onKeyDown: handleButtonKeyDown,
ref: buttonRef,
'aria-controls': isOpen ? id : undefined,
'aria-expanded': isOpen || undefined,
'aria-haspopup': 'menu',
})}
<JoyMenu
id={id}
placement="bottom-end"
actions={menuActions}
open={isOpen}
onClose={close}
anchorEl={anchorEl}
sx={{ minWidth: 120 }}
>
{menus.map(({ label, active, ...item }) => {
const menuItem = (
<MenuItem
selected={active}
variant={active ? 'soft' : 'plain'}
onClick={close}
{...item}
>
{label}
</MenuItem>
);
if (item.href) {
return (
<li key={label} role="none">
{React.cloneElement(menuItem, { component: 'a' })}
</li>
);
}
return React.cloneElement(menuItem, { key: label });
})}
</JoyMenu>
</React.Fragment>
);
}
export default Menu;