diff --git a/packages/main/cypress/specs/Toolbar.cy.tsx b/packages/main/cypress/specs/Toolbar.cy.tsx index 6d54e72cf7c6..ef51d3385bea 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"; @@ -617,3 +617,126 @@ describe("Toolbar Button", () => { }); }); }); + +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 constrained width to force overflow + cy.mount( +
+ + + + + + + + +
+ ); + + // Wait for overflow processing + cy.wait(500); + + // Click the overflow button to open the popover + cy.get("ui5-toolbar") + .shadow() + .find(".ui5-tb-overflow-btn") + .click(); + + // 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 + 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 db9f5057e015..6bac1967fab1 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 */ @@ -65,6 +75,17 @@ class ToolbarItem extends UI5Element { onAfterRendering(): void { this._isRendering = false; } + /** + * Wrapped component slot. + * @public + * @since 2.15.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 @@ -112,10 +133,26 @@ class ToolbarItem extends UI5Element { }, }; } + + constructor() { + super(); + } + + /** + * Handles the click event on the toolbar item. + * If `preventOverflowClosing` is false, it will fire a "close-overflow" event. + */ + onClick(e?: Event): void { + if (e && !this.preventOverflowClosing) { + this.fireDecoratorEvent("close-overflow"); + } + } } 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..12126b0b4f48 --- /dev/null +++ b/packages/main/src/ToolbarItemTemplate.tsx @@ -0,0 +1,9 @@ +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 de6b72c48bcf..8dcbe57ea41e 100644 --- a/packages/main/test/pages/Toolbar.html +++ b/packages/main/test/pages/Toolbar.html @@ -77,7 +77,9 @@ - + + Call me later +

diff --git a/packages/main/test/pages/ToolbarWrappers.html b/packages/main/test/pages/ToolbarWrappers.html new file mode 100644 index 000000000000..f105eaf9ef98 --- /dev/null +++ b/packages/main/test/pages/ToolbarWrappers.html @@ -0,0 +1,105 @@ + + + + + + + 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 + + +
+ Toolbar with various components +
+
+ + + + + + Simple text + + + + + + + + + + + + + + + + + + Simple title + + + + + +
div with Link and text
+
+ +
+
+
+ + + \ No newline at end of file