I am trying to make a sidebar, where a menu might have submenu kind of dropdown, the problem i am facing is when i open the submenu with MdArrowDropDown icon, it perfectly shows up , but it blocks the next menu item or overlaps it .i cant give it spacing . here is my code :
` /* eslint-disable react-hooks/exhaustive-deps */ import { type IconType } from "react-icons"; import { PiUserList, PiChats, PiUserLight, PiBellLight, PiStarLight, PiBriefcaseLight, PiCalendarCheck, PiCurrencyCircleDollarLight, PiIdentificationCardLight, } from "react-icons/pi"; import Link from "next/link"; import { useRouter } from "next/router"; import { useEffect, useMemo, useRef, useState } from "react"; import { type IconProps } from "types/common/types"; import { Flex } from "~/components/atoms/features/layout/Flex"; import { Text } from "~/components/atoms/features/typography/Text"; import { MdArrowDropDown } from "react-icons/md"; import { MdArrowDropUp } from "react-icons/md";
type Menu1Layer = {
href: string;
iconName?: IconProps["iconName"];
label: string;
badgeCount?: number | string;
isOpen: boolean;
activePathWord: string;
hidden: boolean;
};
type Props = {
iconName: IconProps["iconName"];
isMenuOpen: boolean;
title?: string;
hasDetail?: boolean;
isDetailOpen?: boolean;
isActive?: boolean;
className?: string;
dataCy?: string;
href: string;
items?: Menu1Layer[];
};
export const Item = (props: Props) => {
const {
iconName = "Dashboard",
isMenuOpen,
title,
hasDetail = false,
isDetailOpen = false,
className,
dataCy,
href,
items,
} = props;
const getIconComponent = (iconName: string): IconType => {
switch (iconName) {
case "UserList":
return PiUserList;
case "Chat":
return PiChats;
case "CalendarCheck":
return PiCalendarCheck;
case "Star":
return PiStarLight;
case "Bell":
return PiBellLight;
case "User":
return PiUserLight;
case "Briefcase":
return PiBriefcaseLight;
case "PiCurrencyCircleDollarLight":
return PiCurrencyCircleDollarLight;
case "PiIdentificationCardLight":
return PiIdentificationCardLight;
default:
return PiStarLight;
}
};
const [isOver, setIsOver] = useState<boolean>(false);
const [menuactive, setMenuActive] = useState<boolean>(false);
const [openDropDown, setOpenDropDown] = useState<boolean>(false);
const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);
const handleDropdownToggle = () => {
setOpenDropDown((prevOpenDropDown) => !prevOpenDropDown);
setMenuActive((prevActive) => !prevActive);
isActive;
};
const menuref = useRef<HTMLDivElement>(null);
useEffect(() => {
const handler = (event: MouseEvent) => {
if (menuref.current && !menuref.current.contains(event.target as Node)) {
setOpenDropDown(false);
setMenuActive(false);
}
};
document.addEventListener("mousedown", handler);
return () => {
document.removeEventListener("mousedown", handler);
};
});
const getColor = () => {
if (isOver || isActive || menuactive) return "border border-primary";
return "bg-[#FFFFFF]";
};
const router = useRouter();
const x = items?.find((item) => router.pathname.endsWith(item.href));
const child: number[] = [];
items?.map((item, index) => {
if (router.pathname.endsWith(item.href)) {
return child.push(index);
}
});
const isActive = href && router.pathname.endsWith(href) && child.length === 0;
const IconComponent = getIconComponent(iconName);
const contentItem = useMemo(
() => (
<>
{" "}
<Flex
direction="row"
justifyContent="start"
className={`${isActive ?? (menuactive && "bg-primary")} w-full px-1`}
gap={
!isMenuOpen &&
(isOver || (!isMenuOpen && isDetailOpen)) &&
hasDetail
? "0px"
: "8px"
}
wrap={false}
>
{!hasDetail && (
<IconComponent
size={24}
color={
(isOver && !isActive) || !isMenuOpen
? "#FF00FF"
: isActive
? "#FFFFFF"
: "#000000"
}
/>
)}
{hasDetail && (
<IconComponent
size={28}
color={
menuactive || isActive
? "#FFFFFF"
: isOver && !menuactive
? "#FF00FF"
: "#000000"
}
/>
)}
{!hasDetail && (
<Link href={href}>
<Text
text={title ?? ""}
className={`${isOver && !menuactive && "text-primary"} ${
isActive && "text-white"
} xl:text w-full overflow-hidden text-ellipsis font-bold lg:text-[16px]`}
/>
</Link>
)}
{hasDetail && isMenuOpen && href && (
<>
<Link href={href}>
<Text
text={title ?? ""}
className={`${isOver && !menuactive && "text-primary"} ${
isActive && "text-white"
} xl:text w-full overflow-hidden text-ellipsis font-bold lg:text-[16px]`}
/>
</Link>
<div
className={`relative ${openDropDown ? "z-10" : "z-0"}`}
ref={menuref}
>
{openDropDown && (
<MdArrowDropUp
size={24}
onClick={handleDropdownToggle}
className="ml:4"
/>
)}
{!openDropDown && (
<MdArrowDropDown
size={24}
onClick={handleDropdownToggle}
color={isOver && !menuactive ? "#FF00FF" : undefined}
className="ml:4"
/>
)}
{openDropDown && (
<div className="absolute left-0 top-full w-[180px] flex-col pt-2">
{openDropDown &&
items?.map((item, i) => {
const iconName = item.iconName ?? "DefaultIconName";
const IconComponent = getIconComponent(iconName);
return (
<div
key={item.label}
className={`${i === child[0] && "bg-primary"} ${
isOver &&
hoveredIndex === i &&
"border border-primary"
} mr-10 mt-2 flex h-full w-[175px] px-3 py-3 md:h-fit md:w-[160px] md:gap-0`}
onMouseEnter={() => setHoveredIndex(i)}
onMouseLeave={() => setHoveredIndex(null)}
>
<IconComponent
size={24}
color={
i === child[0]
? "#FFFFFF"
: hoveredIndex === i &&
isOver &&
i !== child[0] &&
!isActive
? "#FF00FF"
: "#000000"
}
/>
<Link href={item.href}>
<Text
text={item.label ?? ""}
className={`${
hoveredIndex === i && isOver
? "text-primary"
: "text-[#1D212D]"
} ${
i === child[0] && "text-white"
} xl:text my-1 w-full overflow-hidden text-ellipsis pl-2 font-bold lg:text-[16px]`}
/>
</Link>
</div>
);
})}
</div>
)}
</div>
</>
)}
</Flex>
</>
),
[
isOver,
isActive,
isDetailOpen,
isMenuOpen,
router,
openDropDown,
hoveredIndex,
],
);
const CLASSNAME = `flex flex-row items-center ${
isMenuOpen ? "justify-between" : "justify-center lg:w-[30px] xl:w-[52px]"
} ${menuactive && "bg-primary text-white"} ${
isActive && "bg-primary"
} whitespace-nowrap gap-[4px] px-[10px] py-[6px] w-full ${getColor()} ${className}`;
return (
<div
className={CLASSNAME}
onMouseOver={() => {
setIsOver(true);
}}
onMouseLeave={() => {
setIsOver(false);
}}
data-cy={dataCy}
>
{contentItem}
</div>
);
};
`