diff --git a/packages/fiori/cypress/specs/UserMenu.cy.tsx b/packages/fiori/cypress/specs/UserMenu.cy.tsx
index a9f0ae62ea6ed..c0b4f03e2602d 100644
--- a/packages/fiori/cypress/specs/UserMenu.cy.tsx
+++ b/packages/fiori/cypress/specs/UserMenu.cy.tsx
@@ -877,6 +877,22 @@ describe("Events", () => {
cy.get("@opened").should("have.been.calledOnce");
});
+ it("focuses first menu item after open", () => {
+ cy.mount(
+ <>
+
+
+
+
+
+
+ >
+ );
+
+ cy.get("[ui5-user-menu-item][text='Setting']")
+ .should("be.focused");
+ });
+
it("tests close event", () => {
cy.mount(
<>
@@ -970,7 +986,74 @@ describe("Responsiveness", () => {
.scrollTo("bottom");
cy.get("[ui5-user-menu]").shadow().find("[ui5-bar]").as("headerBar");
cy.get("@headerBar").find("[ui5-title]").contains("Alain Chevalier 1");
- cy.get("@headerBar").find("[ui5-button]").should("have.length", 1);
+ cy.get("@headerBar").find("[ui5-button][slot='endContent']").should("have.length", 1);
+ });
+
+ it("submenu header on phone has close button in UserMenuItem", () => {
+ cy.ui5SimulateDevice("phone");
+ cy.mount(
+ <>
+
+
+
+
+
+
+
+ >
+ );
+
+ cy.get("[ui5-user-menu-item][text='Settings']")
+ .ui5MenuItemClick();
+
+ cy.get("[ui5-user-menu-item][text='Settings']")
+ .shadow()
+ .find("[ui5-responsive-popover]")
+ .should("have.attr", "open");
+
+ cy.get("[ui5-user-menu-item][text='Settings']")
+ .shadow()
+ .find(".ui5-menu-close-button")
+ .should("exist");
+ });
+
+ it("submenu header on desktop has no close button in UserMenuItem", () => {
+ cy.mount(
+ <>
+
+
+
+
+
+
+
+ >
+ );
+
+ cy.get("[ui5-user-menu-item][text='Settings']")
+ .shadow()
+ .find(".ui5-menu-close-button")
+ .should("not.exist");
+ });
+
+ it("popover header has no divider line (::before pseudo-element hidden)", () => {
+ cy.mount(
+ <>
+
+
+
+
+ >
+ );
+
+ cy.get("[ui5-user-menu]").shadow()
+ .find("[ui5-responsive-popover]")
+ .shadow()
+ .find(".ui5-popup-header-root")
+ .then($el => {
+ const before = window.getComputedStyle($el[0], "::before");
+ expect(before.display).to.equal("none");
+ });
});
it("Event firing - 'ui5-check' after 'click' on user menu item", () => {
@@ -1315,6 +1398,26 @@ describe("InfoArea slot", () => {
});
});
});
+
+ it("info-area has 8px padding on all sides", () => {
+ cy.mount(
+ <>
+
+
+
+
+ All actions are recorded under the proxy audit log.
+
+
+ >
+ );
+
+ cy.get("[ui5-user-menu]").shadow().find(".ui5-user-menu-info-area")
+ .should("have.css", "padding-top", "8px")
+ .and("have.css", "padding-bottom", "8px")
+ .and("have.css", "padding-left", "8px")
+ .and("have.css", "padding-right", "8px");
+ });
});
describe("UserMenuItem", () => {
@@ -1580,7 +1683,7 @@ describe("UserMenuItem", () => {
.should("not.have.attr", "show-selection");
});
- it("selection text has correct styling", () => {
+ it("selection text wraps instead of truncating", () => {
cy.mount(
<>
@@ -1598,9 +1701,8 @@ describe("UserMenuItem", () => {
.shadow()
.find(".ui5-user-menu-item-selection-text")
.should("have.css", "font-weight", "400")
- .and("have.css", "white-space", "nowrap")
- .and("have.css", "overflow", "hidden")
- .and("have.css", "text-overflow", "ellipsis");
+ .and("not.have.css", "white-space", "nowrap")
+ .and("not.have.css", "text-overflow", "ellipsis");
});
it("text wrapper has column layout with gap", () => {
diff --git a/packages/fiori/src/UserMenu.ts b/packages/fiori/src/UserMenu.ts
index e8b26d0be842a..ef89551a20364 100644
--- a/packages/fiori/src/UserMenu.ts
+++ b/packages/fiori/src/UserMenu.ts
@@ -433,6 +433,7 @@ class UserMenu extends UI5Element {
this._titleMovedToHeader = false;
this._isScrolled = false;
this._setupObserver();
+ this._menuItems[0]?.getFocusDomRef()?.focus();
this.fireDecoratorEvent("open");
}
diff --git a/packages/fiori/src/UserMenuItemTemplate.tsx b/packages/fiori/src/UserMenuItemTemplate.tsx
index ff561b1bb1627..bb4813c5e53da 100644
--- a/packages/fiori/src/UserMenuItemTemplate.tsx
+++ b/packages/fiori/src/UserMenuItemTemplate.tsx
@@ -1,17 +1,163 @@
import type UserMenuItem from "./UserMenuItem.js";
import MenuItemTemplate from "@ui5/webcomponents/dist/MenuItemTemplate.js";
import type { MenuItemHooks } from "@ui5/webcomponents/dist/MenuItemTemplate.js";
+import ListItemTemplate from "@ui5/webcomponents/dist/ListItemTemplate.js";
+import type { ListItemHooks } from "@ui5/webcomponents/dist/ListItemTemplate.js";
+import ResponsivePopover from "@ui5/webcomponents/dist/ResponsivePopover.js";
+import Button from "@ui5/webcomponents/dist/Button.js";
+import List from "@ui5/webcomponents/dist/List.js";
+import BusyIndicator from "@ui5/webcomponents/dist/BusyIndicator.js";
+import Icon from "@ui5/webcomponents/dist/Icon.js";
+import PopoverPlacement from "@ui5/webcomponents/dist/types/PopoverPlacement.js";
+import navBackIcon from "@ui5/webcomponents-icons/dist/nav-back.js";
+import declineIcon from "@ui5/webcomponents-icons/dist/decline.js";
+import checkIcon from "@ui5/webcomponents-icons/dist/accept.js";
+import slimArrowRight from "@ui5/webcomponents-icons/dist/slim-arrow-right.js";
export default function UserMenuItemTemplate(this: UserMenuItem) {
- const hooks: Partial = {};
+ if (this.isPhone) {
+ return phoneTemplate.call(this);
+ }
+ const hooks: Partial = {};
if (this.showSelection) {
hooks.menuItemTextContent = userMenuItemTextContent;
}
-
return [MenuItemTemplate.call(this, hooks)];
}
+function phoneTemplate(this: UserMenuItem) {
+ const hooks: Partial = {
+ iconBegin(this: UserMenuItem) {
+ if (this.hasIcon) {
+ return ;
+ }
+ if (this._siblingsWithIcon) {
+ return ;
+ }
+ },
+ listItemContent(this: UserMenuItem) {
+ return (<>
+ {this.showSelection ? (
+
+ ) : (
+ <>{this.text && }>
+ )}
+ {rightContent.call(this)}
+ {checkmarkContent.call(this)}
+ >);
+ },
+ };
+
+ return [
+ ListItemTemplate.call(this, hooks),
+ phoneSubmenuPopover.call(this),
+ ];
+}
+
+function checkmarkContent(this: UserMenuItem) {
+ return !this._markChecked ? "" : (
+
+ );
+}
+
+function rightContent(this: UserMenuItem) {
+ switch (true) {
+ case this.hasSubmenu:
+ return (
+
+ );
+ case this.hasEndContent:
+ return (
+
+ );
+ case !!this.additionalText:
+ return (
+
+ {this.additionalText}
+
+ );
+ }
+}
+
+function phoneSubmenuPopover(this: UserMenuItem) {
+ return this.hasSubmenu && ;
+}
+
function userMenuItemTextContent(this: UserMenuItem) {
return (