@srcroot/ui 0.0.49 → 0.0.52
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/dist/index.js +24 -16
- package/package.json +2 -1
- package/src/registry/themes/v3/glass.css +154 -0
- package/src/registry/themes/v4/glass.css +181 -0
- package/src/registry/ui/alert-dialog.tsx +15 -10
- package/src/registry/ui/breadcrumb.tsx +4 -8
- package/src/registry/ui/button.tsx +7 -14
- package/src/registry/ui/collapsible.tsx +4 -9
- package/src/registry/ui/dialog.tsx +13 -10
- package/src/registry/ui/drawer.tsx +34 -10
- package/src/registry/ui/dropdown-menu.tsx +75 -31
- package/src/registry/ui/hover-card.tsx +92 -34
- package/src/registry/ui/popover.tsx +108 -20
- package/src/registry/ui/select.tsx +139 -39
- package/src/registry/ui/sheet.tsx +27 -10
- package/src/registry/ui/sidebar.tsx +28 -78
- package/src/registry/ui/slot.tsx +69 -0
- package/src/registry/ui/tooltip.tsx +15 -14
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import * as React from "react"
|
|
4
|
+
import { createPortal } from "react-dom"
|
|
4
5
|
import { cn } from "@/lib/utils"
|
|
6
|
+
import { Slot } from "@/components/ui/slot"
|
|
5
7
|
|
|
6
8
|
// Drawer Context
|
|
7
9
|
interface DrawerContextValue {
|
|
@@ -27,6 +29,25 @@ interface DrawerProps {
|
|
|
27
29
|
defaultOpen?: boolean
|
|
28
30
|
}
|
|
29
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Drawer component for mobile-first bottom sheets
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* <Drawer>
|
|
37
|
+
* <DrawerTrigger>Open</DrawerTrigger>
|
|
38
|
+
* <DrawerContent>
|
|
39
|
+
* <DrawerHeader>
|
|
40
|
+
* <DrawerTitle>Title</DrawerTitle>
|
|
41
|
+
* <DrawerDescription>Description</DrawerDescription>
|
|
42
|
+
* </DrawerHeader>
|
|
43
|
+
* <div>Content</div>
|
|
44
|
+
* <DrawerFooter>
|
|
45
|
+
* <Button>Submit</Button>
|
|
46
|
+
* <DrawerClose>Cancel</DrawerClose>
|
|
47
|
+
* </DrawerFooter>
|
|
48
|
+
* </DrawerContent>
|
|
49
|
+
* </Drawer>
|
|
50
|
+
*/
|
|
30
51
|
const Drawer = ({ children, open: controlledOpen, onOpenChange, defaultOpen = false }: DrawerProps) => {
|
|
31
52
|
const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen)
|
|
32
53
|
const open = controlledOpen ?? uncontrolledOpen
|
|
@@ -53,17 +74,12 @@ const DrawerTrigger = React.forwardRef<HTMLButtonElement, DrawerTriggerProps>(
|
|
|
53
74
|
onOpenChange(true)
|
|
54
75
|
}
|
|
55
76
|
|
|
56
|
-
|
|
57
|
-
return React.cloneElement(children as React.ReactElement<any>, {
|
|
58
|
-
onClick: handleClick,
|
|
59
|
-
ref,
|
|
60
|
-
})
|
|
61
|
-
}
|
|
77
|
+
const Comp = asChild ? Slot : "button"
|
|
62
78
|
|
|
63
79
|
return (
|
|
64
|
-
<
|
|
80
|
+
<Comp ref={ref} onClick={handleClick} {...props}>
|
|
65
81
|
{children}
|
|
66
|
-
</
|
|
82
|
+
</Comp>
|
|
67
83
|
)
|
|
68
84
|
}
|
|
69
85
|
)
|
|
@@ -166,9 +182,16 @@ const DrawerContent = React.forwardRef<HTMLDivElement, DrawerContentProps>(
|
|
|
166
182
|
}
|
|
167
183
|
}, [open])
|
|
168
184
|
|
|
185
|
+
const [mounted, setMounted] = React.useState(false)
|
|
186
|
+
|
|
187
|
+
React.useEffect(() => {
|
|
188
|
+
setMounted(true)
|
|
189
|
+
}, [])
|
|
190
|
+
|
|
169
191
|
if (!isVisible) return null
|
|
192
|
+
if (!mounted) return null
|
|
170
193
|
|
|
171
|
-
return (
|
|
194
|
+
return createPortal(
|
|
172
195
|
<>
|
|
173
196
|
<DrawerOverlay isAnimating={isAnimating} />
|
|
174
197
|
<div
|
|
@@ -194,7 +217,8 @@ const DrawerContent = React.forwardRef<HTMLDivElement, DrawerContentProps>(
|
|
|
194
217
|
<div className="mx-auto mb-4 h-1.5 w-12 rounded-full bg-muted" />
|
|
195
218
|
)}
|
|
196
219
|
</div>
|
|
197
|
-
|
|
220
|
+
</>,
|
|
221
|
+
document.body
|
|
198
222
|
)
|
|
199
223
|
}
|
|
200
224
|
)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as React from "react"
|
|
2
|
+
import { createPortal } from "react-dom"
|
|
2
3
|
import { cn } from "@/lib/utils"
|
|
4
|
+
import { Slot } from "@/components/ui/slot"
|
|
3
5
|
|
|
4
6
|
interface DropdownMenuContextValue {
|
|
5
7
|
open: boolean
|
|
@@ -66,22 +68,21 @@ const DropdownMenuTrigger = React.forwardRef<HTMLButtonElement, DropdownMenuTrig
|
|
|
66
68
|
|
|
67
69
|
// Combine refs
|
|
68
70
|
const combinedRef = (node: HTMLButtonElement | null) => {
|
|
69
|
-
(context.triggerRef as
|
|
71
|
+
(context.triggerRef as any).current = node
|
|
70
72
|
if (typeof ref === 'function') ref(node)
|
|
71
73
|
else if (ref) ref.current = node
|
|
72
74
|
}
|
|
73
75
|
|
|
74
|
-
if (asChild
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
"aria-haspopup": "menu",
|
|
79
|
-
ref: combinedRef,
|
|
80
|
-
})
|
|
76
|
+
if (asChild) {
|
|
77
|
+
// For asChild, we need to manually make sure the ref is passed correctly.
|
|
78
|
+
// Slot handles merging the passed ref with the child's ref.
|
|
79
|
+
// But here we're passing `combinedRef` as the ref to Slot.
|
|
81
80
|
}
|
|
82
81
|
|
|
82
|
+
const Comp = asChild ? Slot : "button"
|
|
83
|
+
|
|
83
84
|
return (
|
|
84
|
-
<
|
|
85
|
+
<Comp
|
|
85
86
|
ref={combinedRef}
|
|
86
87
|
aria-expanded={context.open}
|
|
87
88
|
aria-haspopup="menu"
|
|
@@ -89,7 +90,7 @@ const DropdownMenuTrigger = React.forwardRef<HTMLButtonElement, DropdownMenuTrig
|
|
|
89
90
|
{...props}
|
|
90
91
|
>
|
|
91
92
|
{children}
|
|
92
|
-
</
|
|
93
|
+
</Comp>
|
|
93
94
|
)
|
|
94
95
|
}
|
|
95
96
|
)
|
|
@@ -102,18 +103,24 @@ interface DropdownMenuContentProps extends React.HTMLAttributes<HTMLDivElement>
|
|
|
102
103
|
side?: 'bottom' | 'top'
|
|
103
104
|
/** Offset from trigger in pixels */
|
|
104
105
|
sideOffset?: number
|
|
106
|
+
/** Whether to render in a portal (default: true) */
|
|
107
|
+
portal?: boolean
|
|
105
108
|
}
|
|
106
109
|
|
|
107
110
|
const DropdownMenuContent = React.forwardRef<HTMLDivElement, DropdownMenuContentProps>(
|
|
108
|
-
({ className, align = 'start', side = 'bottom', sideOffset = 4, ...props }, ref) => {
|
|
111
|
+
({ className, align = 'start', side = 'bottom', sideOffset = 4, portal = true, ...props }, ref) => {
|
|
109
112
|
const context = React.useContext(DropdownMenuContext)
|
|
110
113
|
if (!context) throw new Error("DropdownMenuContent must be used within DropdownMenu")
|
|
111
114
|
const contentRef = React.useRef<HTMLDivElement>(null)
|
|
115
|
+
const [position, setPosition] = React.useState({ top: 0, left: 0 })
|
|
116
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
112
117
|
const [currentSide, setCurrentSide] = React.useState(side)
|
|
113
118
|
|
|
119
|
+
// Reset scroll on mount/unmount if needed, but mainly we just need a portal container
|
|
120
|
+
const [mounted, setMounted] = React.useState(false)
|
|
114
121
|
React.useEffect(() => {
|
|
115
|
-
|
|
116
|
-
}, [
|
|
122
|
+
setMounted(true)
|
|
123
|
+
}, [])
|
|
117
124
|
|
|
118
125
|
React.useEffect(() => {
|
|
119
126
|
const handleClickOutside = (e: MouseEvent) => {
|
|
@@ -141,30 +148,56 @@ const DropdownMenuContent = React.forwardRef<HTMLDivElement, DropdownMenuContent
|
|
|
141
148
|
const triggerRect = context.triggerRef.current.getBoundingClientRect()
|
|
142
149
|
const contentRect = contentRef.current.getBoundingClientRect()
|
|
143
150
|
const viewportHeight = window.innerHeight
|
|
151
|
+
const viewportWidth = window.innerWidth
|
|
152
|
+
|
|
153
|
+
let top = 0
|
|
154
|
+
let left = 0
|
|
155
|
+
let usedSide = side
|
|
144
156
|
|
|
157
|
+
// Vertical positioning logic
|
|
145
158
|
const spaceBelow = viewportHeight - triggerRect.bottom
|
|
146
159
|
const spaceAbove = triggerRect.top
|
|
147
160
|
const neededHeight = contentRect.height + sideOffset
|
|
148
161
|
|
|
149
162
|
if (side === 'bottom') {
|
|
150
163
|
if (spaceBelow < neededHeight && spaceAbove > neededHeight) {
|
|
151
|
-
|
|
152
|
-
} else {
|
|
153
|
-
setCurrentSide('bottom')
|
|
164
|
+
usedSide = 'top'
|
|
154
165
|
}
|
|
155
166
|
} else if (side === 'top') {
|
|
156
167
|
if (spaceAbove < neededHeight && spaceBelow > neededHeight) {
|
|
157
|
-
|
|
158
|
-
} else {
|
|
159
|
-
setCurrentSide('top')
|
|
168
|
+
usedSide = 'bottom'
|
|
160
169
|
}
|
|
161
170
|
}
|
|
171
|
+
setCurrentSide(usedSide)
|
|
172
|
+
|
|
173
|
+
if (usedSide === 'bottom') {
|
|
174
|
+
top = triggerRect.bottom + sideOffset
|
|
175
|
+
} else {
|
|
176
|
+
top = triggerRect.top - contentRect.height - sideOffset
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Horizontal positioning logic (Alignment)
|
|
180
|
+
if (align === 'start') {
|
|
181
|
+
left = triggerRect.left
|
|
182
|
+
} else if (align === 'end') {
|
|
183
|
+
left = triggerRect.right - contentRect.width
|
|
184
|
+
} else {
|
|
185
|
+
// center
|
|
186
|
+
left = triggerRect.left + (triggerRect.width - contentRect.width) / 2
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Collision detection / clamping for X axis
|
|
190
|
+
if (left < 4) left = 4
|
|
191
|
+
if (left + contentRect.width > viewportWidth - 4) {
|
|
192
|
+
left = viewportWidth - contentRect.width - 4
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
setPosition({ top, left })
|
|
162
196
|
}
|
|
163
197
|
}
|
|
164
198
|
|
|
165
199
|
if (context.open) {
|
|
166
|
-
// Check position immediately after render cycle
|
|
167
|
-
// Using requestAnimationFrame for better timing in layout cycle
|
|
200
|
+
// Check position immediately after render cycle
|
|
168
201
|
requestAnimationFrame(checkPosition)
|
|
169
202
|
}
|
|
170
203
|
|
|
@@ -173,7 +206,7 @@ const DropdownMenuContent = React.forwardRef<HTMLDivElement, DropdownMenuContent
|
|
|
173
206
|
}, 0)
|
|
174
207
|
document.addEventListener("keydown", handleEscape)
|
|
175
208
|
window.addEventListener("resize", checkPosition)
|
|
176
|
-
window.addEventListener("scroll", checkPosition, true)
|
|
209
|
+
window.addEventListener("scroll", checkPosition, true)
|
|
177
210
|
|
|
178
211
|
return () => {
|
|
179
212
|
clearTimeout(timer)
|
|
@@ -182,40 +215,51 @@ const DropdownMenuContent = React.forwardRef<HTMLDivElement, DropdownMenuContent
|
|
|
182
215
|
window.removeEventListener("resize", checkPosition)
|
|
183
216
|
window.removeEventListener("scroll", checkPosition, true)
|
|
184
217
|
}
|
|
185
|
-
}, [context.open, context, side, sideOffset])
|
|
218
|
+
}, [context.open, context, side, sideOffset, align])
|
|
186
219
|
|
|
187
220
|
if (!context.open) return null
|
|
221
|
+
if (portal && !mounted) return null
|
|
188
222
|
|
|
189
|
-
//
|
|
223
|
+
// Alignment classes are ignored if we use portal/fixed positioning,
|
|
224
|
+
// but kept for non-portal usage if someone opts out.
|
|
190
225
|
const alignmentClasses = {
|
|
191
226
|
start: 'left-0',
|
|
192
227
|
center: 'left-1/2 -translate-x-1/2',
|
|
193
228
|
end: 'right-0',
|
|
194
229
|
}
|
|
195
230
|
|
|
196
|
-
|
|
231
|
+
const content = (
|
|
197
232
|
<div
|
|
198
233
|
ref={(node) => {
|
|
199
|
-
(contentRef as
|
|
234
|
+
(contentRef as any).current = node
|
|
200
235
|
if (typeof ref === 'function') ref(node)
|
|
201
236
|
else if (ref) ref.current = node
|
|
202
237
|
}}
|
|
203
238
|
role="menu"
|
|
204
239
|
aria-orientation="vertical"
|
|
205
240
|
className={cn(
|
|
206
|
-
"
|
|
241
|
+
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
|
|
207
242
|
"animate-in fade-in-0 zoom-in-95",
|
|
208
|
-
|
|
209
|
-
|
|
243
|
+
!portal && "absolute", // Use absolute if not portal
|
|
244
|
+
!portal && alignmentClasses[align],
|
|
245
|
+
!portal && (side === 'bottom' ? 'top-full mt-1' : 'bottom-full mb-1'),
|
|
246
|
+
portal && "fixed", // Use fixed if portal
|
|
210
247
|
className
|
|
211
248
|
)}
|
|
212
249
|
style={{
|
|
213
|
-
|
|
214
|
-
|
|
250
|
+
top: portal ? position.top : undefined,
|
|
251
|
+
left: portal ? position.left : undefined,
|
|
252
|
+
...props.style
|
|
215
253
|
}}
|
|
216
254
|
{...props}
|
|
217
255
|
/>
|
|
218
256
|
)
|
|
257
|
+
|
|
258
|
+
if (portal) {
|
|
259
|
+
return createPortal(content, document.body)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return content
|
|
219
263
|
}
|
|
220
264
|
)
|
|
221
265
|
DropdownMenuContent.displayName = "DropdownMenuContent"
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import * as React from "react"
|
|
4
|
+
import { createPortal } from "react-dom"
|
|
4
5
|
import { cn } from "@/lib/utils"
|
|
6
|
+
import { Slot } from "@/components/ui/slot"
|
|
5
7
|
|
|
6
8
|
// HoverCard Context
|
|
7
9
|
interface HoverCardContextValue {
|
|
@@ -26,6 +28,19 @@ interface HoverCardProps {
|
|
|
26
28
|
closeDelay?: number
|
|
27
29
|
}
|
|
28
30
|
|
|
31
|
+
/**
|
|
32
|
+
* HoverCard component for displaying content on hover
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* <HoverCard>
|
|
36
|
+
* <HoverCardTrigger asChild>
|
|
37
|
+
* <Button variant="link">@nextjs</Button>
|
|
38
|
+
* </HoverCardTrigger>
|
|
39
|
+
* <HoverCardContent>
|
|
40
|
+
* The React Framework – created and maintained by @vercel.
|
|
41
|
+
* </HoverCardContent>
|
|
42
|
+
* </HoverCard>
|
|
43
|
+
*/
|
|
29
44
|
const HoverCard = ({ children, openDelay = 200, closeDelay = 300 }: HoverCardProps) => {
|
|
30
45
|
const [open, setOpen] = React.useState(false)
|
|
31
46
|
const triggerRef = React.useRef<HTMLDivElement>(null)
|
|
@@ -81,14 +96,24 @@ const HoverCardTrigger = React.forwardRef<HTMLDivElement, HoverCardTriggerProps>
|
|
|
81
96
|
({ children, asChild, className, ...props }, ref) => {
|
|
82
97
|
const { triggerRef } = useHoverCard()
|
|
83
98
|
|
|
99
|
+
// Merge refs manually since we have two refs to attach (triggerRef and ref)
|
|
100
|
+
const combinedRef = React.useCallback((node: HTMLDivElement | null) => {
|
|
101
|
+
if (triggerRef) (triggerRef as any).current = node
|
|
102
|
+
|
|
103
|
+
if (typeof ref === "function") ref(node)
|
|
104
|
+
else if (ref) (ref as any).current = node
|
|
105
|
+
}, [triggerRef, ref])
|
|
106
|
+
|
|
107
|
+
const Comp = asChild ? Slot : "div"
|
|
108
|
+
|
|
84
109
|
return (
|
|
85
|
-
<
|
|
86
|
-
ref={
|
|
110
|
+
<Comp
|
|
111
|
+
ref={combinedRef}
|
|
87
112
|
className={cn("inline-block cursor-pointer", className)}
|
|
88
113
|
{...props}
|
|
89
114
|
>
|
|
90
115
|
{children}
|
|
91
|
-
</
|
|
116
|
+
</Comp>
|
|
92
117
|
)
|
|
93
118
|
}
|
|
94
119
|
)
|
|
@@ -101,63 +126,96 @@ interface HoverCardContentProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
101
126
|
sideOffset?: number
|
|
102
127
|
}
|
|
103
128
|
|
|
104
|
-
const HoverCardContent = React.forwardRef<
|
|
105
|
-
|
|
129
|
+
const HoverCardContent = React.forwardRef<
|
|
130
|
+
HTMLDivElement,
|
|
131
|
+
HoverCardContentProps & { portal?: boolean }
|
|
132
|
+
>(
|
|
133
|
+
({ children, className, align = "center", side = "bottom", sideOffset = 4, portal = true, ...props }, ref) => {
|
|
106
134
|
const { open, triggerRef } = useHoverCard()
|
|
107
135
|
const [position, setPosition] = React.useState({ top: 0, left: 0 })
|
|
108
136
|
const contentRef = React.useRef<HTMLDivElement>(null)
|
|
137
|
+
const [mounted, setMounted] = React.useState(false)
|
|
109
138
|
|
|
110
139
|
React.useEffect(() => {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const triggerRect = triggerRef.current.getBoundingClientRect()
|
|
114
|
-
const contentRect = contentRef.current.getBoundingClientRect()
|
|
140
|
+
setMounted(true)
|
|
141
|
+
}, [])
|
|
115
142
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
// Calculate vertical position
|
|
120
|
-
if (side === "bottom") {
|
|
121
|
-
top = triggerRect.bottom + sideOffset
|
|
122
|
-
} else {
|
|
123
|
-
top = triggerRect.top - contentRect.height - sideOffset
|
|
124
|
-
}
|
|
143
|
+
React.useEffect(() => {
|
|
144
|
+
if (!open || !triggerRef.current || !contentRef.current) return
|
|
125
145
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
left =
|
|
146
|
+
const checkPosition = () => {
|
|
147
|
+
if (!triggerRef.current || !contentRef.current) return
|
|
148
|
+
const triggerRect = triggerRef.current.getBoundingClientRect()
|
|
149
|
+
const contentRect = contentRef.current.getBoundingClientRect()
|
|
150
|
+
|
|
151
|
+
let top = 0
|
|
152
|
+
let left = 0
|
|
153
|
+
|
|
154
|
+
// Calculate vertical position
|
|
155
|
+
if (side === "bottom") {
|
|
156
|
+
top = triggerRect.bottom + sideOffset
|
|
157
|
+
} else {
|
|
158
|
+
top = triggerRect.top - contentRect.height - sideOffset
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Calculate horizontal position
|
|
162
|
+
if (align === "start") {
|
|
163
|
+
left = triggerRect.left
|
|
164
|
+
} else if (align === "end") {
|
|
165
|
+
left = triggerRect.right - contentRect.width
|
|
166
|
+
} else {
|
|
167
|
+
left = triggerRect.left + (triggerRect.width - contentRect.width) / 2
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Clamp to viewport
|
|
171
|
+
left = Math.max(8, Math.min(left, window.innerWidth - contentRect.width - 8))
|
|
172
|
+
top = Math.max(8, Math.min(top, window.innerHeight - contentRect.height - 8))
|
|
173
|
+
|
|
174
|
+
setPosition({ top, left })
|
|
133
175
|
}
|
|
134
176
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
177
|
+
checkPosition()
|
|
178
|
+
window.addEventListener('resize', checkPosition)
|
|
179
|
+
window.addEventListener('scroll', checkPosition, true)
|
|
138
180
|
|
|
139
|
-
|
|
181
|
+
return () => {
|
|
182
|
+
window.removeEventListener('resize', checkPosition)
|
|
183
|
+
window.removeEventListener('scroll', checkPosition, true)
|
|
184
|
+
}
|
|
140
185
|
}, [open, triggerRef, align, side, sideOffset])
|
|
141
186
|
|
|
142
187
|
if (!open) return null
|
|
143
188
|
|
|
144
|
-
|
|
189
|
+
const content = (
|
|
145
190
|
<div
|
|
146
|
-
ref={
|
|
191
|
+
ref={(node) => {
|
|
192
|
+
(contentRef as any).current = node
|
|
193
|
+
if (typeof ref === 'function') ref(node)
|
|
194
|
+
else if (ref) (ref as any).current = node
|
|
195
|
+
}}
|
|
147
196
|
className={cn(
|
|
148
|
-
"
|
|
197
|
+
"z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none",
|
|
149
198
|
"animate-in fade-in-0 zoom-in-95",
|
|
199
|
+
!portal && "absolute",
|
|
200
|
+
portal && "fixed",
|
|
150
201
|
className
|
|
151
202
|
)}
|
|
152
203
|
style={{
|
|
153
|
-
top: position.top,
|
|
154
|
-
left: position.left,
|
|
204
|
+
top: portal ? position.top : undefined,
|
|
205
|
+
left: portal ? position.left : undefined,
|
|
206
|
+
...props.style
|
|
155
207
|
}}
|
|
156
208
|
{...props}
|
|
157
209
|
>
|
|
158
210
|
{children}
|
|
159
211
|
</div>
|
|
160
212
|
)
|
|
213
|
+
|
|
214
|
+
if (portal && mounted) {
|
|
215
|
+
return createPortal(content, document.body)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return content
|
|
161
219
|
}
|
|
162
220
|
)
|
|
163
221
|
HoverCardContent.displayName = "HoverCardContent"
|