diff --git a/packages/fiori/cypress/specs/SideNavigation.cy.tsx b/packages/fiori/cypress/specs/SideNavigation.cy.tsx index 4c660108600c..bb313950936d 100644 --- a/packages/fiori/cypress/specs/SideNavigation.cy.tsx +++ b/packages/fiori/cypress/specs/SideNavigation.cy.tsx @@ -6,6 +6,7 @@ import group from "@ui5/webcomponents-icons/dist/group.js"; import { NAVIGATION_MENU_POPOVER_HIDDEN_TEXT } from "../../src/generated/i18n/i18n-defaults.js"; import Title from "@ui5/webcomponents/dist/Title.js"; import Label from "@ui5/webcomponents/dist/Label.js"; +import ResponsivePopover from "@ui5/webcomponents/dist/ResponsivePopover.js"; describe("Side Navigation Rendering", () => { it("Tests rendering in collapsed mode", () => { @@ -222,6 +223,269 @@ describe("Side Navigation interaction", () => { cy.get("#unselectableItem").should("be.focused").and("not.have.attr", "expanded"); }); + it("Tests expanding of items with ArrowRight", () => { + cy.mount( + + + + + + + ); + + cy.get("#focusStart").realClick(); + cy.realPress("ArrowDown"); + cy.realPress("ArrowRight"); + + cy.get("#unselectableItem").should("have.attr", "expanded"); + }); + + it("Tests collapsing of items with ArrowLeft", () => { + cy.mount( + + + + + + + ); + cy.get("#focusStart").realClick(); + cy.realPress("ArrowDown"); + cy.realPress("ArrowLeft"); + + cy.get("#unselectableItem").should("not.have.attr", "expanded"); + + }); + + it("Tests expanding of items with ArrowRight on collapsed sn", () => { + cy.mount( + + + + + + + ); + + cy.get("#unselectableItem").realClick(); + + cy.get("#sn") + .shadow() + .find(`[ui5-side-navigation-item][text="1"]`) + .should('be.focused'); + + cy.realPress("ArrowLeft"); + cy.get("#unselectableItem").should('be.focused'); + + cy.realPress("ArrowRight"); + cy.get("#sn") + .shadow() + .find(`[ui5-side-navigation-item][text="1"]`) + .should('be.focused'); + + cy.get("#sn") + .shadow() + .find("[ui5-responsive-popover]") + .ui5ResponsivePopoverOpened(); + }); + + it("Tests collapsing of items with ArrowLeft on collapsed sn", () => { + cy.mount( + + + + + + + ); + + cy.get("#unselectableItem").realClick(); + + cy.get("#sn") + .shadow() + .find(`[ui5-side-navigation-item][text="1"]`) + .should('be.focused'); // Фокуса на правилното място ли е след, като съм отворил popover? + + cy.realPress("ArrowLeft"); // Ако фокуса е на правилното място, натисни ArrowLeft + + cy.get("#unselectableItem").should('be.focused'); // След като съм натиснал ArrowLeft, провери дали фокуса е на правилното място + + cy.get("#sn") + .shadow() + .find("[ui5-responsive-popover]") + .ui5ResponsivePopoverClosed(); // Ако фокуса е на правилното място провери дали popover-a е затворен, защото така очаквам + }); + + it("Tests expanding of items with ArrowLeft for rtl", () => { + cy.mount( +
+ + + + + + +
+ ); + + cy.get("#focusStart").realClick(); + cy.realPress("ArrowDown"); + cy.realPress("ArrowLeft"); + + cy.get("#unselectableItem").should("have.attr", "expanded"); + }); + + it("Tests collapsing of items with ArrowRight for rtl", () => { + cy.mount( +
+ + + + + + +
+ ); + + cy.get("#unselectableItem").realClick(); + cy.get("#unselectableItem").realPress("ArrowRight"); + + cy.get("#unselectableItem").should("not.have.attr", "expanded"); + + }); + + it("Tests expanding of items with ArrowLeft on collapsed sn for rtl", () => { + cy.mount( +
+ + + + + + +
+ ); + + cy.get("#unselectableItem").realClick(); + + cy.get("#sn") + .shadow() + .find(`[ui5-side-navigation-item][text="1"]`) + .should('be.focused'); + + cy.realPress("ArrowRight"); + + cy.get("#unselectableItem").should('be.focused'); + + cy.realPress("ArrowLeft"); + cy.get("#sn") + .shadow() + .find(`[ui5-side-navigation-item][text="1"]`) + .should('be.focused'); + + cy.get("#sn") + .shadow() + .find("[ui5-responsive-popover]") + .ui5ResponsivePopoverOpened(); + }); + + it("Tests collapsing of items with ArrowRight on collapsed sn for rtl", () => { + cy.mount( +
+ + + + + + +
+ ); + + cy.get("#unselectableItem").realClick(); + cy.get("#sn") + .shadow() + .find(`[ui5-side-navigation-item][text="1"]`) + .should('be.focused'); + + cy.realPress("ArrowRight"); + + cy.get("#sn") + .shadow() + .find("[ui5-responsive-popover]") + .ui5ResponsivePopoverClosed(); + }); + + it("Tests expanding of items with Plus", () => { + cy.mount( + + + + + + + ); + + cy.get("#focusStart").realClick(); + cy.realPress("ArrowDown"); + cy.realPress("+"); + + cy.get("#unselectableItem").should("have.attr", "expanded"); + + }); + + it("Tests collapsing of items with Minus", () => { + cy.mount( + + + + + + + ); + + cy.get("#unselectableItem").realClick(); + cy.realPress("-"); + + cy.get("#unselectableItem").should("not.have.attr", "expanded"); + + }); + + it("Tests expanding of items with Plus for rtl", () => { + cy.mount( +
+ + + + + + +
+ ); + + cy.get("#focusStart").realClick(); + cy.realPress("ArrowDown"); + cy.realPress("+"); + + cy.get("#unselectableItem").should("have.attr", "expanded"); + }); + + it("Tests collapsing of items with Minus for rtl", () => { + cy.mount( +
+ + + + + + +
+ ); + cy.get("#unselectableItem").realClick(); + cy.realPress("-"); + + cy.get("#unselectableItem").should("not.have.attr", "expanded"); + }); + it("Tests expanding and collapsing of unselectable parent item when SideNavigation is collapsed", () => { cy.mount( diff --git a/packages/fiori/cypress/specs/SideNavigationWithGroups.cy.tsx b/packages/fiori/cypress/specs/SideNavigationWithGroups.cy.tsx index b99495c9912a..2dcfab827d90 100644 --- a/packages/fiori/cypress/specs/SideNavigationWithGroups.cy.tsx +++ b/packages/fiori/cypress/specs/SideNavigationWithGroups.cy.tsx @@ -94,35 +94,177 @@ describe("Component Behavior", () => { .find(".ui5-sn-item") .realClick(); cy.get("#group1").should("have.prop", "expanded", true); + }); + + it("Tests expanding of groups with ArrowRight", () => { + cy.mount( + + + + + + + ); - cy.get("#group2") - .shadow() - .find(".ui5-sn-item") - .realClick(); - cy.get("#group2").should("have.prop", "expanded", false); + cy.get("#focusStart").realClick(); + cy.realPress("ArrowDown"); + cy.realPress("ArrowRight"); + + cy.get("#group1").should("have.attr", "expanded"); }); - it("disabled", () => { + it("Tests collapsing of groups with ArrowLeft", () => { cy.mount( - - - - - + + + + - ); + + ); + + cy.get("#focusStart").realClick(); + cy.realPress("ArrowDown"); + cy.realPress("ArrowLeft"); + + cy.get("#group1").should("not.have.attr", "expanded"); + }); + + it("Tests expanding of groups with ArrowLeft for rtl", () => { + cy.mount( +
+ + + + + + +
+ ); + + cy.get("#focusStart").realClick(); + cy.realPress("ArrowDown"); + cy.realPress("ArrowLeft"); + + cy.get("#group1").should("have.attr", "expanded"); + }); + + it("Tests expanding of groups with ArrowRight for rtl", () => { + cy.mount( +
+ + + + + + +
+ ); + + cy.get("#focusStart").realClick(); + cy.realPress("ArrowDown"); + cy.realPress("ArrowRight"); + + cy.get("#group1").should("not.have.attr", "expanded"); + + }); + + it("Tests expanding of groups with Plus", () => { + cy.mount( + + + + + + + ); + + cy.get("#focusStart").realClick(); + cy.realPress("ArrowDown"); + cy.realPress("+"); + + cy.get("#group1").should("have.attr", "expanded"); + }); + + it("Tests collapsing of groups with Minus", () => { + cy.mount( + + + + + + + ); + + cy.get("#focusStart").realClick(); + cy.realPress("ArrowDown"); + cy.realPress("-"); + + cy.get("#group1").should("not.have.attr", "expanded"); + }); + + it("Tests expanding of groups with Plus for rtl", () => { + cy.mount( +
+ + + + + + +
+ ); + + cy.get("#focusStart").realClick(); + cy.realPress("ArrowDown"); + cy.realPress("+"); + + cy.get("#group1").should("have.attr", "expanded"); + + }); + + it("Tests collapsing of groups with Minus for rtl", () => { + cy.mount( +
+ + + + + + +
+ ); + + cy.get("#focusStart").realClick(); + cy.realPress("ArrowDown"); + cy.realPress("-"); + + cy.get("#group1").should("not.have.attr", "expanded"); - cy.get("#group1").should("not.have.attr", "disabled"); - cy.get("#group1").invoke("prop", "disabled", true); - cy.get("#group1").should("have.attr", "disabled"); - - cy.get("#group1").then(($group) => { - const group = $group[0] as SideNavigationGroup; - cy.wrap(group.items).each((item: SideNavigationItem) => { - cy.wrap(item).should("have.prop", "disabled", true); - }); - }); }); - }); -}); +}); \ No newline at end of file diff --git a/packages/fiori/src/SideNavigationGroup.ts b/packages/fiori/src/SideNavigationGroup.ts index 9abe39c40036..682ba2742c08 100644 --- a/packages/fiori/src/SideNavigationGroup.ts +++ b/packages/fiori/src/SideNavigationGroup.ts @@ -155,12 +155,27 @@ class SideNavigationGroup extends SideNavigationItemBase { } _onkeydown(e: KeyboardEvent) { - if (isLeft(e) || isMinus(e)) { + const isRTL = this.effectiveDir === "rtl"; + + if (isLeft(e)) { + e.preventDefault(); + this.expanded = isRTL; + return; + } + + if (isRight(e)) { + e.preventDefault(); + this.expanded = !isRTL; + } + + if (isMinus(e)) { + e.preventDefault(); this.expanded = false; return; } - if (isRight(e) || isPlus(e)) { + if (isPlus(e)) { + e.preventDefault(); this.expanded = true; } } diff --git a/packages/fiori/src/SideNavigationItem.ts b/packages/fiori/src/SideNavigationItem.ts index 402d92819fc3..f47d078c6e40 100644 --- a/packages/fiori/src/SideNavigationItem.ts +++ b/packages/fiori/src/SideNavigationItem.ts @@ -71,7 +71,7 @@ class SideNavigationItem extends SideNavigationSelectableItemBase { _fixed = false; /** - * Defines nested items by passing `ui5-side-navigation-sub-item` to the default slot. + * Defines nested items by passing `ui5-side-navigation-sub-item` to the default slot. * * @public */ @@ -85,6 +85,10 @@ class SideNavigationItem extends SideNavigationSelectableItemBase { return [this]; } + get hasSubItems() { + return this.items.length > 0; + } + get selectableItems() : Array { if (this.inPopover && this.unselectable && this.items.length) { return [...this.items]; @@ -199,12 +203,33 @@ class SideNavigationItem extends SideNavigationSelectableItemBase { } _onkeydown(e: KeyboardEvent) { - if (isLeft(e) || isMinus(e)) { + const isRTL = this.effectiveDir === "rtl"; + + if (this.sideNavigation.classList.contains("ui5-side-navigation-in-popover") || this.sideNavCollapsed) { + super._onkeydown(e); + return; + } + + if (isLeft(e)) { + e.preventDefault(); + this.expanded = isRTL; + return; + } + + if (isRight(e)) { + e.preventDefault(); + this.expanded = !isRTL; + return; + } + + if (isMinus(e)) { + e.preventDefault(); this.expanded = false; return; } - if (isRight(e) || isPlus(e)) { + if (isPlus(e)) { + e.preventDefault(); this.expanded = true; return; } diff --git a/packages/fiori/src/SideNavigationItemBase.ts b/packages/fiori/src/SideNavigationItemBase.ts index de1b3f989afe..a1f6b6223c5c 100644 --- a/packages/fiori/src/SideNavigationItemBase.ts +++ b/packages/fiori/src/SideNavigationItemBase.ts @@ -76,6 +76,10 @@ class SideNavigationItemBase extends UI5Element implements ITabbable { return this.tooltip || undefined; } + get hasSubItems() { + return false; + } + get classesArray() { const classes = []; diff --git a/packages/fiori/src/SideNavigationSelectableItemBase.ts b/packages/fiori/src/SideNavigationSelectableItemBase.ts index 9ab84f33bd34..00e274de2566 100644 --- a/packages/fiori/src/SideNavigationSelectableItemBase.ts +++ b/packages/fiori/src/SideNavigationSelectableItemBase.ts @@ -1,7 +1,12 @@ import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js"; import property from "@ui5/webcomponents-base/dist/decorators/property.js"; import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; -import { isSpace, isEnter } from "@ui5/webcomponents-base/dist/Keys.js"; +import { + isSpace, + isEnter, + isLeft, + isRight, +} from "@ui5/webcomponents-base/dist/Keys.js"; import SideNavigationItemBase from "./SideNavigationItemBase.js"; import type SideNavigationItemDesign from "./types/SideNavigationItemDesign.js"; import type { AccessibilityAttributes } from "@ui5/webcomponents-base/dist/types.js"; @@ -139,6 +144,13 @@ class SideNavigationSelectableItemBase extends SideNavigationItemBase { @property({ type: Boolean }) isOverflow = false; + /** + * Reference to the original side navigation item that opened the popover. + * + * @private + */ + associatedItem?: SideNavigationItemBase; + get ariaRole() { if (this.sideNavCollapsed) { return this.isOverflow || this.unselectable ? "menuitem" : "menuitemradio"; @@ -194,13 +206,23 @@ class SideNavigationSelectableItemBase extends SideNavigationItemBase { } _onkeydown(e: KeyboardEvent) { - if (isSpace(e)) { + const isRTL = this.effectiveDir === "rtl"; + + if (isSpace(e) || isRight(e) || isLeft(e)) { e.preventDefault(); } if (isEnter(e)) { this._activate(e); } + + if ((isRTL ? isLeft(e) : isRight(e)) && this.sideNavCollapsed && this.hasSubItems) { + this._activate(e); + } + + if ((isRTL ? isRight(e) : isLeft(e)) && this.inPopover) { + this.associatedItem?.sideNavigation?.closePicker(); + } } _onkeyup(e: KeyboardEvent) { diff --git a/packages/fiori/src/themes/SideNavigationGroup.css b/packages/fiori/src/themes/SideNavigationGroup.css index 13eb25e38500..ef28dc29313e 100644 --- a/packages/fiori/src/themes/SideNavigationGroup.css +++ b/packages/fiori/src/themes/SideNavigationGroup.css @@ -9,7 +9,6 @@ .ui5-sn-item.ui5-sn-item-group { min-height: 2rem; padding-inline-start: var(--_ui5_side_navigation_group_padding);; - gap: 0.4375rem; font-family: var(--sapFontFamily); font-size: var(--sapFontSize); }