diff --git a/packages/main/cypress/specs/Menu.cy.tsx b/packages/main/cypress/specs/Menu.cy.tsx index a5f81c24b38f..74ca93f6a623 100644 --- a/packages/main/cypress/specs/Menu.cy.tsx +++ b/packages/main/cypress/specs/Menu.cy.tsx @@ -1162,4 +1162,155 @@ describe("Menu - getFocusDomRef", () => { expect(menu.getFocusDomRef()).equal(clickedItem.getFocusDomRef()); }); }); +}); + +describe("Menu - Submenu Focus Behavior", () => { + it("should not move focus when submenu opens via mouse hover", () => { + cy.mount( + <> + + + + + + + + + + ); + + cy.get("[ui5-menu]") + .ui5MenuOpen(); + + cy.get("[ui5-menu] > [ui5-menu-item]") + .as("items"); + + cy.get("@items") + .first() + .should("be.visible") + .as("parentItem"); + + // Hover item to open submenu + cy.get("@parentItem").realHover(); + + cy.get("@parentItem") + .shadow() + .find("[ui5-responsive-popover]") + .should("have.attr", "open"); + + // Verify focus not moved to submenu + cy.get("@parentItem") + .should("be.focused"); + + cy.get("[ui5-menu-item] > [ui5-menu-item]") + .as("submenuitems"); + + cy.get("@submenuitems") + .first() + .should("be.visible") + .as("childItem"); + + cy.get("@childItem") + .should("not.be.focused"); + }); + + it("should close submenu when hover moves to another item", () => { + cy.mount( + <> + + + + + + + + + + ); + + cy.get("[ui5-menu]") + .ui5MenuOpen(); + + cy.get("[ui5-menu] > [ui5-menu-item]") + .as("items"); + + cy.get("@items") + .first() + .should("be.visible") + .as("parentItem"); + + // Hover item to open submenu + cy.get("@parentItem").realHover(); + + cy.get("@parentItem") + .shadow() + .find("[ui5-responsive-popover]") + .as("submenuPopover"); + + cy.get("@submenuPopover") + .should("have.attr", "open"); + + // Hover over another top-level item + cy.get("@items") + .last() + .should("be.visible") + .as("lastItem"); + + cy.get("@lastItem") + .realHover(); + + // The original submenu should be closed + cy.get("@submenuPopover") + .should("not.have.attr", "open"); + }); + + it("should move focus when submenu opens via keyboard", () => { + cy.mount( + <> + + + + + + + + + + ); + + cy.get("[ui5-menu]") + .ui5MenuOpen(); + + cy.get("[ui5-menu] > [ui5-menu-item]") + .as("items"); + + cy.get("@items") + .first() + .should("be.visible") + .as("parentItem"); + + // Open submenu with keyboard + cy.get("@parentItem") + .should("be.focused") + .realPress("ArrowRight"); + cy.get("@parentItem") + .shadow() + .find("[ui5-responsive-popover]") + .should("have.attr", "open"); + + // Verify focus is moved to submenu + cy.get("@parentItem") + .should("not.be.focused"); + + cy.get("[ui5-menu-item] > [ui5-menu-item]") + .as("submenuitems"); + + cy.get("@submenuitems") + .first() + .should("be.visible") + .as("childItem"); + + cy.get("@childItem") + .should("be.focused"); + }); }); \ No newline at end of file diff --git a/packages/main/src/Menu.ts b/packages/main/src/Menu.ts index fdb2198e715b..6d978569928c 100644 --- a/packages/main/src/Menu.ts +++ b/packages/main/src/Menu.ts @@ -350,7 +350,7 @@ class Menu extends UI5Element { this.open = false; } - _openItemSubMenu(item: MenuItem) { + _openItemSubMenu(item: MenuItem, openedByMouse = false) { clearTimeout(this._timeout); if (!item._popover || item._popover.open) { @@ -364,6 +364,7 @@ class Menu extends UI5Element { item._popover.opener = item; item._popover.open = true; item.selected = true; + item._openedByMouse = openedByMouse; } _itemMouseOver(e: MouseEvent) { @@ -412,7 +413,7 @@ class Menu extends UI5Element { this._timeout = setTimeout(() => { this._closeOtherSubMenus(item); - this._openItemSubMenu(item); + this._openItemSubMenu(item, true); }, MENU_OPEN_DELAY); } @@ -454,7 +455,7 @@ class Menu extends UI5Element { } if (shouldOpenMenu) { - this._openItemSubMenu(item); + this._openItemSubMenu(item, false); } else if (isTabNextPrevious) { this._close(); } diff --git a/packages/main/src/MenuItem.ts b/packages/main/src/MenuItem.ts index f9db130beec8..41ff525fec9c 100644 --- a/packages/main/src/MenuItem.ts +++ b/packages/main/src/MenuItem.ts @@ -317,6 +317,7 @@ class MenuItem extends ListItem implements IMenuItem { _itemNavigation: ItemNavigation; _shiftPressed: boolean = false; + _openedByMouse = false; constructor() { super(); @@ -620,7 +621,9 @@ class MenuItem extends ListItem implements IMenuItem { } _afterPopoverOpen() { - this._allMenuItems[0]?.focus(); + if (!this._openedByMouse) { + this._allMenuItems[0]?.focus(); + } this.fireDecoratorEvent("open"); } @@ -642,6 +645,7 @@ class MenuItem extends ListItem implements IMenuItem { } _afterPopoverClose() { + this._openedByMouse = false; this.fireDecoratorEvent("close"); }