1+ import React , { useState , useRef , useEffect } from 'react' ;
2+ import { cn } from '@/lib/utils' ;
3+
4+ interface SimpleDropdownMenuProps {
5+ children : React . ReactNode ;
6+ }
7+
8+ interface SimpleDropdownMenuTriggerProps {
9+ children : React . ReactNode ;
10+ asChild ?: boolean ;
11+ }
12+
13+ interface SimpleDropdownMenuContentProps {
14+ children : React . ReactNode ;
15+ className ?: string ;
16+ sideOffset ?: number ;
17+ [ key : string ] : any ;
18+ }
19+
20+ interface SimpleDropdownMenuItemProps {
21+ children : React . ReactNode ;
22+ className ?: string ;
23+ [ key : string ] : any ;
24+ }
25+
26+ interface SimpleDropdownMenuSeparatorProps {
27+ className ?: string ;
28+ [ key : string ] : any ;
29+ }
30+
31+ // The root dropdown component
32+ const SimpleDropdownMenu : React . FC < SimpleDropdownMenuProps > = ( { children } ) => {
33+ const [ isOpen , setIsOpen ] = useState ( false ) ;
34+ const dropdownRef = useRef < HTMLDivElement > ( null ) ;
35+
36+ // Close the dropdown when clicking outside
37+ useEffect ( ( ) => {
38+ if ( ! isOpen ) return ;
39+
40+ const handleClickOutside = ( event : MouseEvent ) => {
41+ if ( dropdownRef . current && ! dropdownRef . current . contains ( event . target as Node ) ) {
42+ setIsOpen ( false ) ;
43+ }
44+ } ;
45+
46+ document . addEventListener ( 'mousedown' , handleClickOutside ) ;
47+ return ( ) => document . removeEventListener ( 'mousedown' , handleClickOutside ) ;
48+ } , [ isOpen ] ) ;
49+
50+ return (
51+ < div ref = { dropdownRef } className = "relative" >
52+ { React . Children . map ( children , ( child ) => {
53+ if ( ! React . isValidElement ( child ) ) return child ;
54+
55+ // Pass the open state and toggle function to the children
56+ if ( child . type === SimpleDropdownMenuTrigger ) {
57+ return React . cloneElement ( child as React . ReactElement < any > , {
58+ onClick : ( ) => setIsOpen ( ! isOpen ) ,
59+ } ) ;
60+ }
61+
62+ if ( child . type === SimpleDropdownMenuContent ) {
63+ return isOpen ? child : null ;
64+ }
65+
66+ return child ;
67+ } ) }
68+ </ div >
69+ ) ;
70+ } ;
71+
72+ // The trigger button
73+ const SimpleDropdownMenuTrigger : React . FC < SimpleDropdownMenuTriggerProps > = ( {
74+ children,
75+ asChild,
76+ ...props
77+ } ) => {
78+ return (
79+ < div { ...props } className = "cursor-pointer" >
80+ { children }
81+ </ div >
82+ ) ;
83+ } ;
84+
85+ // The dropdown content container
86+ const SimpleDropdownMenuContent = React . forwardRef < HTMLDivElement , SimpleDropdownMenuContentProps > (
87+ ( { children, className, sideOffset = 4 , ...props } , ref ) => {
88+ return (
89+ < div
90+ ref = { ref }
91+ className = { cn (
92+ 'absolute z-50 min-w-[8rem] overflow-hidden rounded-md border bg-white p-2 shadow-md' ,
93+ 'top-full right-0 mt-1' ,
94+ className
95+ ) }
96+ { ...props }
97+ >
98+ { children }
99+ </ div >
100+ ) ;
101+ }
102+ ) ;
103+ SimpleDropdownMenuContent . displayName = 'SimpleDropdownMenuContent' ;
104+
105+ // Individual dropdown items
106+ const SimpleDropdownMenuItem = React . forwardRef < HTMLDivElement , SimpleDropdownMenuItemProps > (
107+ ( { children, className, ...props } , ref ) => {
108+ return (
109+ < div
110+ ref = { ref }
111+ className = { cn (
112+ 'flex cursor-pointer items-center rounded-sm px-2 py-1 text-sm text-gray-700 hover:bg-gray-100' ,
113+ className
114+ ) }
115+ { ...props }
116+ >
117+ { children }
118+ </ div >
119+ ) ;
120+ }
121+ ) ;
122+ SimpleDropdownMenuItem . displayName = 'SimpleDropdownMenuItem' ;
123+
124+ // Separator line
125+ const SimpleDropdownMenuSeparator = React . forwardRef < HTMLDivElement , SimpleDropdownMenuSeparatorProps > (
126+ ( { className, ...props } , ref ) => {
127+ return (
128+ < div
129+ ref = { ref }
130+ className = { cn ( 'my-1 h-px bg-gray-200' , className ) }
131+ { ...props }
132+ />
133+ ) ;
134+ }
135+ ) ;
136+ SimpleDropdownMenuSeparator . displayName = 'SimpleDropdownMenuSeparator' ;
137+
138+ export {
139+ SimpleDropdownMenu ,
140+ SimpleDropdownMenuTrigger ,
141+ SimpleDropdownMenuContent ,
142+ SimpleDropdownMenuItem ,
143+ SimpleDropdownMenuSeparator ,
144+ } ;
0 commit comments