forked from PinSpace-Org/GistPin
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDropdown.tsx
More file actions
72 lines (65 loc) 路 2.09 KB
/
Copy pathDropdown.tsx
File metadata and controls
72 lines (65 loc) 路 2.09 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
'use client';
import { ReactNode, useEffect, useRef, useState } from 'react';
interface DropdownItem {
label: string;
onClick: () => void;
disabled?: boolean;
danger?: boolean;
}
interface DropdownProps {
trigger: ReactNode;
items: DropdownItem[];
align?: 'left' | 'right';
}
export default function Dropdown({ trigger, items, align = 'left' }: DropdownProps) {
const [open, setOpen] = useState(false);
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
function handleClickOutside(e: MouseEvent) {
if (ref.current && !ref.current.contains(e.target as Node)) {
setOpen(false);
}
}
document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);
return (
<div ref={ref} className="relative inline-block">
<div onClick={() => setOpen((o) => !o)} className="cursor-pointer">
{trigger}
</div>
{open && (
<div
className={[
'absolute z-50 mt-1 min-w-[10rem] rounded-md border border-gray-200 bg-white shadow-md dark:border-gray-700 dark:bg-gray-800',
align === 'right' ? 'right-0' : 'left-0',
].join(' ')}
role="menu"
>
{items.map((item, i) => (
<button
key={i}
role="menuitem"
disabled={item.disabled}
onClick={() => {
if (!item.disabled) {
item.onClick();
setOpen(false);
}
}}
className={[
'w-full px-4 py-2 text-left text-sm transition-colors',
item.danger
? 'text-red-600 hover:bg-red-50 dark:text-red-400 dark:hover:bg-red-900/20'
: 'text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700',
item.disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer',
].join(' ')}
>
{item.label}
</button>
))}
</div>
)}
</div>
);
}