From cbec09ea0a823da0bdb08a2613d1b8ab4197dd2e Mon Sep 17 00:00:00 2001 From: i518532 Date: Wed, 28 Jan 2026 09:20:07 +0200 Subject: [PATCH 1/4] feat(ui5-multi-combobox): intrduce loading property --- packages/main/cypress/specs/ComboBox.cy.tsx | 90 +++++++++++++++++++ .../main/cypress/specs/MultiComboBox.cy.tsx | 90 +++++++++++++++++++ packages/main/src/ComboBoxPopoverTemplate.tsx | 8 +- packages/main/src/MultiComboBox.ts | 12 ++- .../main/src/MultiComboBoxPopoverTemplate.tsx | 13 ++- .../main/src/themes/MultiComboBoxPopover.css | 17 ++++ packages/main/test/pages/ComboBox.html | 21 ++++- packages/main/test/pages/MultiComboBox.html | 44 ++++++--- 8 files changed, 273 insertions(+), 22 deletions(-) diff --git a/packages/main/cypress/specs/ComboBox.cy.tsx b/packages/main/cypress/specs/ComboBox.cy.tsx index cbea94de23ec..f87d54344319 100644 --- a/packages/main/cypress/specs/ComboBox.cy.tsx +++ b/packages/main/cypress/specs/ComboBox.cy.tsx @@ -2974,6 +2974,96 @@ describe("ComboBox Composition", () => { }); }); +describe("Loading State", () => { + it("should display busy indicator when loading is true", () => { + cy.mount( + + + + + ); + + cy.get("[ui5-combobox]") + .shadow() + .find("ui5-responsive-popover") + .as("popover"); + + cy.get("@popover") + .find("ui5-busy-indicator") + .should("exist"); + + cy.get("@popover") + .find("ui5-list") + .should("not.exist"); + }); + + it("should hide busy indicator and show items when loading becomes false", () => { + cy.mount( + + + + + ); + + cy.get("[ui5-combobox]") + .as("combo") + .shadow() + .find("ui5-responsive-popover") + .as("popover"); + + cy.get("@popover") + .find("ui5-busy-indicator") + .should("exist"); + + cy.get("@combo") + .invoke("prop", "loading", false); + + cy.get("@popover") + .find("ui5-busy-indicator") + .should("not.exist"); + + cy.get("@popover") + .find("ui5-list") + .should("exist"); + }); + + it("should toggle loading state correctly", () => { + cy.mount( + + + + + ); + + cy.get("[ui5-combobox]") + .as("combo") + .should("not.have.prop", "loading", true); + + cy.get("@combo") + .invoke("prop", "loading", true); + + cy.get("@combo") + .should("have.prop", "loading", true); + + cy.get("@combo") + .shadow() + .find("[ui5-icon]") + .realClick(); + + cy.get("@combo") + .shadow() + .find("ui5-responsive-popover") + .as("popover"); + + cy.get("@popover") + .should("have.attr", "open"); + + cy.get("@popover") + .find("ui5-busy-indicator") + .should("exist"); + }); +}); + describe("Validation inside a form", () => { it("has correct validity for valueMissing", () => { cy.mount( diff --git a/packages/main/cypress/specs/MultiComboBox.cy.tsx b/packages/main/cypress/specs/MultiComboBox.cy.tsx index b811b1768cb3..78e7646e95f2 100644 --- a/packages/main/cypress/specs/MultiComboBox.cy.tsx +++ b/packages/main/cypress/specs/MultiComboBox.cy.tsx @@ -4427,6 +4427,96 @@ describe("MultiComboBox Composition", () => { }); }); +describe("Loading State", () => { + it("should display busy indicator when loading is true", () => { + cy.mount( + + + + + ); + + cy.get("[ui5-multi-combobox]") + .shadow() + .find("ui5-responsive-popover") + .as("popover"); + + cy.get("@popover") + .find("ui5-busy-indicator") + .should("exist"); + + cy.get("@popover") + .find("ui5-list") + .should("not.exist"); + }); + + it("should hide busy indicator and show items when loading becomes false", () => { + cy.mount( + + + + + ); + + cy.get("[ui5-multi-combobox]") + .as("mcb") + .shadow() + .find("ui5-responsive-popover") + .as("popover"); + + cy.get("@popover") + .find("ui5-busy-indicator") + .should("exist"); + + cy.get("@mcb") + .invoke("prop", "loading", false); + + cy.get("@popover") + .find("ui5-busy-indicator") + .should("not.exist"); + + cy.get("@popover") + .find("ui5-list") + .should("exist"); + }); + + it("should toggle loading state correctly", () => { + cy.mount( + + + + + ); + + cy.get("[ui5-multi-combobox]") + .as("mcb") + .should("not.have.prop", "loading", true); + + cy.get("@mcb") + .invoke("prop", "loading", true); + + cy.get("@mcb") + .should("have.prop", "loading", true); + + cy.get("@mcb") + .shadow() + .find("[ui5-icon]") + .realClick(); + + cy.get("@mcb") + .shadow() + .find("ui5-responsive-popover") + .as("popover"); + + cy.get("@popover") + .should("have.attr", "open"); + + cy.get("@popover") + .find("ui5-busy-indicator") + .should("exist"); + }); +}); + describe("Validation inside a form", () => { it("has correct validity for valueMissing", () => { cy.mount( diff --git a/packages/main/src/ComboBoxPopoverTemplate.tsx b/packages/main/src/ComboBoxPopoverTemplate.tsx index 77a483304361..378e70ca2f95 100644 --- a/packages/main/src/ComboBoxPopoverTemplate.tsx +++ b/packages/main/src/ComboBoxPopoverTemplate.tsx @@ -31,9 +31,11 @@ export default function ComboBoxPopoverTemplate(this: ComboBox) { onKeyDown={this._handlePopoverKeydown} onFocusOut={this._handlePopoverFocusout} > - + {this.loading && + + } - {this._isPhone && + {!this.loading && this._isPhone && <>
@@ -79,7 +81,7 @@ export default function ComboBoxPopoverTemplate(this: ComboBox) {
} - {!!this._filteredItems.length && + {!this.loading && !!this._filteredItems.length && @@ -31,7 +32,11 @@ export default function MultiComboBoxPopoverTemplate(this: MultiComboBox) { open={this.open} opener={this} > - {this._isPhone && <> + {this.loading && + + } + + {!this.loading && this._isPhone && <>
{this._headerTitleText} @@ -70,7 +75,7 @@ export default function MultiComboBoxPopoverTemplate(this: MultiComboBox) { {selectAllWrapper.call(this)} } - {!this._isPhone && <> + {!this.loading && !this._isPhone && <> {this.hasValueStateMessage &&
@@ -81,11 +86,11 @@ export default function MultiComboBoxPopoverTemplate(this: MultiComboBox) { {selectAllWrapper.call(this)} } - {this.filterSelected ? + {!this.loading && this.filterSelected ? {this.selectedItems.map(item => )} - : + : !this.loading && {this._filteredItems.map(item => )} diff --git a/packages/main/src/themes/MultiComboBoxPopover.css b/packages/main/src/themes/MultiComboBoxPopover.css index 9f03d8189a82..3b6110f763bc 100644 --- a/packages/main/src/themes/MultiComboBoxPopover.css +++ b/packages/main/src/themes/MultiComboBoxPopover.css @@ -40,3 +40,20 @@ [ui5-responsive-popover] .ui5-valuestatemessage-header, [ui5-popover] .ui5-valuestatemessage-header { max-width: inherit; } + +.ui5-multi-combobox-busy { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%,-50%); + z-index: 42; + display: flex; + justify-content: center; + align-items: center; + pointer-events: all; + width: 100%; +} + +.ui5-multi-combobox-busy:not([active]) { + display: none; +} diff --git a/packages/main/test/pages/ComboBox.html b/packages/main/test/pages/ComboBox.html index abf48ebbf21c..27cf28276793 100644 --- a/packages/main/test/pages/ComboBox.html +++ b/packages/main/test/pages/ComboBox.html @@ -192,6 +192,20 @@ SelectionChange call count: 0
+
+ Toggle Loading State + +
+
+ + + + + + + Toggle Loading +
+
Lazy Loading - example does not work on IE11 @@ -604,8 +618,13 @@

ComboBox Composition

document.getElementById("combo-focus").addEventListener("click", function () { document.getElementById("combo").focus(); }); + + document.getElementById("toggle-loading-btn").addEventListener("click", function () { + const combo = document.getElementById("toggle-loading-cb"); + combo.loading = !combo.loading; + }); - \ No newline at end of file + diff --git a/packages/main/test/pages/MultiComboBox.html b/packages/main/test/pages/MultiComboBox.html index 20ddd9f28daa..3d46ca95b13b 100644 --- a/packages/main/test/pages/MultiComboBox.html +++ b/packages/main/test/pages/MultiComboBox.html @@ -65,7 +65,7 @@ Predefined value
- + @@ -75,6 +75,7 @@

Focus MultiComboBox + Toggle Loading
@@ -575,21 +576,35 @@

MultiComboBox in Compact

- Placeholder test + Filter selected: +
+
-
- Toggle Item - - - + + + + + + +

+ + Filter Selected Items +
+ +
+ Toggle Loading State:

- Toggle Item - - - + + + + + +

+ + Toggle Loading
@@ -791,6 +806,11 @@

MultiComboBox in Compact

mcbFocus.focus(); }); + document.getElementById("toggle-loading-btn").addEventListener("click", function () { + const mcb = document.getElementById("toggle-loading-mcb"); + mcb.loading = !mcb.loading; + }); + document.getElementById("add").addEventListener("click", event => { const mcb = document.getElementById("mcb-dynamic-selection"); @@ -820,4 +840,4 @@

MultiComboBox in Compact

- \ No newline at end of file + From 4418865afa4fca1a9aa7c631b3f8f387cdd41f45 Mon Sep 17 00:00:00 2001 From: i518532 Date: Mon, 2 Feb 2026 16:12:53 +0200 Subject: [PATCH 2/4] feat(ui5-multi-combobox): fix sample --- packages/main/test/pages/MultiComboBox.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/main/test/pages/MultiComboBox.html b/packages/main/test/pages/MultiComboBox.html index 3d46ca95b13b..0fec10fb6828 100644 --- a/packages/main/test/pages/MultiComboBox.html +++ b/packages/main/test/pages/MultiComboBox.html @@ -65,7 +65,7 @@ Predefined value
- + @@ -75,7 +75,6 @@

Focus MultiComboBox - Toggle Loading
From 0e35a5b3e3f097fdee20de9346c6e58e00f5825f Mon Sep 17 00:00:00 2001 From: i518532 Date: Mon, 2 Feb 2026 16:20:26 +0200 Subject: [PATCH 3/4] feat(ui5-multi-combobox): fix sample --- packages/main/test/pages/MultiComboBox.html | 28 ++------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/packages/main/test/pages/MultiComboBox.html b/packages/main/test/pages/MultiComboBox.html index 0fec10fb6828..74279017bca6 100644 --- a/packages/main/test/pages/MultiComboBox.html +++ b/packages/main/test/pages/MultiComboBox.html @@ -596,7 +596,7 @@

MultiComboBox in Compact



- + @@ -773,34 +773,10 @@

MultiComboBox in Compact

closeCounter = 0; }); - // Placeholders test - const btn = document.getElementById("sel"); - const mcb1 = document.getElementById("mcb1"); - const btn2 = document.getElementById("sel2"); - const mcb1_2 = document.getElementById("mcb1_2"); + // Focus button const btnfocusMCB = document.getElementById("focus-mcb"); const mcbFocus = document.getElementById("multi1"); - let selected = mcb1.hasAttribute("selected"); - btn.addEventListener("click", () => { - if (!selected) { - mcb1.setAttribute("selected", selected); - } else { - mcb1.removeAttribute("selected"); - } - selected = !selected; - }); - - let selected2 = mcb1_2.hasAttribute("selected"); - btn2.addEventListener("click", () => { - if (!selected2) { - mcb1_2.setAttribute("selected", selected2); - } else { - mcb1_2.removeAttribute("selected"); - } - selected2 = !selected2; - }); - btnfocusMCB.addEventListener("click", () => { mcbFocus.focus(); }); From 1bf7477f9eda1c6b828fe42bc67d2cab9902bb3c Mon Sep 17 00:00:00 2001 From: i518532 Date: Mon, 2 Feb 2026 16:26:33 +0200 Subject: [PATCH 4/4] feat(ui5-multi-combobox): fix sample --- packages/main/test/pages/MultiComboBox.html | 71 ++++++++++++++------- 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/packages/main/test/pages/MultiComboBox.html b/packages/main/test/pages/MultiComboBox.html index 74279017bca6..082c29af7a2a 100644 --- a/packages/main/test/pages/MultiComboBox.html +++ b/packages/main/test/pages/MultiComboBox.html @@ -574,23 +574,6 @@

MultiComboBox in Compact

-
- Filter selected: -
-
- - - - - - - - -

- - Filter Selected Items -
-
Toggle Loading State:
@@ -606,6 +589,24 @@

MultiComboBox in Compact

Toggle Loading
+
+ Placeholder test + +
+ Toggle Item + + + + +
+
+ Toggle Item + + + + +
+
@@ -773,17 +774,36 @@

MultiComboBox in Compact

closeCounter = 0; }); - // Focus button + // Placeholders test + const btn = document.getElementById("sel"); + const mcb1 = document.getElementById("mcb1"); + const btn2 = document.getElementById("sel2"); + const mcb1_2 = document.getElementById("mcb1_2"); const btnfocusMCB = document.getElementById("focus-mcb"); const mcbFocus = document.getElementById("multi1"); - btnfocusMCB.addEventListener("click", () => { - mcbFocus.focus(); + let selected = mcb1.hasAttribute("selected"); + btn.addEventListener("click", () => { + if (!selected) { + mcb1.setAttribute("selected", selected); + } else { + mcb1.removeAttribute("selected"); + } + selected = !selected; }); - document.getElementById("toggle-loading-btn").addEventListener("click", function () { - const mcb = document.getElementById("toggle-loading-mcb"); - mcb.loading = !mcb.loading; + let selected2 = mcb1_2.hasAttribute("selected"); + btn2.addEventListener("click", () => { + if (!selected2) { + mcb1_2.setAttribute("selected", selected2); + } else { + mcb1_2.removeAttribute("selected"); + } + selected2 = !selected2; + }); + + btnfocusMCB.addEventListener("click", () => { + mcbFocus.focus(); }); document.getElementById("add").addEventListener("click", event => { @@ -811,6 +831,11 @@

MultiComboBox in Compact

e.preventDefault(); document.getElementById("mcb-form-submit").textContent = ++submitCounter; }); + + document.getElementById("toggle-loading-btn").addEventListener("click", function () { + const mcb = document.getElementById("toggle-loading-mcb"); + mcb.loading = !mcb.loading; + });