diff --git a/packages/lib/src/base-menu/GroupItem.tsx b/packages/lib/src/base-menu/GroupItem.tsx index 177e1dab3..412c1b693 100644 --- a/packages/lib/src/base-menu/GroupItem.tsx +++ b/packages/lib/src/base-menu/GroupItem.tsx @@ -1,93 +1,61 @@ -import { useContext, useEffect, useId, useState } from "react"; +import { useContext, useId, useState } from "react"; import DxcIcon from "../icon/Icon"; import SubMenu from "./SubMenu"; import ItemAction from "./ItemAction"; import MenuItem from "./MenuItem"; import { GroupItemProps } from "./types"; -import * as Popover from "@radix-ui/react-popover"; import { useGroupItem } from "./useGroupItem"; import BaseMenuContext from "./BaseMenuContext"; +import DxcPopover from "../popover/Popover"; const GroupItem = ({ items, ...props }: GroupItemProps) => { const groupMenuId = `group-menu-${useId()}`; - const navigationTreeId = `sidenav-${useId()}`; const contextValue = useContext(BaseMenuContext) ?? {}; const { groupSelected, isOpen, toggleOpen, hasPopOver, isHorizontal } = useGroupItem( items, contextValue, props.defaultOpen ); - const [portalContainer, setPortalContainer] = useState(null); - useEffect(() => { - setPortalContainer(document?.getElementById(`${navigationTreeId}-portal`)); - }, []); + const [isSubMenuOpen, setIsSubMenuOpen] = useState(true); + + const toggleSubMenu = () => { + setIsSubMenuOpen((prev) => !prev); + }; return hasPopOver ? ( <> - - - : } - onClick={() => { - toggleOpen(); - }} - selected={groupSelected && !isOpen} - {...props} - /> - - {portalContainer && ( - + { + if (isOpen) { + toggleOpen(); + } + }} + asChild + popoverContent={ + <> - { - if (event.key === "Escape") { - toggleOpen(); + {!isHorizontal && props.depthLevel === 0 && ( + : } - }} - align="start" - side={isHorizontal ? "bottom" : "right"} - style={{ - zIndex: "var(--z-contextualmenu)", - padding: "var(--spacing-padding-xs)", - boxShadow: "var(--shadow-100)", - backgroundColor: "var(--color-bg-neutral-lightest)", - borderRadius: "var(--border-radius-m)", - ...(isHorizontal - ? {} - : { - display: "flex", - flexDirection: "column", - gap: "var(--spacing-gap-xxs)", - }), - }} - sideOffset={isHorizontal ? 16 : 0} - onInteractOutside={() => toggleOpen()} - > - {!isHorizontal && props.depthLevel === 0 && ( - : - } - onClick={() => toggleOpen()} - selected={groupSelected && !isOpen} - {...props} - icon={undefined} - /> - )} + onClick={() => { + toggleSubMenu(); + }} + selected={groupSelected && !isSubMenuOpen} + {...props} + icon={undefined} + /> + )} + {isSubMenuOpen && ( {items.map((item, index) => ( { /> ))} - + )} - - )} - -
+ + } + isOpen={isOpen} + > + : } + onClick={() => { + toggleOpen(); + }} + selected={groupSelected && !isOpen} + {...props} + /> + ) : ( <> diff --git a/packages/lib/src/base-menu/ItemAction.tsx b/packages/lib/src/base-menu/ItemAction.tsx index 984d9652a..6decb6905 100644 --- a/packages/lib/src/base-menu/ItemAction.tsx +++ b/packages/lib/src/base-menu/ItemAction.tsx @@ -28,7 +28,7 @@ const Action = styled.a<{ cursor: pointer; overflow: hidden; text-decoration: none; - + width: stretch; &:hover { background-color: ${({ selected }) => selected ? "var(--color-bg-primary-medium)" : "var(--color-bg-neutral-light)"}; diff --git a/packages/lib/src/sidenav/Sidenav.test.tsx b/packages/lib/src/sidenav/Sidenav.test.tsx index 0808a3016..48bf447a5 100644 --- a/packages/lib/src/sidenav/Sidenav.test.tsx +++ b/packages/lib/src/sidenav/Sidenav.test.tsx @@ -60,6 +60,31 @@ describe("DxcSidenav component", () => { expect(getByText("Dashboard")).toBeTruthy(); expect(getByText("Settings")).toBeTruthy(); }); + test("Sidenav opens and closes a group submenu in a collapsed navigation menu", () => { + const navItems = [ + { + label: "Parent group", + items: [ + { + label: "Nested group", + items: [{ label: "Nested item" }], + }, + ], + }, + ]; + const { getByLabelText, getByText, queryByText } = render( + + ); + + fireEvent.click(getByLabelText("Parent group").closest("button")!); + expect(getByText("Nested group")).toBeInTheDocument(); + + fireEvent.click(getByText("Parent group")); + expect(queryByText("Nested group")).not.toBeInTheDocument(); + + fireEvent.click(getByText("Parent group")); + expect(getByText("Nested group")).toBeInTheDocument(); + }); test("Sidenav renders link items correctly", () => { const navItems = [{ label: "Dashboard", href: "/dashboard" }];