Skip to content

Commit fc063f0

Browse files
authored
fix(ui5-toolbar-select): sync programmatic selection (#12790)
Programmatic changes to ToolbarSelectOption.selected property now properly synchronize with the internal Select component and maintain single selection. - Add custom property setter for ToolbarSelectOption.selected - Ensure sibling options are deselected when one is programmatically selected - Sync selection state to internal Select component value - Modify _syncOptions to use property setter for unified selection handling - Maintain backward compatibility for mouse-based selection - Add cypress test Fixes: #12619
1 parent 878d8a3 commit fc063f0

File tree

3 files changed

+66
-6
lines changed

3 files changed

+66
-6
lines changed

packages/main/cypress/specs/ToolbarSelect.cy.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,4 +344,42 @@ describe("Toolbar general interaction", () => {
344344
.eq(0)
345345
.should("not.have.attr", "selected");
346346
});
347+
348+
it("Should ensure only one option is selected at any time", () => {
349+
cy.mount(
350+
<>
351+
<Toolbar>
352+
<ToolbarSelect>
353+
<ToolbarSelectOption id="opt1">1</ToolbarSelectOption>
354+
<ToolbarSelectOption id="opt2">2</ToolbarSelectOption>
355+
<ToolbarSelectOption id="opt3">3</ToolbarSelectOption>
356+
</ToolbarSelect>
357+
</Toolbar>
358+
<Button id="selectMultiple">Select Multiple</Button>
359+
</>
360+
);
361+
362+
// Set up button to attempt selecting multiple options
363+
cy.get("#selectMultiple").then($btn => {
364+
$btn.get(0).addEventListener("ui5-click", () => {
365+
const opt1 = document.getElementById("opt1") as ToolbarSelectOption;
366+
const opt2 = document.getElementById("opt2") as ToolbarSelectOption;
367+
const opt3 = document.getElementById("opt3") as ToolbarSelectOption;
368+
369+
// Try to select multiple options
370+
opt1.selected = true;
371+
opt2.selected = true;
372+
opt3.selected = true; // This should be the final selection
373+
});
374+
});
375+
376+
// Click button to attempt multiple selections
377+
cy.get("#selectMultiple").realClick();
378+
379+
// Verify only the last option (opt3) is selected
380+
cy.get("[ui5-toolbar-select-option]").eq(2).should("have.attr", "selected");
381+
cy.get("[ui5-toolbar-select-option]").eq(0).should("not.have.attr", "selected");
382+
cy.get("[ui5-toolbar-select-option]").eq(1).should("not.have.attr", "selected");
383+
cy.get("ui5-select", { includeShadowDom: true }).should("have.attr", "value", "3");
384+
});
347385
});

packages/main/src/ToolbarSelect.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -201,11 +201,7 @@ class ToolbarSelect extends ToolbarItem {
201201
_syncOptions(selectedOption: HTMLElement): void {
202202
const selectedOptionIndex = Number(selectedOption?.getAttribute("data-ui5-external-action-item-index"));
203203
this.options.forEach((option: ToolbarSelectOption, index: number) => {
204-
if (index === selectedOptionIndex) {
205-
option.setAttribute("selected", "");
206-
} else {
207-
option.removeAttribute("selected");
208-
}
204+
option.selected = index === selectedOptionIndex;
209205
});
210206
}
211207

packages/main/src/ToolbarSelectOption.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
22
import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js";
33
import slot from "@ui5/webcomponents-base/dist/decorators/slot.js";
44
import property from "@ui5/webcomponents-base/dist/decorators/property.js";
5+
import type ToolbarSelect from "./ToolbarSelect.js";
56

67
/**
78
* @class
@@ -23,7 +24,32 @@ class ToolbarSelectOption extends UI5Element {
2324
* @public
2425
*/
2526
@property({ type: Boolean })
26-
selected = false;
27+
set selected(value: boolean) {
28+
if (value) {
29+
this.setAttribute("selected", "");
30+
this._clearSiblingsAndSync();
31+
} else {
32+
this.removeAttribute("selected");
33+
}
34+
}
35+
36+
get selected(): boolean {
37+
return this.hasAttribute("selected");
38+
}
39+
40+
_clearSiblingsAndSync(): void {
41+
const parent = this.parentElement as ToolbarSelect;
42+
if (parent) {
43+
parent.options?.forEach(option => {
44+
if (option !== this) {
45+
option.removeAttribute("selected");
46+
}
47+
});
48+
if (parent.select) {
49+
parent.select.value = this.textContent || "";
50+
}
51+
}
52+
}
2753

2854
/**
2955
* Defines the text of the component.

0 commit comments

Comments
 (0)