From 640ffd38456c7c049cb4e66bb0658b98fa2d22ac Mon Sep 17 00:00:00 2001 From: Red Adaya Date: Mon, 23 Sep 2024 09:11:04 +0800 Subject: [PATCH] save work --- frontend/app/element/dropdown.tsx | 65 +++++++++++-------------------- 1 file changed, 22 insertions(+), 43 deletions(-) diff --git a/frontend/app/element/dropdown.tsx b/frontend/app/element/dropdown.tsx index e59113b7..113e0953 100644 --- a/frontend/app/element/dropdown.tsx +++ b/frontend/app/element/dropdown.tsx @@ -3,13 +3,11 @@ import { useWidth } from "@/app/hook/useWidth"; import clsx from "clsx"; import React, { memo, useLayoutEffect, useRef, useState } from "react"; import ReactDOM from "react-dom"; - import "./dropdown.less"; const SubMenu = ({ subItems, parentKey, - parentRef, subMenuPosition, visibleSubMenus, handleMouseEnterItem, @@ -17,13 +15,20 @@ const SubMenu = ({ }: { subItems: DropdownItem[]; parentKey: string; - parentRef: React.RefObject; subMenuPosition: any; visibleSubMenus: any; handleMouseEnterItem: any; subMenuRefs: any; }) => { - return ( + // Ensure a ref exists for each submenu + subItems.forEach((_, idx) => { + const newKey = `${parentKey}-${idx}`; + if (!subMenuRefs.current[newKey]) { + subMenuRefs.current[newKey] = React.createRef(); + } + }); + + const subMenu = (
{subItems.map((item, idx) => { const newKey = `${parentKey}-${idx}`; // Full hierarchical key - console.log("newKey===============", newKey, visibleSubMenus[newKey]); - console.log("visibleSubMenus************", visibleSubMenus); return (
handleMouseEnterItem(event, parentKey, idx, item)} + onMouseEnter={(event) => handleMouseEnterItem(event, parentKey, idx, item)} > {item.label} {item.subItems && } @@ -50,7 +54,6 @@ const SubMenu = ({ ); + return ReactDOM.createPortal(subMenu, document.body); }; type DropdownItem = { @@ -78,21 +82,19 @@ interface DropdownProps { } const Dropdown = memo(({ items, anchorRef, boundaryRef, className }: DropdownProps) => { - const [visibleSubMenus, setVisibleSubMenus] = useState<{ [key: string]: any }>({}); // Track visibility of each submenu + const [visibleSubMenus, setVisibleSubMenus] = useState<{ [key: string]: any }>({}); const [subMenuPosition, setSubMenuPosition] = useState<{ [key: string]: { top: number; left: number; label: string }; }>({}); const [position, setPosition] = useState({ top: 0, left: 0 }); const dropdownRef = useRef(null); - const subMenuRefs = useRef<{ [key: string]: React.RefObject }>({}); // Store refs using flat structure + const subMenuRefs = useRef<{ [key: string]: React.RefObject }>({}); const effectiveBoundaryRef: React.RefObject = boundaryRef ?? { current: document.documentElement }; const width = useWidth(effectiveBoundaryRef); const height = useHeight(effectiveBoundaryRef); - // console.log("visibleSubMenus.............", visibleSubMenus); - - // Add ref for each submenu dynamically + // Add refs for top-level menus items.forEach((_, idx) => { const key = `${idx}`; if (!subMenuRefs.current[key]) { @@ -134,12 +136,9 @@ const Dropdown = memo(({ items, anchorRef, boundaryRef, className }: DropdownPro parentRef: React.RefObject, label: string ) => { - // Delay the position calculation to allow the subMenuRef to be populated setTimeout(() => { const subMenuRef = subMenuRefs.current[key]?.current; - if (!subMenuRef) { - return; // Avoid proceeding if the ref is still null - } + if (!subMenuRef) return; const boundaryRect = effectiveBoundaryRef.current?.getBoundingClientRect() || { top: 0, @@ -151,8 +150,8 @@ const Dropdown = memo(({ items, anchorRef, boundaryRef, className }: DropdownPro const submenuWidth = subMenuRef.offsetWidth; const submenuHeight = subMenuRef.offsetHeight; - let left = itemRect.width; // Default position to the right of the hovered item - let top = submenuHeight - itemRect.height; + let left = itemRect.right; + let top = itemRect.top; // Adjust to the left if overflowing the right boundary if (left + submenuWidth > window.innerWidth) { @@ -164,15 +163,13 @@ const Dropdown = memo(({ items, anchorRef, boundaryRef, className }: DropdownPro top = window.innerHeight - submenuHeight - 10; } - // Set the submenu position setSubMenuPosition((prev) => ({ ...prev, [key]: { top, left, label }, })); - }, 0); // Delay by 50 milliseconds to ensure the submenu has rendered + }, 0); }; - // Handle submenu visibility updates const updateVisibility = (currentState: any, key: string, item: DropdownItem) => { const updatedState = Object.keys(currentState).reduce((acc, k) => { acc[k] = { ...currentState[k], visible: false }; @@ -180,7 +177,6 @@ const Dropdown = memo(({ items, anchorRef, boundaryRef, className }: DropdownPro }, {} as any); updatedState[key] = { visible: true, label: item.label }; - return updatedState; }; @@ -192,15 +188,11 @@ const Dropdown = memo(({ items, anchorRef, boundaryRef, className }: DropdownPro ) => { event.stopPropagation(); - const key = parentKey ? `${parentKey}-${index}` : `${index}`; // Full hierarchical key + const key = parentKey ? `${parentKey}-${index}` : `${index}`; setVisibleSubMenus((prev) => { - // Preserve the current hierarchy visibility and only update the current item const updatedState = { ...prev }; - - // Ensure the current submenu is visible updatedState[key] = { visible: true, label: item.label }; - return updatedState; }); @@ -208,17 +200,6 @@ const Dropdown = memo(({ items, anchorRef, boundaryRef, className }: DropdownPro handleSubMenuPosition(key, itemRect, dropdownRef, item.label); }; - // Hide submenu on mouse leave - const handleMouseLeaveItem = (key: string) => { - setTimeout(() => { - setVisibleSubMenus((prev) => ({ - ...prev, - [key]: { ...prev[key], visible: false }, - })); - }, 200); - }; - - // Render the main dropdown and submenus return ReactDOM.createPortal(
handleMouseEnterItem(event, null, index, item)} + onMouseEnter={(event) => handleMouseEnterItem(event, null, index, item)} > {item.label} {item.subItems && } @@ -239,11 +220,9 @@ const Dropdown = memo(({ items, anchorRef, boundaryRef, className }: DropdownPro )}