@orsetra/shared-ui 1.1.25 → 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)
|
|
@@ -105,12 +119,13 @@ export function MainSidebar({
|
|
|
105
119
|
<nav className="space-y-2">
|
|
106
120
|
{mainMenuItems.map((item) => {
|
|
107
121
|
const Icon = item.icon
|
|
122
|
+
const hasSubMenu = sidebarMenus[item.id]?.length > 0
|
|
108
123
|
return (
|
|
109
124
|
<div
|
|
110
125
|
key={item.id}
|
|
111
126
|
className="relative"
|
|
112
|
-
onMouseEnter={() =>
|
|
113
|
-
onMouseLeave={() =>
|
|
127
|
+
onMouseEnter={() => hasSubMenu && handleFlyoutMouseEnter(item.id)}
|
|
128
|
+
onMouseLeave={() => hasSubMenu && handleFlyoutMouseLeave()}
|
|
114
129
|
>
|
|
115
130
|
<button
|
|
116
131
|
onClick={() => handleMenuClick(item.id)}
|
|
@@ -132,8 +147,14 @@ export function MainSidebar({
|
|
|
132
147
|
{!isMinimized && <span className="text-base">{item.label}</span>}
|
|
133
148
|
</button>
|
|
134
149
|
|
|
135
|
-
{
|
|
136
|
-
<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" />
|
|
137
158
|
<div className="px-4 py-2 border-b border-ui-border">
|
|
138
159
|
<h3 className="text-sm font-semibold text-text-primary">{item.label}</h3>
|
|
139
160
|
</div>
|