mirror of
https://github.com/wavetermdev/backup.git
synced 2026-08-05 13:57:07 -07:00
hide if click outside the menus
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
line-height: normal;
|
||||
letter-spacing: -0.12px;
|
||||
width: 100%;
|
||||
border-radius: 2px;
|
||||
|
||||
&:hover,
|
||||
&.active {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { fn } from "@storybook/test";
|
||||
import { useRef, useState } from "react";
|
||||
import { Dropdown } from "./dropdown";
|
||||
|
||||
@@ -10,6 +11,7 @@ const meta = {
|
||||
anchorRef: undefined,
|
||||
boundaryRef: undefined,
|
||||
className: "",
|
||||
setVisibility: fn(),
|
||||
},
|
||||
argTypes: {
|
||||
items: {
|
||||
@@ -18,6 +20,9 @@ const meta = {
|
||||
anchorRef: {
|
||||
description: "Element to attach the dropdown",
|
||||
},
|
||||
setVisibility: {
|
||||
description: "Visibility event handler",
|
||||
},
|
||||
boundaryRef: {
|
||||
description: "Component that defines the boundaries of the dropdown",
|
||||
},
|
||||
@@ -82,7 +87,14 @@ export const Test: Story = {
|
||||
Anchor Element
|
||||
</div>
|
||||
</div>
|
||||
{isDropdownVisible && <Dropdown {...modifiedArgs} anchorRef={anchorRef} boundaryRef={boundaryRef} />}
|
||||
{isDropdownVisible && (
|
||||
<Dropdown
|
||||
{...modifiedArgs}
|
||||
setVisibility={(visible) => setIsDropdownVisible(visible)}
|
||||
anchorRef={anchorRef}
|
||||
boundaryRef={boundaryRef}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useHeight } from "@/app/hook/useHeight";
|
||||
import { useWidth } from "@/app/hook/useWidth";
|
||||
import clsx from "clsx";
|
||||
import React, { memo, useLayoutEffect, useRef, useState } from "react";
|
||||
import React, { memo, useEffect, useLayoutEffect, useRef, useState } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import "./dropdown.less";
|
||||
|
||||
@@ -92,8 +92,8 @@ const SubMenu = memo(
|
||||
|
||||
type DropdownItem = {
|
||||
label: string;
|
||||
onClick?: (e) => void;
|
||||
subItems?: DropdownItem[];
|
||||
onClick?: (e) => void;
|
||||
};
|
||||
|
||||
const Dropdown = memo(
|
||||
@@ -102,11 +102,13 @@ const Dropdown = memo(
|
||||
anchorRef,
|
||||
boundaryRef,
|
||||
className,
|
||||
setVisibility,
|
||||
}: {
|
||||
items: DropdownItem[];
|
||||
anchorRef: React.RefObject<HTMLElement>;
|
||||
boundaryRef?: React.RefObject<HTMLElement>;
|
||||
className?: string;
|
||||
setVisibility: (_: boolean) => void;
|
||||
}) => {
|
||||
const [visibleSubMenus, setVisibleSubMenus] = useState<{ [key: string]: any }>({});
|
||||
const [hoveredItems, setHoveredItems] = useState<string[]>([]); // Track hovered items and ancestors
|
||||
@@ -159,6 +161,31 @@ const Dropdown = memo(
|
||||
}
|
||||
}, [width, height]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
const isClickInsideDropdown = dropdownRef.current && dropdownRef.current.contains(event.target as Node);
|
||||
const isClickInsideAnchor = anchorRef.current && anchorRef.current.contains(event.target as Node);
|
||||
|
||||
// Check if the click is inside any of the submenus
|
||||
const isClickInsideSubMenus = Object.keys(subMenuRefs.current).some(
|
||||
(key) =>
|
||||
subMenuRefs.current[key]?.current &&
|
||||
subMenuRefs.current[key]?.current.contains(event.target as Node)
|
||||
);
|
||||
|
||||
// If the click is outside the dropdown, anchor, and all submenus, hide the dropdown
|
||||
if (!isClickInsideDropdown && !isClickInsideAnchor && !isClickInsideSubMenus) {
|
||||
setVisibility(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("mousedown", handleClickOutside);
|
||||
};
|
||||
}, [dropdownRef, anchorRef, subMenuRefs]);
|
||||
|
||||
// Position submenus based on available space and scroll position
|
||||
const handleSubMenuPosition = (
|
||||
key: string,
|
||||
|
||||
Reference in New Issue
Block a user