From e0de80f399ca49cf54e929ff68243835adf31bbb Mon Sep 17 00:00:00 2001 From: Nikola Anachkov Date: Thu, 9 Jul 2026 14:22:03 +0300 Subject: [PATCH 1/3] feat(ui5-toolbar-select): add value prop to ToolbarSelectOption and selectedToolbarOption in change event --- .../main/cypress/specs/ToolbarSelect.cy.tsx | 144 ++++++++++++++++++ packages/main/src/ToolbarSelect.ts | 10 +- packages/main/src/ToolbarSelectOption.ts | 11 +- packages/main/src/ToolbarSelectTemplate.tsx | 1 + 4 files changed, 163 insertions(+), 3 deletions(-) diff --git a/packages/main/cypress/specs/ToolbarSelect.cy.tsx b/packages/main/cypress/specs/ToolbarSelect.cy.tsx index f7c1fef6a698c..786e8579e1721 100644 --- a/packages/main/cypress/specs/ToolbarSelect.cy.tsx +++ b/packages/main/cypress/specs/ToolbarSelect.cy.tsx @@ -111,6 +111,150 @@ describe("Toolbar general interaction", () => { .should("have.attr", "accessible-name-ref", "title"); }); + it("Should expose value and selectedToolbarOption in change event detail", () => { + cy.mount( + <> + + + Option 1 + Option 2 + Option 3 + + + + + + ); + + cy.get("[ui5-toolbar-select]").then($select => { + $select.get(0).addEventListener("ui5-change", (e: Event) => { + const ce = e as CustomEvent; + (document.querySelector("[data-testid='result-value']") as HTMLInputElement).value = ce.detail.selectedOption.value; + (document.querySelector("[data-testid='result-toolbar-option']") as HTMLInputElement).value = ce.detail.selectedToolbarOption.value; + }); + }); + + cy.get("[ui5-toolbar]") + .find("[ui5-toolbar-select]") + .shadow() + .find("[ui5-select]") + .realClick(); + + cy.get("[ui5-toolbar]") + .find("[ui5-toolbar-select]") + .shadow() + .find("[ui5-select]") + .realPress("ArrowUp"); + + cy.get("[ui5-toolbar]") + .find("[ui5-toolbar-select]") + .shadow() + .find("[ui5-select]") + .realPress("Enter"); + + cy.get("[data-testid='result-value']").should("have.prop", "value", "opt1"); + cy.get("[data-testid='result-toolbar-option']").should("have.prop", "value", "opt1"); + }); + + it("Should expose correct selectedToolbarOption for duplicate text options", () => { + cy.mount( + <> + + + Pending + Active + Pending + + + + + ); + + cy.get("[ui5-toolbar-select]").then($select => { + $select.get(0).addEventListener("ui5-change", (e: Event) => { + const ce = e as CustomEvent; + (document.querySelector("[data-testid='dup-result-value']") as HTMLInputElement).value = ce.detail.selectedToolbarOption.value; + }); + }); + + cy.get("[ui5-toolbar]") + .find("[ui5-toolbar-select]") + .shadow() + .find("[ui5-select]") + .realClick(); + + cy.get("[ui5-toolbar]") + .find("[ui5-toolbar-select]") + .shadow() + .find("[ui5-select]") + .realPress("ArrowDown"); + + cy.get("[ui5-toolbar]") + .find("[ui5-toolbar-select]") + .shadow() + .find("[ui5-select]") + .realPress("ArrowDown"); + + cy.get("[ui5-toolbar]") + .find("[ui5-toolbar-select]") + .shadow() + .find("[ui5-select]") + .realPress("Enter"); + + cy.get("[data-testid='dup-result-value']").should("have.prop", "value", "pending-urgent"); + }); + + it("Should work correctly when options have no value property set", () => { + cy.mount( + <> + + + Option A + Option B + Option C + + + + + ); + + cy.get("[ui5-toolbar-select]").then($select => { + $select.get(0).addEventListener("ui5-change", (e: Event) => { + const ce = e as CustomEvent; + (document.querySelector("[data-testid='no-value-result']") as HTMLInputElement).value = ce.detail.selectedToolbarOption.textContent?.trim() ?? ""; + }); + }); + + cy.get("[ui5-toolbar]") + .find("[ui5-toolbar-select]") + .shadow() + .find("[ui5-select]") + .realClick(); + + cy.get("[ui5-toolbar]") + .find("[ui5-toolbar-select]") + .shadow() + .find("[ui5-select]") + .realPress("ArrowDown"); + + cy.get("[ui5-toolbar]") + .find("[ui5-toolbar-select]") + .shadow() + .find("[ui5-select]") + .realPress("Enter"); + + cy.get("[data-testid='no-value-result']").should("have.prop", "value", "Option B"); + + // Verify the internal select still shows the correct option selected + cy.get("[ui5-toolbar]") + .find("[ui5-toolbar-select]") + .shadow() + .find("[ui5-select]") + .find("[ui5-option]") + .eq(1) + .should("have.attr", "selected"); + }); + it("Should fire change event on selection change", () => { cy.mount( <> diff --git a/packages/main/src/ToolbarSelect.ts b/packages/main/src/ToolbarSelect.ts index 5885a16ade5f3..5948812586fd0 100644 --- a/packages/main/src/ToolbarSelect.ts +++ b/packages/main/src/ToolbarSelect.ts @@ -15,7 +15,9 @@ import type ToolbarSelectOption from "./ToolbarSelectOption.js"; import type { SelectChangeEventDetail } from "./Select.js"; import type { DefaultSlot, Slot } from "@ui5/webcomponents-base/dist/UI5Element.js"; -type ToolbarSelectChangeEventDetail = ToolbarItemEventDetail & SelectChangeEventDetail; +type ToolbarSelectChangeEventDetail = ToolbarItemEventDetail & SelectChangeEventDetail & { + selectedToolbarOption: ToolbarSelectOption; +}; /** * @class @@ -44,6 +46,8 @@ type ToolbarSelectChangeEventDetail = ToolbarItemEventDetail & SelectChangeEvent /** * Fired when the selected option changes. * @param {HTMLElement} selectedOption the selected option. + * @param {HTMLElement} selectedToolbarOption the original toolbar select option. + * @since 2.24.0 * @public */ @event("change", { @@ -193,7 +197,9 @@ class ToolbarSelect extends ToolbarItemBase { onChange(e: CustomEvent): void { e.stopImmediatePropagation(); - const prevented = !this.fireDecoratorEvent("change", { ...e.detail, targetRef: e.target as HTMLElement }); + const selectedOptionIndex = Number(e.detail.selectedOption?.getAttribute("data-ui5-external-action-item-index")); + const selectedToolbarOption = this.options[selectedOptionIndex]; + const prevented = !this.fireDecoratorEvent("change", { ...e.detail, targetRef: e.target as HTMLElement, selectedToolbarOption }); if (!prevented) { this.fireDecoratorEvent("close-overflow"); } diff --git a/packages/main/src/ToolbarSelectOption.ts b/packages/main/src/ToolbarSelectOption.ts index d89aed22e6975..e7bb538d342fd 100644 --- a/packages/main/src/ToolbarSelectOption.ts +++ b/packages/main/src/ToolbarSelectOption.ts @@ -19,6 +19,15 @@ import type ToolbarSelect from "./ToolbarSelect.js"; */ @customElement("ui5-toolbar-select-option") class ToolbarSelectOption extends UI5Element { + /** + * Defines the value of the component. + * @default undefined + * @public + * @since 2.24.0 + */ + @property() + value?: string; + /** * Defines the selected state of the component. * @default false @@ -47,7 +56,7 @@ class ToolbarSelectOption extends UI5Element { } }); if (parent.select) { - parent.select.value = this.textContent || ""; + parent.select.value = this.value !== undefined ? this.value : (this.textContent || ""); } } } diff --git a/packages/main/src/ToolbarSelectTemplate.tsx b/packages/main/src/ToolbarSelectTemplate.tsx index 28e1f2c1dc3e6..b1ffef24f03b2 100644 --- a/packages/main/src/ToolbarSelectTemplate.tsx +++ b/packages/main/src/ToolbarSelectTemplate.tsx @@ -25,6 +25,7 @@ export default function ToolbarSelectTemplate(this: ToolbarSelect) { {this.options.map((option, index) => (