From 4b9e525cc77b3ee76961d1ccd6cd67a3342e89c2 Mon Sep 17 00:00:00 2001 From: PetyaMarkovaBogdanova Date: Tue, 12 Aug 2025 16:12:50 +0300 Subject: [PATCH 1/9] chore(ui5-toolbar): toolbar item wrapper introduced --- packages/main/src/ToolbarItem.ts | 25 ++++++++++++++++++++++- packages/main/src/ToolbarItemTemplate.tsx | 5 +++++ packages/main/test/pages/Toolbar.html | 7 ++++++- 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 packages/main/src/ToolbarItemTemplate.tsx diff --git a/packages/main/src/ToolbarItem.ts b/packages/main/src/ToolbarItem.ts index 44f55f1f6c37..5da94afeab22 100644 --- a/packages/main/src/ToolbarItem.ts +++ b/packages/main/src/ToolbarItem.ts @@ -1,6 +1,10 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import property from "@ui5/webcomponents-base/dist/decorators/property.js"; import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; +import slot from "@ui5/webcomponents-base/dist/decorators/slot.js"; +import jsxRenderer from "@ui5/webcomponents-base/dist/renderer/JsxRenderer.js"; +import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js"; +import ToolbarItemTemplate from "./ToolbarItemTemplate.js"; import type ToolbarItemOverflowBehavior from "./types/ToolbarItemOverflowBehavior.js"; @@ -16,13 +20,19 @@ type ToolbarItemEventDetail = { bubbles: true, }) +@customElement({ + tag: "ui5-toolbar-item", + languageAware: true, + renderer: jsxRenderer, + template: ToolbarItemTemplate, +}) + /** * @class * * Represents an abstract class for items, used in the `ui5-toolbar`. * @constructor * @extends UI5Element - * @abstract * @public * @since 1.17.0 */ @@ -60,6 +70,17 @@ class ToolbarItem extends UI5Element { @property({ type: Boolean }) isOverflowed: boolean = false; + /** + * Defines if the toolbar item is overflowed. + * @default false + * @since 2.11.0 + */ + + @slot({ + "default": true, type: HTMLElement, invalidateOnChildChange: true, + }) + item!: HTMLElement | undefined; + /** * Defines if the width of the item should be ignored in calculating the whole width of the toolbar * @protected @@ -113,4 +134,6 @@ export type { IEventOptions, ToolbarItemEventDetail, }; +ToolbarItem.define(); + export default ToolbarItem; diff --git a/packages/main/src/ToolbarItemTemplate.tsx b/packages/main/src/ToolbarItemTemplate.tsx new file mode 100644 index 000000000000..d45096879aca --- /dev/null +++ b/packages/main/src/ToolbarItemTemplate.tsx @@ -0,0 +1,5 @@ +export default function ToolbarItemTemplate() { + return ( + + ); +} diff --git a/packages/main/test/pages/Toolbar.html b/packages/main/test/pages/Toolbar.html index de6b72c48bcf..26665d25a51b 100644 --- a/packages/main/test/pages/Toolbar.html +++ b/packages/main/test/pages/Toolbar.html @@ -77,7 +77,9 @@ - + + Call me later +

@@ -115,6 +117,9 @@ + + User Menu +
From 7c49aa42e9ccfce74741c916654d8d874d76d94e Mon Sep 17 00:00:00 2001 From: PetyaMarkovaBogdanova Date: Tue, 9 Sep 2025 17:31:01 +0300 Subject: [PATCH 2/9] chore(ui5-toolbar-item): wrappers introduced --- packages/main/cypress/specs/Toolbar.cy.tsx | 148 +++++++++++++++++---- packages/main/src/ToolbarItem.ts | 23 ++++ packages/main/src/ToolbarItemTemplate.tsx | 8 +- packages/main/test/pages/Toolbar.html | 8 +- 4 files changed, 157 insertions(+), 30 deletions(-) diff --git a/packages/main/cypress/specs/Toolbar.cy.tsx b/packages/main/cypress/specs/Toolbar.cy.tsx index 45da94b0a372..81cf00445137 100644 --- a/packages/main/cypress/specs/Toolbar.cy.tsx +++ b/packages/main/cypress/specs/Toolbar.cy.tsx @@ -4,7 +4,7 @@ import ToolbarSelect from "../../src/ToolbarSelect.js"; import ToolbarSelectOption from "../../src/ToolbarSelectOption.js"; import ToolbarSeparator from "../../src/ToolbarSeparator.js"; import ToolbarSpacer from "../../src/ToolbarSpacer.js"; -import type ToolbarItem from "../../src/ToolbarItem.js"; +import ToolbarItem from "../../src/ToolbarItem.js"; import add from "@ui5/webcomponents-icons/dist/add.js"; import decline from "@ui5/webcomponents-icons/dist/decline.js"; import employee from "@ui5/webcomponents-icons/dist/employee.js"; @@ -325,20 +325,20 @@ describe("Toolbar general interaction", () => { it("Should render ui5-button by toolbar template, when slotting ui5-toolbar-button elements", () => { cy.mount( - - ); - + cy.get("[ui5-toolbar]") .find("[ui5-toolbar-button]") .first() @@ -353,51 +353,51 @@ describe("Toolbar general interaction", () => { .should("be.visible") .should("have.length", 2); }); - + it("Should call child events only once", () => { cy.mount( <> - - ); - + // Create stubs for event tracking cy.get("[data-testid='clickCountToolbar']") .as("toolbar") .then($toolbar => { $toolbar.get(0).addEventListener("click", cy.stub().as("toolbarClickStub")); }); - + cy.get("[data-testid='clickCounter']") .as("clickCounter") .then($button => { $button.get(0).addEventListener("click", cy.stub().as("counterClickStub")); }); - + cy.get("[data-testid='clearCounter']") .as("clearCounter") .then($button => { $button.get(0).addEventListener("click", cy.stub().as("clearClickStub")); }); - + // Set up input manipulation logic cy.get("@toolbar").then($toolbar => { $toolbar.get(0).addEventListener("click", (e) => { const input = document.querySelector("[data-testid='input']") as HTMLInputElement; const target = e.target as HTMLElement; - + if (target.dataset.testid === "clearCounter") { input.value = "0"; } else if (target.dataset.testid === "clickCounter") { @@ -406,16 +406,16 @@ describe("Toolbar general interaction", () => { } }); }); - + cy.get("[data-testid='input']").invoke("val", "0"); - + cy.get("@clickCounter").realClick(); - + cy.get("[data-testid='input']").should("have.prop", "value", "1"); - + cy.get("@toolbarClickStub").should("have.been.calledOnce"); cy.get("@counterClickStub").should("have.been.calledOnce"); - + cy.get("[data-testid='input']").invoke("val", "0"); }); }); @@ -620,3 +620,99 @@ describe("Toolbar Button", () => { cy.get("#value-input").should("have.value", "1"); }); }); + +describe("Toolbar Item", () => { + it("Should render ui5-toolbar-item with correct properties and not suppress events", () => { + // Mount the Toolbar with a ui5-toolbar-item wrapping a web component + cy.mount( + + + + + + ); + + // Verify the ui5-toolbar-item has the correct properties + cy.get("ui5-toolbar-item").should((item) => { + expect(item).to.have.attr("prevent-overflow-closing"); + expect(item).to.have.attr("overflow-priority", "AlwaysOverflow"); + }); + + // Verify the inner component (ui5-button) is rendered + cy.get("ui5-toolbar-item") + .find("ui5-button").should((button) => { + expect(button).to.exist; + expect(button).to.contain.text("User Menu"); + }); + + // Attach a click event to the inner button + cy.get("ui5-button#innerButton") + .then(button => { + button.get(0).addEventListener("click", cy.stub().as("buttonClicked")); + }); + + // Trigger a click event on the inner button + cy.get("ui5-button#innerButton").click(); + + // Verify the click event was triggered + cy.get("@buttonClicked").should("have.been.calledOnce"); + }); + + it("Should respect prevent-overflow-closing property", () => { + // Mount the Toolbar with a ui5-toolbar-item + cy.mount( + + + + + + ); + + // Simulate overflow behavior + cy.get("ui5-toolbar-item") + .invoke("attr", "prevent-overflow-closing") + .should("exist"); + + // Verify the inner button is still visible and not hidden + cy.get("ui5-toolbar-item") + .find("ui5-button") + .should("be.visible"); + + cy.get("ui5-toolbar-item") + .find("ui5-button") + .realClick(); + expect(cy.get("ui5-popover").should("be.visible")); + }); + + it("Should respect overflow-priority property", () => { + // Mount the Toolbar with multiple ui5-toolbar-items + cy.mount( + + + + + + + + + ); + + // Verify the overflow-priority property is respected + cy.get("ui5-toolbar-item[overflow-priority='AlwaysOverflow']") + .should("exist") + .should("have.attr", "overflow-priority", "AlwaysOverflow"); + + cy.get("ui5-toolbar-item[overflow-priority='NeverOverflow']") + .should("exist") + .should("have.attr", "overflow-priority", "NeverOverflow"); + + // Simulate overflow behavior and ensure high-priority item remains visible + cy.viewport(300, 1080); // Simulate a smaller viewport + cy.get("ui5-toolbar-item[overflow-priority='NeverOverflow']") + .should("be.visible"); + + // Ensure low-priority item is hidden or moved to overflow + cy.get("ui5-toolbar-item[overflow-priority='AlwaysOverflow']") + .should("not.be.visible"); + }); +}) diff --git a/packages/main/src/ToolbarItem.ts b/packages/main/src/ToolbarItem.ts index 5da94afeab22..6d8a0fa6f051 100644 --- a/packages/main/src/ToolbarItem.ts +++ b/packages/main/src/ToolbarItem.ts @@ -20,6 +20,10 @@ type ToolbarItemEventDetail = { bubbles: true, }) +@event("click", { + bubbles: true, +}) + @customElement({ tag: "ui5-toolbar-item", languageAware: true, @@ -128,6 +132,25 @@ class ToolbarItem extends UI5Element { }, }; } + + _onClick = this.onClick.bind(this); + + constructor() { + super(); + } + + /** + * Handles the click event on the toolbar item. + * It stops the event propagation and fires a "click" event with the target reference. + * If `preventOverflowClosing` is false, it will also fire a "close-overflow" event. + * @param {Event} e - The click event + */ + onClick(e: Event): void { + e.stopImmediatePropagation(); + if (!this.preventOverflowClosing) { + this.fireDecoratorEvent("close-overflow"); + } + } } export type { diff --git a/packages/main/src/ToolbarItemTemplate.tsx b/packages/main/src/ToolbarItemTemplate.tsx index d45096879aca..32898b7ea647 100644 --- a/packages/main/src/ToolbarItemTemplate.tsx +++ b/packages/main/src/ToolbarItemTemplate.tsx @@ -1,5 +1,9 @@ -export default function ToolbarItemTemplate() { +import type ToolbarItem from "./ToolbarItem.js"; + +export default function ToolbarItemTemplate(this: ToolbarItem) { return ( - +
+ +
); } diff --git a/packages/main/test/pages/Toolbar.html b/packages/main/test/pages/Toolbar.html index 26665d25a51b..bcd053bda1e2 100644 --- a/packages/main/test/pages/Toolbar.html +++ b/packages/main/test/pages/Toolbar.html @@ -117,8 +117,8 @@ - - User Menu + + User Menu
@@ -403,6 +403,10 @@ menu2.open = !menu2.open; menu2.opener = btnOpenMenu2; }); + + tralala.addEventListener("ui5-click", function(event) { + alert("clicked"); + }); From 6169477425dc18994c1c0257ee721dbf7def634e Mon Sep 17 00:00:00 2001 From: PetyaMarkovaBogdanova Date: Wed, 10 Sep 2025 14:40:50 +0300 Subject: [PATCH 3/9] chore(ui5-toolbar-item): toolbar wrappers --- packages/main/cypress/specs/Toolbar.cy.tsx | 69 +++++++++++++++------- 1 file changed, 48 insertions(+), 21 deletions(-) diff --git a/packages/main/cypress/specs/Toolbar.cy.tsx b/packages/main/cypress/specs/Toolbar.cy.tsx index 7d9ce5382a43..aef436a9a83a 100644 --- a/packages/main/cypress/specs/Toolbar.cy.tsx +++ b/packages/main/cypress/specs/Toolbar.cy.tsx @@ -611,30 +611,57 @@ describe("Toolbar Item", () => { }); it("Should respect prevent-overflow-closing property", () => { - // Mount the Toolbar with a ui5-toolbar-item - cy.mount( - - - - - - ); + // Mount the Toolbar with constrained width to force overflow + cy.mount( +
+ + + + + + + + +
+ ); - // Simulate overflow behavior - cy.get("ui5-toolbar-item") - .invoke("attr", "prevent-overflow-closing") - .should("exist"); + // Wait for overflow processing + cy.wait(500); - // Verify the inner button is still visible and not hidden - cy.get("ui5-toolbar-item") - .find("ui5-button") - .should("be.visible"); + // Click the overflow button to open the popover + cy.get("ui5-toolbar") + .shadow() + .find(".ui5-tb-overflow-btn") + .click(); - cy.get("ui5-toolbar-item") - .find("ui5-button") - .realClick(); - expect(cy.get("ui5-popover").should("be.visible")); - }); + // Verify the popover is open + cy.get("ui5-toolbar") + .shadow() + .find(".ui5-overflow-popover") + .should("have.prop", "open", true); + + // Click on the item with prevent-overflow-closing + cy.get("ui5-toolbar-item[prevent-overflow-closing]") + .find("ui5-button") + .click(); + + // Verify the popover remains open + cy.get("ui5-toolbar") + .shadow() + .find(".ui5-overflow-popover") + .should("have.prop", "open", true); + + // Optional: Test that normal items still close the popover + cy.get("ui5-toolbar-item:not([prevent-overflow-closing])") + .find("ui5-button") + .click(); + + // Verify the popover closes + cy.get("ui5-toolbar") + .shadow() + .find(".ui5-overflow-popover") + .should("have.prop", "open", false); + }); it("Should respect overflow-priority property", () => { // Mount the Toolbar with multiple ui5-toolbar-items From 6d61c76a38082785207104aa8df9a22d79072ef5 Mon Sep 17 00:00:00 2001 From: PetyaMarkovaBogdanova Date: Wed, 10 Sep 2025 16:18:41 +0300 Subject: [PATCH 4/9] chore(ui5-toolbar): toolbar item wrapper introduced --- packages/main/src/ToolbarItem.ts | 5 +- packages/main/src/ToolbarItemTemplate.tsx | 2 +- packages/main/test/pages/Toolbar.html | 7 -- packages/main/test/pages/ToolbarWrappers.html | 68 +++++++++++++++++++ 4 files changed, 70 insertions(+), 12 deletions(-) create mode 100644 packages/main/test/pages/ToolbarWrappers.html diff --git a/packages/main/src/ToolbarItem.ts b/packages/main/src/ToolbarItem.ts index 6d8a0fa6f051..5db9aae6aead 100644 --- a/packages/main/src/ToolbarItem.ts +++ b/packages/main/src/ToolbarItem.ts @@ -133,16 +133,13 @@ class ToolbarItem extends UI5Element { }; } - _onClick = this.onClick.bind(this); - constructor() { super(); } /** * Handles the click event on the toolbar item. - * It stops the event propagation and fires a "click" event with the target reference. - * If `preventOverflowClosing` is false, it will also fire a "close-overflow" event. + * If `preventOverflowClosing` is false, it will fire a "close-overflow" event. * @param {Event} e - The click event */ onClick(e: Event): void { diff --git a/packages/main/src/ToolbarItemTemplate.tsx b/packages/main/src/ToolbarItemTemplate.tsx index 32898b7ea647..12126b0b4f48 100644 --- a/packages/main/src/ToolbarItemTemplate.tsx +++ b/packages/main/src/ToolbarItemTemplate.tsx @@ -2,7 +2,7 @@ import type ToolbarItem from "./ToolbarItem.js"; export default function ToolbarItemTemplate(this: ToolbarItem) { return ( -
+
); diff --git a/packages/main/test/pages/Toolbar.html b/packages/main/test/pages/Toolbar.html index bcd053bda1e2..8dcbe57ea41e 100644 --- a/packages/main/test/pages/Toolbar.html +++ b/packages/main/test/pages/Toolbar.html @@ -117,9 +117,6 @@ - - User Menu -
@@ -403,10 +400,6 @@ menu2.open = !menu2.open; menu2.opener = btnOpenMenu2; }); - - tralala.addEventListener("ui5-click", function(event) { - alert("clicked"); - }); diff --git a/packages/main/test/pages/ToolbarWrappers.html b/packages/main/test/pages/ToolbarWrappers.html new file mode 100644 index 000000000000..8a0d4f2b9024 --- /dev/null +++ b/packages/main/test/pages/ToolbarWrappers.html @@ -0,0 +1,68 @@ + + + + + + + Toolbar + + + + + + + + +
+ Standard Toolbar with ToolbarSelect and ToolbarButton +
+
+ + + + + + + + + + + 1 + 2 + 3 + + + + + +
+ Toolbar with ui5-select and ui5-button wrapped in ui5-toolbar-item +
+
+ + Left 1 (long) + Left 2 + Left 3 + Left 4 + Mid 1 + Mid 2 + Right 1 + Right 4 + + + 1 + 2 + 3 + + + + + + Call me later + + +
+
+ + + \ No newline at end of file From 84607fbc0bf8ff2c1371d944af6704913fce3234 Mon Sep 17 00:00:00 2001 From: PetyaMarkovaBogdanova Date: Wed, 10 Sep 2025 17:04:00 +0300 Subject: [PATCH 5/9] chore(ui5-toolbar): toolbar item wrapper introduced --- packages/main/src/ToolbarItem.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/main/src/ToolbarItem.ts b/packages/main/src/ToolbarItem.ts index 5db9aae6aead..02f193b63382 100644 --- a/packages/main/src/ToolbarItem.ts +++ b/packages/main/src/ToolbarItem.ts @@ -140,7 +140,7 @@ class ToolbarItem extends UI5Element { /** * Handles the click event on the toolbar item. * If `preventOverflowClosing` is false, it will fire a "close-overflow" event. - * @param {Event} e - The click event + * @param {Event} e */ onClick(e: Event): void { e.stopImmediatePropagation(); From 8b60ec7d94814292970fffcdb3b05fcc206c0d79 Mon Sep 17 00:00:00 2001 From: PetyaMarkovaBogdanova Date: Wed, 10 Sep 2025 17:22:11 +0300 Subject: [PATCH 6/9] chore(ui5-toolbar): toolbar item wrapper introduced --- packages/main/src/ToolbarItem.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/main/src/ToolbarItem.ts b/packages/main/src/ToolbarItem.ts index 02f193b63382..69cdd74410a6 100644 --- a/packages/main/src/ToolbarItem.ts +++ b/packages/main/src/ToolbarItem.ts @@ -140,7 +140,6 @@ class ToolbarItem extends UI5Element { /** * Handles the click event on the toolbar item. * If `preventOverflowClosing` is false, it will fire a "close-overflow" event. - * @param {Event} e */ onClick(e: Event): void { e.stopImmediatePropagation(); From fed79a56873bc137f032f51aa9542ec1b1df1c7e Mon Sep 17 00:00:00 2001 From: PetyaMarkovaBogdanova Date: Tue, 16 Sep 2025 11:25:29 +0300 Subject: [PATCH 7/9] chore(ui5-toolbar-item): item wrapers introduced --- packages/main/src/ToolbarItem.ts | 11 ++---- packages/main/test/pages/ToolbarWrappers.html | 37 +++++++++++++++++++ 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/packages/main/src/ToolbarItem.ts b/packages/main/src/ToolbarItem.ts index 69cdd74410a6..a0cfca51b705 100644 --- a/packages/main/src/ToolbarItem.ts +++ b/packages/main/src/ToolbarItem.ts @@ -20,10 +20,6 @@ type ToolbarItemEventDetail = { bubbles: true, }) -@event("click", { - bubbles: true, -}) - @customElement({ tag: "ui5-toolbar-item", languageAware: true, @@ -75,9 +71,9 @@ class ToolbarItem extends UI5Element { isOverflowed: boolean = false; /** - * Defines if the toolbar item is overflowed. - * @default false - * @since 2.11.0 + * Wrapped component slot. + * @public + * @since 2.15.0 */ @slot({ @@ -142,7 +138,6 @@ class ToolbarItem extends UI5Element { * If `preventOverflowClosing` is false, it will fire a "close-overflow" event. */ onClick(e: Event): void { - e.stopImmediatePropagation(); if (!this.preventOverflowClosing) { this.fireDecoratorEvent("close-overflow"); } diff --git a/packages/main/test/pages/ToolbarWrappers.html b/packages/main/test/pages/ToolbarWrappers.html index 8a0d4f2b9024..1b000f9d3a58 100644 --- a/packages/main/test/pages/ToolbarWrappers.html +++ b/packages/main/test/pages/ToolbarWrappers.html @@ -62,6 +62,43 @@ + Toolbar with various components +
+
+ + + + + + Simple text + + + + + + + + + + + + + + + + + + Simple title + + + + + +
div with Link and text
+
+ +
+
From 669a44a31d749a1d2a58845266b78285de2cc86f Mon Sep 17 00:00:00 2001 From: PetyaMarkovaBogdanova Date: Tue, 16 Sep 2025 14:06:38 +0300 Subject: [PATCH 8/9] chore(ui5-toolbar-item): items wrappers introduced --- packages/main/src/ToolbarItem.ts | 4 ++-- packages/main/test/pages/ToolbarWrappers.html | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/main/src/ToolbarItem.ts b/packages/main/src/ToolbarItem.ts index 35064129c6f2..6bac1967fab1 100644 --- a/packages/main/src/ToolbarItem.ts +++ b/packages/main/src/ToolbarItem.ts @@ -142,8 +142,8 @@ class ToolbarItem extends UI5Element { * Handles the click event on the toolbar item. * If `preventOverflowClosing` is false, it will fire a "close-overflow" event. */ - onClick(e: Event): void { - if (!this.preventOverflowClosing) { + onClick(e?: Event): void { + if (e && !this.preventOverflowClosing) { this.fireDecoratorEvent("close-overflow"); } } diff --git a/packages/main/test/pages/ToolbarWrappers.html b/packages/main/test/pages/ToolbarWrappers.html index 1b000f9d3a58..99749b1b75aa 100644 --- a/packages/main/test/pages/ToolbarWrappers.html +++ b/packages/main/test/pages/ToolbarWrappers.html @@ -73,7 +73,7 @@ Simple text - + From 9a1252234a32c16e718b92f93750c166029f2466 Mon Sep 17 00:00:00 2001 From: PetyaMarkovaBogdanova Date: Tue, 16 Sep 2025 14:20:04 +0300 Subject: [PATCH 9/9] chore(ui5-toolbar): toolbar item wrapper introduced --- packages/main/test/pages/ToolbarWrappers.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/main/test/pages/ToolbarWrappers.html b/packages/main/test/pages/ToolbarWrappers.html index 99749b1b75aa..f105eaf9ef98 100644 --- a/packages/main/test/pages/ToolbarWrappers.html +++ b/packages/main/test/pages/ToolbarWrappers.html @@ -69,7 +69,7 @@ - + Simple text