@orsetra/shared-ui 1.1.24 → 1.1.26
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.
|
@@ -35,6 +35,20 @@ export function MainSidebar({
|
|
|
35
35
|
}: MainSidebarProps) {
|
|
36
36
|
const isMinimized = mode === 'minimized'
|
|
37
37
|
const [hoveredMenu, setHoveredMenu] = React.useState<string | null>(null)
|
|
38
|
+
const closeTimeoutRef = React.useRef<ReturnType<typeof setTimeout> | undefined>(undefined)
|
|
39
|
+
|
|
40
|
+
React.useEffect(() => {
|
|
41
|
+
return () => { if (closeTimeoutRef.current) clearTimeout(closeTimeoutRef.current) }
|
|
42
|
+
}, [])
|
|
43
|
+
|
|
44
|
+
const handleFlyoutMouseEnter = (menuId: string) => {
|
|
45
|
+
if (closeTimeoutRef.current) clearTimeout(closeTimeoutRef.current)
|
|
46
|
+
setHoveredMenu(menuId)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const handleFlyoutMouseLeave = () => {
|
|
50
|
+
closeTimeoutRef.current = setTimeout(() => setHoveredMenu(null), 150)
|
|
51
|
+
}
|
|
38
52
|
|
|
39
53
|
const handleMenuClick = (menuId: string) => {
|
|
40
54
|
onMenuSelect(menuId)
|
|
@@ -43,21 +57,12 @@ export function MainSidebar({
|
|
|
43
57
|
onSecondarySidebarOpen()
|
|
44
58
|
}
|
|
45
59
|
|
|
46
|
-
const subMenus = sidebarMenus[menuId]
|
|
47
|
-
if (subMenus && subMenus.length > 0) {
|
|
48
|
-
const targetUrl = subMenus[0].href
|
|
49
|
-
const path = targetUrl.startsWith('http://') || targetUrl.startsWith('https://')
|
|
50
|
-
? new URL(targetUrl).pathname
|
|
51
|
-
: targetUrl
|
|
52
|
-
window.location.href = path
|
|
53
|
-
} else {
|
|
54
60
|
const targetUrl = `${main_base_url}/${menuId}`
|
|
55
61
|
const path = targetUrl.startsWith('http://') || targetUrl.startsWith('https://')
|
|
56
62
|
? new URL(targetUrl).pathname
|
|
57
63
|
: targetUrl
|
|
58
64
|
window.location.href = path
|
|
59
|
-
|
|
60
|
-
|
|
65
|
+
|
|
61
66
|
if (!isMinimized) {
|
|
62
67
|
onToggle()
|
|
63
68
|
}
|
|
@@ -114,12 +119,13 @@ export function MainSidebar({
|
|
|
114
119
|
<nav className="space-y-2">
|
|
115
120
|
{mainMenuItems.map((item) => {
|
|
116
121
|
const Icon = item.icon
|
|
122
|
+
const hasSubMenu = sidebarMenus[item.id]?.length > 0
|
|
117
123
|
return (
|
|
118
124
|
<div
|
|
119
125
|
key={item.id}
|
|
120
126
|
className="relative"
|
|
121
|
-
onMouseEnter={() =>
|
|
122
|
-
onMouseLeave={() =>
|
|
127
|
+
onMouseEnter={() => hasSubMenu && handleFlyoutMouseEnter(item.id)}
|
|
128
|
+
onMouseLeave={() => hasSubMenu && handleFlyoutMouseLeave()}
|
|
123
129
|
>
|
|
124
130
|
<button
|
|
125
131
|
onClick={() => handleMenuClick(item.id)}
|
|
@@ -141,8 +147,14 @@ export function MainSidebar({
|
|
|
141
147
|
{!isMinimized && <span className="text-base">{item.label}</span>}
|
|
142
148
|
</button>
|
|
143
149
|
|
|
144
|
-
{
|
|
145
|
-
<div
|
|
150
|
+
{hoveredMenu === item.id && hasSubMenu && (
|
|
151
|
+
<div
|
|
152
|
+
className="absolute left-full top-0 ml-2 bg-white border border-ui-border rounded-lg shadow-xl z-50 min-w-[200px] py-2"
|
|
153
|
+
onMouseEnter={() => handleFlyoutMouseEnter(item.id)}
|
|
154
|
+
onMouseLeave={handleFlyoutMouseLeave}
|
|
155
|
+
>
|
|
156
|
+
{/* Arrow pointing left toward hovered item */}
|
|
157
|
+
<div className="absolute -left-[5px] top-[18px] w-[10px] h-[10px] bg-white border-l border-t border-ui-border -rotate-45" />
|
|
146
158
|
<div className="px-4 py-2 border-b border-ui-border">
|
|
147
159
|
<h3 className="text-sm font-semibold text-text-primary">{item.label}</h3>
|
|
148
160
|
</div>
|