forked from grafana/grafana
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathSubMenu.tsx
106 lines (97 loc) · 2.88 KB
/
SubMenu.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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import { css, cx } from '@emotion/css';
import React, { CSSProperties, ReactElement, useEffect, useRef, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { useStyles2 } from '../../themes';
import { Icon } from '../Icon/Icon';
import { MenuItemProps } from './MenuItem';
import { useMenuFocus } from './hooks';
import { isElementOverflowing } from './utils';
/** @internal */
export interface SubMenuProps {
/** List of menu items of the subMenu */
items?: Array<ReactElement<MenuItemProps>>;
/** Open */
isOpen: boolean;
/** Marks whether subMenu was opened with arrow */
openedWithArrow: boolean;
/** Changes value of openedWithArrow */
setOpenedWithArrow: (openedWithArrow: boolean) => void;
/** Closes the subMenu */
close: () => void;
/** Custom style */
customStyle?: CSSProperties;
}
/** @internal */
export const SubMenu = React.memo(
({ items, isOpen, openedWithArrow, setOpenedWithArrow, close, customStyle }: SubMenuProps) => {
const styles = useStyles2(getStyles);
const localRef = useRef<HTMLDivElement>(null);
const [handleKeys] = useMenuFocus({
localRef,
isMenuOpen: isOpen,
openedWithArrow,
setOpenedWithArrow,
close,
});
const [pushLeft, setPushLeft] = useState(false);
useEffect(() => {
if (isOpen && localRef.current) {
setPushLeft(isElementOverflowing(localRef.current));
}
}, [isOpen]);
return (
<>
<div className={styles.iconWrapper} aria-label={selectors.components.Menu.SubMenu.icon}>
{/* @ts-ignore */}
<Icon name="angle-right" className={styles.icon} aria-hidden />
</div>
{isOpen && (
<div
ref={localRef}
className={cx(styles.subMenu, { [styles.pushLeft]: pushLeft })}
aria-label={selectors.components.Menu.SubMenu.container}
style={customStyle}
>
<div tabIndex={-1} className={styles.itemsWrapper} role="menu" onKeyDown={handleKeys}>
{/* @ts-ignore */}
{items}
</div>
</div>
)}
</>
);
}
);
SubMenu.displayName = 'SubMenu';
/** @internal */
const getStyles = (theme: GrafanaTheme2) => {
return {
iconWrapper: css({
display: 'flex',
flex: 1,
justifyContent: 'end',
}),
icon: css({
opacity: 0.7,
marginLeft: theme.spacing(1),
color: theme.colors.text.secondary,
}),
itemsWrapper: css({
background: theme.colors.background.primary,
boxShadow: theme.shadows.z3,
display: 'inline-block',
borderRadius: theme.shape.borderRadius(),
}),
pushLeft: css({
right: '100%',
left: 'unset',
}),
subMenu: css({
position: 'absolute',
top: 0,
left: '100%',
zIndex: theme.zIndex.dropdown,
}),
};
};