Use FloatingPortal to position menu above all other contents (#1136)

This commit is contained in:
Evan Simkowitz 2024-10-24 23:32:54 -07:00 committed by GitHub
parent 20d333f724
commit 34e4ffc429
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 47 additions and 46 deletions

View File

@ -1,6 +1,5 @@
.menu { .menu {
position: absolute; position: absolute;
z-index: 1000;
display: flex; display: flex;
max-width: 400px; max-width: 400px;
padding: 2px; padding: 2px;

View File

@ -1,7 +1,7 @@
// Copyright 2024, Command Line Inc. // Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
import { type Placement, useDismiss, useFloating, useInteractions } from "@floating-ui/react"; import { FloatingPortal, type Placement, useDismiss, useFloating, useInteractions } from "@floating-ui/react";
import clsx from "clsx"; import clsx from "clsx";
import { createRef, Fragment, memo, ReactNode, useRef, useState } from "react"; import { createRef, Fragment, memo, ReactNode, useRef, useState } from "react";
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
@ -141,53 +141,55 @@ const MenuComponent = memo(
</div> </div>
{isOpen && ( {isOpen && (
<div <FloatingPortal>
className={clsx("menu", className)} <div
ref={refs.setFloating} className={clsx("menu", className)}
style={floatingStyles} ref={refs.setFloating}
{...getFloatingProps()} style={floatingStyles}
> {...getFloatingProps()}
{items.map((item, index) => { >
const key = `${index}`; {items.map((item, index) => {
const isActive = hoveredItems.includes(key); const key = `${index}`;
const isActive = hoveredItems.includes(key);
const menuItemProps = { const menuItemProps = {
className: clsx("menu-item", { active: isActive }), className: clsx("menu-item", { active: isActive }),
onMouseEnter: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => onMouseEnter: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) =>
handleMouseEnterItem(event, null, index, item), handleMouseEnterItem(event, null, index, item),
onClick: (e: React.MouseEvent<HTMLDivElement>) => handleOnClick(e, item), onClick: (e: React.MouseEvent<HTMLDivElement>) => handleOnClick(e, item),
}; };
const renderedItem = renderMenuItem ? ( const renderedItem = renderMenuItem ? (
renderMenuItem(item, menuItemProps) renderMenuItem(item, menuItemProps)
) : ( ) : (
<div key={key} {...menuItemProps}> <div key={key} {...menuItemProps}>
<span className="label">{item.label}</span> <span className="label">{item.label}</span>
{item.subItems && <i className="fa-sharp fa-solid fa-chevron-right"></i>} {item.subItems && <i className="fa-sharp fa-solid fa-chevron-right"></i>}
</div> </div>
); );
return ( return (
<Fragment key={key}> <Fragment key={key}>
{renderedItem} {renderedItem}
{visibleSubMenus[key]?.visible && item.subItems && ( {visibleSubMenus[key]?.visible && item.subItems && (
<SubMenu <SubMenu
subItems={item.subItems} subItems={item.subItems}
parentKey={key} parentKey={key}
subMenuPosition={subMenuPosition} subMenuPosition={subMenuPosition}
visibleSubMenus={visibleSubMenus} visibleSubMenus={visibleSubMenus}
hoveredItems={hoveredItems} hoveredItems={hoveredItems}
handleMouseEnterItem={handleMouseEnterItem} handleMouseEnterItem={handleMouseEnterItem}
handleOnClick={handleOnClick} handleOnClick={handleOnClick}
subMenuRefs={subMenuRefs} subMenuRefs={subMenuRefs}
renderMenu={renderMenu} renderMenu={renderMenu}
renderMenuItem={renderMenuItem} renderMenuItem={renderMenuItem}
/> />
)} )}
</Fragment> </Fragment>
); );
})} })}
</div> </div>
</FloatingPortal>
)} )}
</> </>
); );