forked from pterodactyl/panel
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDropdownMenu.tsx
More file actions
87 lines (73 loc) · 2.47 KB
/
Copy pathDropdownMenu.tsx
File metadata and controls
87 lines (73 loc) · 2.47 KB
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 React, { useEffect, useRef, useState } from 'react';
import { CSSTransition } from 'react-transition-group';
import styled from 'styled-components';
interface Props {
children: React.ReactNode;
renderToggle: (onClick: (e: React.MouseEvent<any, MouseEvent>) => void) => React.ReactChild;
}
export const DropdownButtonRow = styled.button<{ danger?: boolean }>`
${tw`p-2 flex items-center rounded w-full text-neutral-500`};
transition: 150ms all ease;
&:hover {
${props => props.danger
? tw`text-red-700 bg-red-100`
: tw`text-neutral-700 bg-neutral-100`
};
}
`;
const DropdownMenu = ({ renderToggle, children }: Props) => {
const menu = useRef<HTMLDivElement>(null);
const [ posX, setPosX ] = useState(0);
const [ visible, setVisible ] = useState(false);
const onClickHandler = (e: React.MouseEvent<any, MouseEvent>) => {
e.preventDefault();
!visible && setPosX(e.clientX);
setVisible(s => !s);
};
const windowListener = (e: MouseEvent) => {
if (e.button === 2 || !visible || !menu.current) {
return;
}
if (e.target === menu.current || menu.current.contains(e.target as Node)) {
return;
}
if (e.target !== menu.current && !menu.current.contains(e.target as Node)) {
setVisible(false);
}
};
useEffect(() => {
if (!visible || !menu.current) {
return;
}
document.addEventListener('click', windowListener);
menu.current.setAttribute(
'style', `left: ${Math.round(posX - menu.current.clientWidth)}px`,
);
return () => {
document.removeEventListener('click', windowListener);
}
}, [ visible ]);
return (
<div>
{renderToggle(onClickHandler)}
<CSSTransition
timeout={250}
in={visible}
unmountOnExit={true}
classNames={'fade'}
>
<div
ref={menu}
onClick={e => {
e.stopPropagation();
setVisible(false);
}}
className={'absolute bg-white p-2 rounded border border-neutral-700 shadow-lg text-neutral-500 min-w-48'}
>
{children}
</div>
</CSSTransition>
</div>
);
};
export default DropdownMenu;