Skip to content

Commit 34e4ffc

Browse files
authored
Use FloatingPortal to position menu above all other contents (#1136)
1 parent 20d333f commit 34e4ffc

File tree

2 files changed

+50
-49
lines changed

2 files changed

+50
-49
lines changed

frontend/app/element/menu.less

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
.menu {
22
position: absolute;
3-
z-index: 1000;
43
display: flex;
54
max-width: 400px;
65
padding: 2px;

frontend/app/element/menu.tsx

Lines changed: 50 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2024, Command Line Inc.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
import { type Placement, useDismiss, useFloating, useInteractions } from "@floating-ui/react";
4+
import { FloatingPortal, type Placement, useDismiss, useFloating, useInteractions } from "@floating-ui/react";
55
import clsx from "clsx";
66
import { createRef, Fragment, memo, ReactNode, useRef, useState } from "react";
77
import ReactDOM from "react-dom";
@@ -141,53 +141,55 @@ const MenuComponent = memo(
141141
</div>
142142

143143
{isOpen && (
144-
<div
145-
className={clsx("menu", className)}
146-
ref={refs.setFloating}
147-
style={floatingStyles}
148-
{...getFloatingProps()}
149-
>
150-
{items.map((item, index) => {
151-
const key = `${index}`;
152-
const isActive = hoveredItems.includes(key);
153-
154-
const menuItemProps = {
155-
className: clsx("menu-item", { active: isActive }),
156-
onMouseEnter: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) =>
157-
handleMouseEnterItem(event, null, index, item),
158-
onClick: (e: React.MouseEvent<HTMLDivElement>) => handleOnClick(e, item),
159-
};
160-
161-
const renderedItem = renderMenuItem ? (
162-
renderMenuItem(item, menuItemProps)
163-
) : (
164-
<div key={key} {...menuItemProps}>
165-
<span className="label">{item.label}</span>
166-
{item.subItems && <i className="fa-sharp fa-solid fa-chevron-right"></i>}
167-
</div>
168-
);
169-
170-
return (
171-
<Fragment key={key}>
172-
{renderedItem}
173-
{visibleSubMenus[key]?.visible && item.subItems && (
174-
<SubMenu
175-
subItems={item.subItems}
176-
parentKey={key}
177-
subMenuPosition={subMenuPosition}
178-
visibleSubMenus={visibleSubMenus}
179-
hoveredItems={hoveredItems}
180-
handleMouseEnterItem={handleMouseEnterItem}
181-
handleOnClick={handleOnClick}
182-
subMenuRefs={subMenuRefs}
183-
renderMenu={renderMenu}
184-
renderMenuItem={renderMenuItem}
185-
/>
186-
)}
187-
</Fragment>
188-
);
189-
})}
190-
</div>
144+
<FloatingPortal>
145+
<div
146+
className={clsx("menu", className)}
147+
ref={refs.setFloating}
148+
style={floatingStyles}
149+
{...getFloatingProps()}
150+
>
151+
{items.map((item, index) => {
152+
const key = `${index}`;
153+
const isActive = hoveredItems.includes(key);
154+
155+
const menuItemProps = {
156+
className: clsx("menu-item", { active: isActive }),
157+
onMouseEnter: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) =>
158+
handleMouseEnterItem(event, null, index, item),
159+
onClick: (e: React.MouseEvent<HTMLDivElement>) => handleOnClick(e, item),
160+
};
161+
162+
const renderedItem = renderMenuItem ? (
163+
renderMenuItem(item, menuItemProps)
164+
) : (
165+
<div key={key} {...menuItemProps}>
166+
<span className="label">{item.label}</span>
167+
{item.subItems && <i className="fa-sharp fa-solid fa-chevron-right"></i>}
168+
</div>
169+
);
170+
171+
return (
172+
<Fragment key={key}>
173+
{renderedItem}
174+
{visibleSubMenus[key]?.visible && item.subItems && (
175+
<SubMenu
176+
subItems={item.subItems}
177+
parentKey={key}
178+
subMenuPosition={subMenuPosition}
179+
visibleSubMenus={visibleSubMenus}
180+
hoveredItems={hoveredItems}
181+
handleMouseEnterItem={handleMouseEnterItem}
182+
handleOnClick={handleOnClick}
183+
subMenuRefs={subMenuRefs}
184+
renderMenu={renderMenu}
185+
renderMenuItem={renderMenuItem}
186+
/>
187+
)}
188+
</Fragment>
189+
);
190+
})}
191+
</div>
192+
</FloatingPortal>
191193
)}
192194
</>
193195
);

0 commit comments

Comments
 (0)