From ed4ff91b8111b845fde9b197aebee6c4ed7362f0 Mon Sep 17 00:00:00 2001 From: Iliana Bobeva Date: Mon, 13 Jul 2026 16:10:09 +0300 Subject: [PATCH] feat(ui5-product-switch): support 2-column layout and free text wrapping Add a 2-column desktop layout for cases with two or fewer items, since the previous logic only supported 3 or 4 columns. The ProductSwitch now sets desktop-columns="2" (376px width) accordingly. Enable free text wrapping for the item title and subtitle instead of truncating with an ellipsis. Per the updated design spec, text is never truncated - it wraps freely and the item grows vertically, with items in the same row stretching to match the tallest one. --- .../fiori/cypress/specs/ProductSwitch.cy.tsx | 134 ++++++++++++++++++ packages/fiori/src/ProductSwitch.ts | 10 +- packages/fiori/src/themes/ProductSwitch.css | 7 +- .../fiori/src/themes/ProductSwitchItem.css | 17 +-- 4 files changed, 154 insertions(+), 14 deletions(-) diff --git a/packages/fiori/cypress/specs/ProductSwitch.cy.tsx b/packages/fiori/cypress/specs/ProductSwitch.cy.tsx index 2bfea7a72f38f..ddff92eb1ded9 100644 --- a/packages/fiori/cypress/specs/ProductSwitch.cy.tsx +++ b/packages/fiori/cypress/specs/ProductSwitch.cy.tsx @@ -72,6 +72,26 @@ describe("List - getFocusDomRef Method", () => { }); describe("ProductSwitch general interaction", () => { + it("tests 2-column desktop layout", () => { + cy.mount( + + + + + ); + + cy.get("[ui5-product-switch]") + .should("have.attr", "desktop-columns", "2") + .invoke("prop", "items") + .should("have.length", 2) + .should("have.length.at.most", 2); + + cy.get("[ui5-product-switch]") + .shadow() + .find(".ui5-product-switch-root") + .should("have.css", "width", "376px"); + }); + it("tests 3-column desktop layout", () => { cy.mount( @@ -152,3 +172,117 @@ describe("ProductSwitch styles", () => { .should("have.css", "align-items", "center"); }); }); + +describe("ProductSwitchItem text wrapping", () => { + it("title and subtitle wrap freely without truncation", () => { + cy.mount( + + + + + ); + + cy.get("#longItem") + .shadow() + .find(".ui5-product-switch-item-title") + .should("have.css", "white-space", "normal") + .should("not.have.css", "text-overflow", "ellipsis"); + + cy.get("#longItem") + .shadow() + .find(".ui5-product-switch-item-subtitle") + .should("have.css", "white-space", "normal") + .should("not.have.css", "text-overflow", "ellipsis"); + + // text is not clipped — the rendered scroll height fits the visible height + cy.get("#longItem") + .shadow() + .find(".ui5-product-switch-item-title") + .then($el => { + const el = $el[0]; + expect(el.scrollHeight).to.equal(el.clientHeight); + }); + }); + + it("host grows vertically when text wraps", () => { + cy.mount( + + + + + ); + + // the long-text item's host renders taller than the default 7rem (112px) baseline + cy.get("#longItem").then($long => { + expect($long[0].getBoundingClientRect().height).to.be.greaterThan(112); + }); + }); + + it("items in the same row stretch to the tallest sibling", () => { + cy.mount( + + + + + ); + + cy.get("#longItem").then($long => { + cy.get("#shortItem").then($short => { + expect($short[0].getBoundingClientRect().height) + .to.equal($long[0].getBoundingClientRect().height); + }); + }); + }); + + it("title-only item wraps freely (no 2-line clamp)", () => { + cy.mount( + + + + ); + + cy.get("#titleOnly") + .shadow() + .find(".ui5-product-switch-item-title") + .should("have.css", "white-space", "normal") + .then($title => { + const el = $title[0]; + // nothing is clipped + expect(el.scrollHeight).to.equal(el.clientHeight); + }); + }); +}); diff --git a/packages/fiori/src/ProductSwitch.ts b/packages/fiori/src/ProductSwitch.ts index 84d38306502ed..a84ae46ab27e9 100644 --- a/packages/fiori/src/ProductSwitch.ts +++ b/packages/fiori/src/ProductSwitch.ts @@ -126,7 +126,13 @@ class ProductSwitch extends UI5Element { } onBeforeRendering() { - this.desktopColumns = this.items.length > 6 ? 4 : 3; + if (this.items.length > 6) { + this.desktopColumns = 4; + } else if (this.items.length <= 2) { + this.desktopColumns = 2; + } else { + this.desktopColumns = 3; + } } _handleResize() { @@ -134,6 +140,8 @@ class ProductSwitch extends UI5Element { if (documentWidth <= (this.constructor as typeof ProductSwitch).ROW_MIN_WIDTH.ONE_COLUMN) { this._setRowSize(1); + } else if (this.items.length <= 2) { + this._setRowSize(2); } else if (documentWidth <= (this.constructor as typeof ProductSwitch).ROW_MIN_WIDTH.THREE_COLUMN || this.items.length <= 6) { this._setRowSize(3); } else { diff --git a/packages/fiori/src/themes/ProductSwitch.css b/packages/fiori/src/themes/ProductSwitch.css index 9c8b5cc3eaf64..85fabb88dd7f7 100644 --- a/packages/fiori/src/themes/ProductSwitch.css +++ b/packages/fiori/src/themes/ProductSwitch.css @@ -16,6 +16,10 @@ width: 564px; /* 3 * item size */ } +:host([desktop-columns="2"]) .ui5-product-switch-root { + width: 376px; /* 2 * item size */ +} + @media only screen and (max-width: 900px) { .ui5-product-switch-root { width: 564px; /* 3 * item size */ @@ -24,7 +28,8 @@ @media only screen and (max-width: 600px) { .ui5-product-switch-root, - :host([desktop-columns="3"]) .ui5-product-switch-root { + :host([desktop-columns="3"]) .ui5-product-switch-root, + :host([desktop-columns="2"]) .ui5-product-switch-root { flex-direction: column; padding: 0; width: 100%; diff --git a/packages/fiori/src/themes/ProductSwitchItem.css b/packages/fiori/src/themes/ProductSwitchItem.css index 40c76744e7518..4aa75d9b030cd 100644 --- a/packages/fiori/src/themes/ProductSwitchItem.css +++ b/packages/fiori/src/themes/ProductSwitchItem.css @@ -1,6 +1,6 @@ :host { width: var(--_ui5_product_switch_item_width); - height: var(--_ui5_product_switch_item_height); + min-height: var(--_ui5_product_switch_item_height); margin: .25rem; border-radius: .25rem; box-sizing: border-box; @@ -88,9 +88,8 @@ .ui5-product-switch-item-root .ui5-product-switch-item-text-content .ui5-product-switch-item-subtitle, .ui5-product-switch-item-root .ui5-product-switch-item-text-content .ui5-product-switch-item-title { line-height: 1.25rem; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + white-space: normal; + overflow-wrap: anywhere; max-width: 100%; pointer-events: none; text-align: center; @@ -101,13 +100,6 @@ color:var(--sapGroup_TitleTextColor); } -.ui5-product-switch-item-root .ui5-product-switch-item-text-content .ui5-product-switch-item-title:only-child { - white-space: normal; - -webkit-line-clamp: 2; - display: -webkit-box; - -webkit-box-orient: vertical; -} - .ui5-product-switch-item-root .ui5-product-switch-item-text-content .ui5-product-switch-item-subtitle { font-size:var(--sapFontSmallSize); color:var(--sapContent_LabelColor); @@ -119,7 +111,8 @@ width: 100%; width: 100%; max-width: 600px; - height: 5rem; + min-height: 5rem; + height: auto; border-radius: 0; }