@srcroot/ui 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@srcroot/ui",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "A shadcn-style CLI UI library with polymorphic, accessible React components",
5
5
  "type": "module",
6
6
  "bin": {
@@ -22,15 +22,12 @@ const badgeVariants = cva(
22
22
  }
23
23
  )
24
24
 
25
- type BadgeVariants = VariantProps<typeof badgeVariants>
26
-
27
- interface BadgeBaseProps extends BadgeVariants {
28
- className?: string
29
- children?: React.ReactNode
30
- }
25
+ interface BadgeProps
26
+ extends React.HTMLAttributes<HTMLSpanElement>,
27
+ VariantProps<typeof badgeVariants> { }
31
28
 
32
29
  /**
33
- * Polymorphic Badge component for status indicators
30
+ * Badge component for status indicators
34
31
  *
35
32
  * @example
36
33
  * // Default badge
@@ -38,26 +35,13 @@ interface BadgeBaseProps extends BadgeVariants {
38
35
  *
39
36
  * // Destructive variant
40
37
  * <Badge variant="destructive">Error</Badge>
41
- *
42
- * // As a link
43
- * <Badge as="a" href="/status">View Status</Badge>
44
38
  */
45
- const Badge = React.forwardRef(
46
- <T extends React.ElementType = "span">(
47
- {
48
- as,
49
- className,
50
- variant,
51
- ...props
52
- }: BadgeBaseProps & { as?: T } & Omit<React.ComponentPropsWithoutRef<T>, keyof BadgeBaseProps | "as">,
53
- ref: React.ForwardedRef<React.ElementRef<T>>
54
- ) => {
55
- const Comp = as || "span"
56
-
39
+ const Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(
40
+ ({ className, variant, ...props }, ref) => {
57
41
  return (
58
- <Comp
59
- ref={ref as any}
60
- className={cn(badgeVariants({ variant, className }))}
42
+ <span
43
+ ref={ref}
44
+ className={cn(badgeVariants({ variant }), className)}
61
45
  {...props}
62
46
  />
63
47
  )
@@ -28,7 +28,7 @@ Breadcrumb.displayName = "Breadcrumb"
28
28
 
29
29
  const BreadcrumbList = React.forwardRef<
30
30
  HTMLOListElement,
31
- React.OListHTMLAttributes<HTMLOListElement>
31
+ React.OlHTMLAttributes<HTMLOListElement>
32
32
  >(({ className, ...props }, ref) => (
33
33
  <ol
34
34
  ref={ref}
@@ -33,15 +33,12 @@ const buttonGroupVariants = cva("inline-flex", {
33
33
  },
34
34
  })
35
35
 
36
- type ButtonGroupVariants = VariantProps<typeof buttonGroupVariants>
37
-
38
- interface ButtonGroupBaseProps extends ButtonGroupVariants {
39
- className?: string
40
- children?: React.ReactNode
41
- }
36
+ interface ButtonGroupProps
37
+ extends React.HTMLAttributes<HTMLDivElement>,
38
+ VariantProps<typeof buttonGroupVariants> { }
42
39
 
43
40
  /**
44
- * Polymorphic ButtonGroup to group buttons together
41
+ * ButtonGroup to group buttons together
45
42
  *
46
43
  * @example
47
44
  * <ButtonGroup>
@@ -49,31 +46,14 @@ interface ButtonGroupBaseProps extends ButtonGroupVariants {
49
46
  * <Button>Center</Button>
50
47
  * <Button>Right</Button>
51
48
  * </ButtonGroup>
52
- *
53
- * @example
54
- * <ButtonGroup attached={false}>
55
- * <Button>Spaced</Button>
56
- * <Button>Buttons</Button>
57
- * </ButtonGroup>
58
49
  */
59
- const ButtonGroup = React.forwardRef(
60
- <T extends React.ElementType = "div">(
61
- {
62
- as,
63
- className,
64
- orientation,
65
- attached,
66
- ...props
67
- }: ButtonGroupBaseProps & { as?: T } & Omit<React.ComponentPropsWithoutRef<T>, keyof ButtonGroupBaseProps | "as">,
68
- ref: React.ForwardedRef<React.ElementRef<T>>
69
- ) => {
70
- const Comp = as || "div"
71
-
50
+ const ButtonGroup = React.forwardRef<HTMLDivElement, ButtonGroupProps>(
51
+ ({ className, orientation, attached, ...props }, ref) => {
72
52
  return (
73
- <Comp
74
- ref={ref as any}
53
+ <div
54
+ ref={ref}
75
55
  role="group"
76
- className={cn(buttonGroupVariants({ orientation, attached, className }))}
56
+ className={cn(buttonGroupVariants({ orientation, attached }), className)}
77
57
  {...props}
78
58
  />
79
59
  )
@@ -32,68 +32,42 @@ const buttonVariants = cva(
32
32
  }
33
33
  )
34
34
 
35
- type ButtonVariants = VariantProps<typeof buttonVariants>
36
-
37
- interface ButtonBaseProps extends ButtonVariants {
38
- className?: string
39
- children?: React.ReactNode
35
+ interface ButtonProps
36
+ extends React.ButtonHTMLAttributes<HTMLButtonElement>,
37
+ VariantProps<typeof buttonVariants> {
38
+ asChild?: boolean
40
39
  }
41
40
 
42
41
  /**
43
- * Polymorphic Button component
42
+ * Button component
44
43
  *
45
44
  * @example
46
- * // As a button (default)
45
+ * // Default button
47
46
  * <Button variant="outline">Click me</Button>
48
47
  *
49
- * // As a link
50
- * <Button as="a" href="/home" variant="link">Go Home</Button>
51
- *
52
48
  * // With loading state
53
49
  * <Button disabled>
54
50
  * <LoadingSpinner /> Processing...
55
51
  * </Button>
56
52
  */
57
- const Button = React.forwardRef(
58
- <T extends React.ElementType = "button">(
59
- {
60
- as,
61
- className,
62
- variant,
63
- size,
64
- ...props
65
- }: ButtonBaseProps & { as?: T } & Omit<React.ComponentPropsWithoutRef<T>, keyof ButtonBaseProps | "as">,
66
- ref: React.ForwardedRef<React.ElementRef<T>>
67
- ) => {
68
- const Comp = as || "button"
69
-
70
- // Ensure proper keyboard handling for non-button elements
71
- const handleKeyDown = (e: React.KeyboardEvent) => {
72
- if (Comp !== "button" && (e.key === "Enter" || e.key === " ")) {
73
- e.preventDefault()
74
- ; (e.currentTarget as HTMLElement).click()
75
- }
76
- // Call original onKeyDown if provided
77
- const originalOnKeyDown = (props as any).onKeyDown
78
- if (originalOnKeyDown) {
79
- originalOnKeyDown(e)
80
- }
53
+ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
54
+ ({ className, variant, size, asChild = false, children, ...props }, ref) => {
55
+ if (asChild && React.isValidElement(children)) {
56
+ return React.cloneElement(children as React.ReactElement<any>, {
57
+ ref,
58
+ className: cn(buttonVariants({ variant, size }), className),
59
+ ...props,
60
+ })
81
61
  }
82
62
 
83
- // Add role="button" for non-button elements
84
- const accessibilityProps = Comp !== "button" ? {
85
- role: "button",
86
- tabIndex: 0,
87
- onKeyDown: handleKeyDown,
88
- } : {}
89
-
90
63
  return (
91
- <Comp
92
- ref={ref as any}
93
- className={cn(buttonVariants({ variant, size, className }))}
94
- {...accessibilityProps}
64
+ <button
65
+ ref={ref}
66
+ className={cn(buttonVariants({ variant, size }), className)}
95
67
  {...props}
96
- />
68
+ >
69
+ {children}
70
+ </button>
97
71
  )
98
72
  }
99
73
  )
package/registry/card.tsx CHANGED
@@ -15,33 +15,17 @@ import { cn } from "@/lib/utils"
15
15
  * </Card>
16
16
  */
17
17
 
18
- interface CardBaseProps {
19
- className?: string
20
- children?: React.ReactNode
21
- }
22
-
23
- const Card = React.forwardRef(
24
- <T extends React.ElementType = "div">(
25
- {
26
- as,
27
- className,
28
- ...props
29
- }: CardBaseProps & { as?: T } & Omit<React.ComponentPropsWithoutRef<T>, keyof CardBaseProps | "as">,
30
- ref: React.ForwardedRef<React.ElementRef<T>>
31
- ) => {
32
- const Comp = as || "div"
33
-
34
- return (
35
- <Comp
36
- ref={ref as any}
37
- className={cn(
38
- "rounded-xl border bg-card text-card-foreground shadow",
39
- className
40
- )}
41
- {...props}
42
- />
43
- )
44
- }
18
+ const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
19
+ ({ className, ...props }, ref) => (
20
+ <div
21
+ ref={ref}
22
+ className={cn(
23
+ "rounded-xl border bg-card text-card-foreground shadow",
24
+ className
25
+ )}
26
+ {...props}
27
+ />
28
+ )
45
29
  )
46
30
  Card.displayName = "Card"
47
31
 
@@ -57,26 +41,16 @@ const CardHeader = React.forwardRef<
57
41
  ))
58
42
  CardHeader.displayName = "CardHeader"
59
43
 
60
- const CardTitle = React.forwardRef(
61
- <T extends React.ElementType = "h3">(
62
- {
63
- as,
64
- className,
65
- ...props
66
- }: CardBaseProps & { as?: T } & Omit<React.ComponentPropsWithoutRef<T>, keyof CardBaseProps | "as">,
67
- ref: React.ForwardedRef<React.ElementRef<T>>
68
- ) => {
69
- const Comp = as || "h3"
70
-
71
- return (
72
- <Comp
73
- ref={ref as any}
74
- className={cn("font-semibold leading-none tracking-tight", className)}
75
- {...props}
76
- />
77
- )
78
- }
79
- )
44
+ const CardTitle = React.forwardRef<
45
+ HTMLHeadingElement,
46
+ React.HTMLAttributes<HTMLHeadingElement>
47
+ >(({ className, ...props }, ref) => (
48
+ <h3
49
+ ref={ref}
50
+ className={cn("font-semibold leading-none tracking-tight", className)}
51
+ {...props}
52
+ />
53
+ ))
80
54
  CardTitle.displayName = "CardTitle"
81
55
 
82
56
  const CardDescription = React.forwardRef<
@@ -120,9 +120,6 @@ export function Combobox({
120
120
  )
121
121
  ) : (
122
122
  <div className="flex items-center gap-2">
123
- {selectedOptions[0].icon && (
124
- <selectedOptions[0].icon className="h-4 w-4 text-muted-foreground" />
125
- ) /* this effectively forces me to use a variable too */}
126
123
  {(() => {
127
124
  const Icon = selectedOptions[0].icon
128
125
  return Icon ? <Icon className="h-4 w-4 text-muted-foreground" /> : null
@@ -156,11 +156,13 @@ const CommandEmpty = React.forwardRef<HTMLDivElement, CommandEmptyProps>(
156
156
  ({ className, children, ...props }, ref) => {
157
157
  const { search, items } = useCommandContext()
158
158
 
159
- // Check if any items are visible
160
- const hasVisibleItems = items.length > 0
159
+ // Count how many items would be visible with the current search
160
+ const visibleCount = search
161
+ ? items.filter(item => item.toLowerCase().includes(search.toLowerCase())).length
162
+ : items.length
161
163
 
162
- if (hasVisibleItems && search) {
163
- // This will be handled by filtering in CommandItem
164
+ // Only show empty message when user has typed something but no results match
165
+ if (!search || visibleCount > 0) {
164
166
  return null
165
167
  }
166
168
 
@@ -18,38 +18,22 @@ const containerVariants = cva("mx-auto w-full px-4", {
18
18
  },
19
19
  })
20
20
 
21
- type ContainerVariants = VariantProps<typeof containerVariants>
22
-
23
- interface ContainerBaseProps extends ContainerVariants {
24
- className?: string
25
- children?: React.ReactNode
26
- }
21
+ interface ContainerProps
22
+ extends React.HTMLAttributes<HTMLDivElement>,
23
+ VariantProps<typeof containerVariants> { }
27
24
 
28
25
  /**
29
- * Polymorphic Container for max-width layouts
26
+ * Container for max-width layouts
30
27
  *
31
28
  * @example
32
29
  * <Container size="lg">Content</Container>
33
- *
34
- * @example
35
- * <Container as="section" size="md">Section content</Container>
36
30
  */
37
- const Container = React.forwardRef(
38
- <T extends React.ElementType = "div">(
39
- {
40
- as,
41
- className,
42
- size,
43
- ...props
44
- }: ContainerBaseProps & { as?: T } & Omit<React.ComponentPropsWithoutRef<T>, keyof ContainerBaseProps | "as">,
45
- ref: React.ForwardedRef<React.ElementRef<T>>
46
- ) => {
47
- const Comp = as || "div"
48
-
31
+ const Container = React.forwardRef<HTMLDivElement, ContainerProps>(
32
+ ({ className, size, ...props }, ref) => {
49
33
  return (
50
- <Comp
51
- ref={ref as any}
52
- className={cn(containerVariants({ size, className }))}
34
+ <div
35
+ ref={ref}
36
+ className={cn(containerVariants({ size }), className)}
53
37
  {...props}
54
38
  />
55
39
  )
@@ -88,19 +88,21 @@ const DrawerClose = React.forwardRef<HTMLButtonElement, React.ButtonHTMLAttribut
88
88
  )
89
89
  DrawerClose.displayName = "DrawerClose"
90
90
 
91
- // Drawer Overlay
92
- const DrawerOverlay = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
93
- ({ className, ...props }, ref) => {
94
- const { open, onOpenChange } = useDrawer()
91
+ // Drawer Overlay (internal)
92
+ interface DrawerOverlayProps extends React.HTMLAttributes<HTMLDivElement> {
93
+ isAnimating: boolean
94
+ }
95
95
 
96
- if (!open) return null
96
+ const DrawerOverlay = React.forwardRef<HTMLDivElement, DrawerOverlayProps>(
97
+ ({ className, isAnimating, ...props }, ref) => {
98
+ const { onOpenChange } = useDrawer()
97
99
 
98
100
  return (
99
101
  <div
100
102
  ref={ref}
101
103
  className={cn(
102
- "fixed inset-0 z-50 bg-black/80",
103
- "animate-in fade-in-0",
104
+ "fixed inset-0 z-50 bg-black/80 transition-opacity duration-300",
105
+ isAnimating ? "opacity-100" : "opacity-0",
104
106
  className
105
107
  )}
106
108
  onClick={() => onOpenChange(false)}
@@ -119,6 +121,28 @@ interface DrawerContentProps extends React.HTMLAttributes<HTMLDivElement> {
119
121
  const DrawerContent = React.forwardRef<HTMLDivElement, DrawerContentProps>(
120
122
  ({ className, children, side = "bottom", ...props }, ref) => {
121
123
  const { open, onOpenChange } = useDrawer()
124
+ const [isVisible, setIsVisible] = React.useState(false)
125
+ const [isAnimating, setIsAnimating] = React.useState(false)
126
+
127
+ React.useEffect(() => {
128
+ if (open) {
129
+ // First make visible (off-screen)
130
+ setIsVisible(true)
131
+ // Use a small timeout to ensure the browser has painted the initial state
132
+ const timer = setTimeout(() => {
133
+ setIsAnimating(true)
134
+ }, 10)
135
+ return () => clearTimeout(timer)
136
+ } else {
137
+ // Start close animation
138
+ setIsAnimating(false)
139
+ // Wait for animation to complete before hiding
140
+ const timer = setTimeout(() => {
141
+ setIsVisible(false)
142
+ }, 300)
143
+ return () => clearTimeout(timer)
144
+ }
145
+ }, [open])
122
146
 
123
147
  // Close on Escape
124
148
  React.useEffect(() => {
@@ -142,11 +166,11 @@ const DrawerContent = React.forwardRef<HTMLDivElement, DrawerContentProps>(
142
166
  }
143
167
  }, [open])
144
168
 
145
- if (!open) return null
169
+ if (!isVisible) return null
146
170
 
147
171
  return (
148
172
  <>
149
- <DrawerOverlay />
173
+ <DrawerOverlay isAnimating={isAnimating} />
150
174
  <div
151
175
  ref={ref}
152
176
  className={cn(
@@ -154,9 +178,9 @@ const DrawerContent = React.forwardRef<HTMLDivElement, DrawerContentProps>(
154
178
  "transition-transform duration-300 ease-out",
155
179
  side === "bottom" && "inset-x-0 bottom-0 rounded-t-xl border-t",
156
180
  side === "top" && "inset-x-0 top-0 rounded-b-xl border-b",
157
- // Animation
158
- side === "bottom" && "animate-in slide-in-from-bottom",
159
- side === "top" && "animate-in slide-in-from-top",
181
+ // Animation states
182
+ side === "bottom" && (isAnimating ? "translate-y-0" : "translate-y-full"),
183
+ side === "top" && (isAnimating ? "translate-y-0" : "-translate-y-full"),
160
184
  className
161
185
  )}
162
186
  {...props}
@@ -4,6 +4,7 @@ import { cn } from "@/lib/utils"
4
4
  interface DropdownMenuContextValue {
5
5
  open: boolean
6
6
  onOpenChange: (open: boolean) => void
7
+ triggerRef: React.RefObject<HTMLButtonElement | null>
7
8
  }
8
9
 
9
10
  const DropdownMenuContext = React.createContext<DropdownMenuContextValue | null>(null)
@@ -16,7 +17,7 @@ interface DropdownMenuProps {
16
17
  }
17
18
 
18
19
  /**
19
- * DropdownMenu component with keyboard navigation
20
+ * DropdownMenu component with keyboard navigation and proper positioning
20
21
  *
21
22
  * @example
22
23
  * <DropdownMenu>
@@ -33,12 +34,13 @@ interface DropdownMenuProps {
33
34
  */
34
35
  function DropdownMenu({ children, open: controlledOpen, onOpenChange, defaultOpen = false }: DropdownMenuProps) {
35
36
  const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen)
37
+ const triggerRef = React.useRef<HTMLButtonElement>(null)
36
38
 
37
39
  const open = controlledOpen !== undefined ? controlledOpen : uncontrolledOpen
38
40
  const setOpen = onOpenChange || setUncontrolledOpen
39
41
 
40
42
  return (
41
- <DropdownMenuContext.Provider value={{ open, onOpenChange: setOpen }}>
43
+ <DropdownMenuContext.Provider value={{ open, onOpenChange: setOpen, triggerRef }}>
42
44
  <div className="relative inline-block text-left">
43
45
  {children}
44
46
  </div>
@@ -60,18 +62,25 @@ const DropdownMenuTrigger = React.forwardRef<HTMLButtonElement, DropdownMenuTrig
60
62
  context.onOpenChange(!context.open)
61
63
  }
62
64
 
65
+ // Combine refs
66
+ const combinedRef = (node: HTMLButtonElement | null) => {
67
+ (context.triggerRef as React.MutableRefObject<HTMLButtonElement | null>).current = node
68
+ if (typeof ref === 'function') ref(node)
69
+ else if (ref) ref.current = node
70
+ }
71
+
63
72
  if (asChild && React.isValidElement(children)) {
64
73
  return React.cloneElement(children as React.ReactElement<any>, {
65
74
  onClick: handleClick,
66
75
  "aria-expanded": context.open,
67
76
  "aria-haspopup": "menu",
68
- ref,
77
+ ref: combinedRef,
69
78
  })
70
79
  }
71
80
 
72
81
  return (
73
82
  <button
74
- ref={ref}
83
+ ref={combinedRef}
75
84
  aria-expanded={context.open}
76
85
  aria-haspopup="menu"
77
86
  onClick={handleClick}
@@ -84,53 +93,94 @@ const DropdownMenuTrigger = React.forwardRef<HTMLButtonElement, DropdownMenuTrig
84
93
  )
85
94
  DropdownMenuTrigger.displayName = "DropdownMenuTrigger"
86
95
 
87
- const DropdownMenuContent = React.forwardRef<
88
- HTMLDivElement,
89
- React.HTMLAttributes<HTMLDivElement>
90
- >(({ className, ...props }, ref) => {
91
- const context = React.useContext(DropdownMenuContext)
92
- if (!context) throw new Error("DropdownMenuContent must be used within DropdownMenu")
96
+ interface DropdownMenuContentProps extends React.HTMLAttributes<HTMLDivElement> {
97
+ /** Alignment relative to trigger: 'start' | 'center' | 'end' */
98
+ align?: 'start' | 'center' | 'end'
99
+ /** Side of trigger to open: 'bottom' | 'top' */
100
+ side?: 'bottom' | 'top'
101
+ /** Offset from trigger in pixels */
102
+ sideOffset?: number
103
+ }
93
104
 
94
- React.useEffect(() => {
95
- const handleClickOutside = () => {
96
- if (context.open) {
97
- context.onOpenChange(false)
105
+ const DropdownMenuContent = React.forwardRef<HTMLDivElement, DropdownMenuContentProps>(
106
+ ({ className, align = 'start', side = 'bottom', sideOffset = 4, ...props }, ref) => {
107
+ const context = React.useContext(DropdownMenuContext)
108
+ if (!context) throw new Error("DropdownMenuContent must be used within DropdownMenu")
109
+ const contentRef = React.useRef<HTMLDivElement>(null)
110
+
111
+ React.useEffect(() => {
112
+ const handleClickOutside = (e: MouseEvent) => {
113
+ if (context.open) {
114
+ const target = e.target as Node
115
+ const content = contentRef.current
116
+ const trigger = context.triggerRef.current
117
+
118
+ // Don't close if clicking inside content or trigger
119
+ if (content?.contains(target) || trigger?.contains(target)) {
120
+ return
121
+ }
122
+ context.onOpenChange(false)
123
+ }
98
124
  }
99
- }
100
125
 
101
- const handleEscape = (e: KeyboardEvent) => {
102
- if (e.key === "Escape" && context.open) {
103
- context.onOpenChange(false)
126
+ const handleEscape = (e: KeyboardEvent) => {
127
+ if (e.key === "Escape" && context.open) {
128
+ context.onOpenChange(false)
129
+ }
104
130
  }
105
- }
106
131
 
107
- const timer = setTimeout(() => {
108
- document.addEventListener("click", handleClickOutside)
109
- }, 0)
110
- document.addEventListener("keydown", handleEscape)
132
+ const timer = setTimeout(() => {
133
+ document.addEventListener("click", handleClickOutside)
134
+ }, 0)
135
+ document.addEventListener("keydown", handleEscape)
136
+
137
+ return () => {
138
+ clearTimeout(timer)
139
+ document.removeEventListener("click", handleClickOutside)
140
+ document.removeEventListener("keydown", handleEscape)
141
+ }
142
+ }, [context.open, context])
143
+
144
+ if (!context.open) return null
111
145
 
112
- return () => {
113
- clearTimeout(timer)
114
- document.removeEventListener("click", handleClickOutside)
115
- document.removeEventListener("keydown", handleEscape)
146
+ // Calculate alignment classes
147
+ const alignmentClasses = {
148
+ start: 'left-0',
149
+ center: 'left-1/2 -translate-x-1/2',
150
+ end: 'right-0',
116
151
  }
117
- }, [context.open, context])
118
152
 
119
- if (!context.open) return null
153
+ // Calculate side classes
154
+ const sideClasses = {
155
+ bottom: `top-full mt-${sideOffset}`,
156
+ top: `bottom-full mb-${sideOffset}`,
157
+ }
120
158
 
121
- return (
122
- <div
123
- ref={ref}
124
- role="menu"
125
- className={cn(
126
- "absolute right-0 z-50 mt-2 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
127
- className
128
- )}
129
- onClick={(e) => e.stopPropagation()}
130
- {...props}
131
- />
132
- )
133
- })
159
+ return (
160
+ <div
161
+ ref={(node) => {
162
+ (contentRef as React.MutableRefObject<HTMLDivElement | null>).current = node
163
+ if (typeof ref === 'function') ref(node)
164
+ else if (ref) ref.current = node
165
+ }}
166
+ role="menu"
167
+ aria-orientation="vertical"
168
+ className={cn(
169
+ "absolute z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
170
+ "animate-in fade-in-0 zoom-in-95",
171
+ alignmentClasses[align],
172
+ side === 'bottom' ? 'top-full' : 'bottom-full',
173
+ className
174
+ )}
175
+ style={{
176
+ marginTop: side === 'bottom' ? sideOffset : undefined,
177
+ marginBottom: side === 'top' ? sideOffset : undefined,
178
+ }}
179
+ {...props}
180
+ />
181
+ )
182
+ }
183
+ )
134
184
  DropdownMenuContent.displayName = "DropdownMenuContent"
135
185
 
136
186
  const DropdownMenuItem = React.forwardRef<
@@ -188,8 +238,6 @@ const DropdownMenuCheckboxItem = React.forwardRef<
188
238
  HTMLDivElement,
189
239
  React.HTMLAttributes<HTMLDivElement> & { checked?: boolean; disabled?: boolean }
190
240
  >(({ className, children, checked, disabled, onClick, ...props }, ref) => {
191
- const context = React.useContext(DropdownMenuContext)
192
-
193
241
  const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
194
242
  if (disabled) return
195
243
  onClick?.(e)