diff --git a/bun.lockb b/bun.lockb index 73ecddf..20b7f98 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index e136fb9..89f193f 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "@hono/zod-validator": "^0.4.2", "@hookform/resolvers": "^3.10.0", "@radix-ui/react-avatar": "^1.1.2", + "@radix-ui/react-dropdown-menu": "^2.1.5", "@radix-ui/react-label": "^2.1.1", "@radix-ui/react-radio-group": "^1.2.2", "@radix-ui/react-separator": "^1.1.1", diff --git a/src/components/ui/dropdown-menu.tsx b/src/components/ui/dropdown-menu.tsx new file mode 100644 index 0000000..3d62e19 --- /dev/null +++ b/src/components/ui/dropdown-menu.tsx @@ -0,0 +1,263 @@ +"use client"; + +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; +import { Check, ChevronRight, Circle } from "lucide-react"; +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +type PointerDownEvent = Parameters< + NonNullable +>[0]; +type PointerDownOutsideEvent = Parameters< + NonNullable< + DropdownMenuPrimitive.DropdownMenuContentProps["onPointerDownOutside"] + > +>[0]; + +const DropdownMenu = DropdownMenuPrimitive.Root; + +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; + +const DropdownMenuGroup = DropdownMenuPrimitive.Group; + +const DropdownMenuPortal = DropdownMenuPrimitive.Portal; + +const DropdownMenuSub = DropdownMenuPrimitive.Sub; + +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup; + +const DropdownMenuSubTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, children, ...props }, ref) => ( + + {children} + + +)); +DropdownMenuSubTrigger.displayName = + DropdownMenuPrimitive.SubTrigger.displayName; + +const DropdownMenuSubContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DropdownMenuSubContent.displayName = + DropdownMenuPrimitive.SubContent.displayName; + +const DropdownMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>( + ( + { + className, + sideOffset = 4, + onPointerDown, + onPointerDownOutside, + onCloseAutoFocus, + ...props + }, + ref + ) => { + const isCloseFromMouse = React.useRef(false); + + const handlePointerDown = React.useCallback( + (e: PointerDownEvent) => { + isCloseFromMouse.current = true; + onPointerDown?.(e); + }, + [onPointerDown] + ); + + const handlePointerDownOutside = React.useCallback( + (e: PointerDownOutsideEvent) => { + isCloseFromMouse.current = true; + onPointerDownOutside?.(e); + }, + [onPointerDownOutside] + ); + + const handleCloseAutoFocus = React.useCallback( + (e: Event) => { + if (onCloseAutoFocus) { + return onCloseAutoFocus(e); + } + + if (!isCloseFromMouse.current) { + return; + } + + e.preventDefault(); + isCloseFromMouse.current = false; + }, + [onCloseAutoFocus] + ); + + return ( + + + + ); + } +); +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName; + +const DropdownMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, ...props }, ref) => ( + +)); +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; + +const DropdownMenuCheckboxItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, checked, ...props }, ref) => ( + + + + + + + {children} + +)); +DropdownMenuCheckboxItem.displayName = + DropdownMenuPrimitive.CheckboxItem.displayName; + +const DropdownMenuRadioItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)); +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName; + +const DropdownMenuLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, ...props }, ref) => ( + +)); +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName; + +const DropdownMenuSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; + +const DropdownMenuShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ); +}; +DropdownMenuShortcut.displayName = "DropdownMenuShortcut"; + +export { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuPortal, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuTrigger, +};