Files
QR-master/src/components/ui/Dropdown.tsx

63 lines
1.8 KiB
TypeScript

import React, { useState, useRef, useEffect } from 'react';
import { cn } from '@/lib/utils';
interface DropdownProps {
trigger: React.ReactNode;
children: React.ReactNode;
align?: 'left' | 'right';
}
export const Dropdown: React.FC<DropdownProps> = ({ trigger, children, align = 'left' }) => {
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
setIsOpen(false);
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);
return (
<div className="relative" ref={dropdownRef}>
<div onClick={() => setIsOpen(!isOpen)}>
{trigger}
</div>
{isOpen && (
<div
className={cn(
'absolute top-full mt-1 w-48 bg-white rounded-lg shadow-lg border border-gray-200 py-1 z-50',
align === 'right' ? 'right-0' : 'left-0'
)}
>
{children}
</div>
)}
</div>
);
};
interface DropdownItemProps extends React.HTMLAttributes<HTMLDivElement> {
icon?: React.ReactNode;
}
export const DropdownItem = React.forwardRef<HTMLDivElement, DropdownItemProps>(
({ className, icon, children, ...props }, ref) => (
<div
ref={ref}
className={cn(
'flex items-center px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 cursor-pointer',
className
)}
{...props}
>
{icon && <span className="mr-2">{icon}</span>}
{children}
</div>
)
);
DropdownItem.displayName = 'DropdownItem';