diff --git a/packages/fiori/cypress/specs/SearchField.cy.tsx b/packages/fiori/cypress/specs/SearchField.cy.tsx index db80dffd555b..aa35f8dc8ac2 100644 --- a/packages/fiori/cypress/specs/SearchField.cy.tsx +++ b/packages/fiori/cypress/specs/SearchField.cy.tsx @@ -507,4 +507,44 @@ describe("SearchField general interaction", () => { .should("not.exist"); }); }); + + describe("Field Loading", () => { + it("shows loading indicator on button in collapsed mode", () => { + cy.mount(); + + cy.get("[ui5-search-field]") + .shadow() + .find("[ui5-button]") + .should("have.attr", "loading"); + }); + + it("does not show loading indicator on button when fieldLoading is false in collapsed mode", () => { + cy.mount(); + + cy.get("[ui5-search-field]") + .shadow() + .find("[ui5-button]") + .should("not.have.attr", "loading"); + }); + + it("shows BusyIndicator in expanded mode when fieldLoading is true", () => { + cy.mount(); + + cy.get("[ui5-search-field]") + .shadow() + .find("[ui5-busy-indicator]") + .should("exist") + .should("have.attr", "active"); + }); + + it("BusyIndicator is not active in expanded mode when fieldLoading is false", () => { + cy.mount(); + + cy.get("[ui5-search-field]") + .shadow() + .find("[ui5-busy-indicator]") + .should("exist") + .should("not.have.attr", "active"); + }); + }); }); diff --git a/packages/fiori/src/SearchField.ts b/packages/fiori/src/SearchField.ts index 4956195e1b9d..7e12153a94cb 100644 --- a/packages/fiori/src/SearchField.ts +++ b/packages/fiori/src/SearchField.ts @@ -101,6 +101,15 @@ class SearchField extends UI5Element { "scope-change": SearchFieldScopeSelectionChangeDetails, } + /** + * Indicates whether a loading indicator should be shown in the input field. + * @default false + * @since 2.19.0 + * @public + */ + @property({ type: Boolean }) + fieldLoading = false + /** * Defines whether the clear icon of the search will be shown. * @default false diff --git a/packages/fiori/src/SearchFieldTemplate.tsx b/packages/fiori/src/SearchFieldTemplate.tsx index 89b78de79d01..df9e0b00cae8 100644 --- a/packages/fiori/src/SearchFieldTemplate.tsx +++ b/packages/fiori/src/SearchFieldTemplate.tsx @@ -6,6 +6,7 @@ import type SearchField from "./SearchField.js"; import decline from "@ui5/webcomponents-icons/dist/decline.js"; import search from "@ui5/webcomponents-icons/dist/search.js"; import ButtonDesign from "@ui5/webcomponents/dist/types/ButtonDesign.js"; +import BusyIndicator from "@ui5/webcomponents/dist/BusyIndicator.js"; export type SearchFieldTemplateOptions = { /** @@ -22,81 +23,84 @@ export default function SearchFieldTemplate(this: SearchField, options?: SearchF icon={search} design={ButtonDesign.Transparent} data-sap-focus-ref + loading={this.fieldLoading} onClick={this._handleSearchIconPress} tooltip={this._effectiveIconTooltip} accessibleName={this._effectiveIconTooltip} accessibilityAttributes={this._searchButtonAccessibilityAttributes} > ) : ( - +
+ Search with field loading state (type and press Enter) + +
+
Search with lazy loaded Suggestions - Autocomplete and highlighting @@ -450,6 +455,15 @@ }, 300); } }); + + const searchWithLoading = document.getElementById('search-with-loading'); + searchWithLoading.addEventListener('ui5-search', async (e) => { + if (e.target.value) { + e.target.fieldLoading = true; + await new Promise(resolve => setTimeout(resolve, 2000)); + e.target.fieldLoading = false; + } + }); diff --git a/packages/fiori/test/pages/SearchField.html b/packages/fiori/test/pages/SearchField.html index 029ad1d51a78..cb53c085453c 100644 --- a/packages/fiori/test/pages/SearchField.html +++ b/packages/fiori/test/pages/SearchField.html @@ -42,6 +42,10 @@ +
+ Search with loading state (click search icon) + +
Collapsed search
@@ -87,6 +91,13 @@ scopedSearch.addEventListener('ui5-scope-change', (event) => { console.log('scope-change', event.detail.scope); }); + + const searchLoading = document.getElementById('search-loading'); + searchLoading.addEventListener('ui5-search', async () => { + searchLoading.fieldLoading = true; + await new Promise(resolve => setTimeout(resolve, 2000)); + searchLoading.fieldLoading = false; + }); diff --git a/packages/website/docs/_components_pages/fiori/Search/Search.mdx b/packages/website/docs/_components_pages/fiori/Search/Search.mdx index 2d270d8d29fe..9e877dc2b6fd 100644 --- a/packages/website/docs/_components_pages/fiori/Search/Search.mdx +++ b/packages/website/docs/_components_pages/fiori/Search/Search.mdx @@ -8,6 +8,7 @@ import Byline from "../../../_samples/fiori/Search/Byline/Byline.md"; import AdvancedFilter from "../../../_samples/fiori/Search/AdvancedFilter/AdvancedFilter.md" import ShowMore from "../../../_samples/fiori/Search/ShowMore/ShowMore.md" import Actions from "../../../_samples/fiori/Search/Actions/Actions.md" +import Loading from "../../../_samples/fiori/Search/Loading/Loading.md" <%COMPONENT_OVERVIEW%> @@ -45,3 +46,8 @@ This example shows how to use a interactive elements in search items. +### Loading State +This example shows the loading indicator during async search operations. + + + diff --git a/packages/website/docs/_samples/fiori/Search/Loading/Loading.md b/packages/website/docs/_samples/fiori/Search/Loading/Loading.md new file mode 100644 index 000000000000..17798ecc59ab --- /dev/null +++ b/packages/website/docs/_samples/fiori/Search/Loading/Loading.md @@ -0,0 +1,4 @@ +import html from '!!raw-loader!./sample.html'; +import js from '!!raw-loader!./main.js'; + + diff --git a/packages/website/docs/_samples/fiori/Search/Loading/main.js b/packages/website/docs/_samples/fiori/Search/Loading/main.js new file mode 100644 index 000000000000..ef493e9393e8 --- /dev/null +++ b/packages/website/docs/_samples/fiori/Search/Loading/main.js @@ -0,0 +1,27 @@ +import "@ui5/webcomponents-fiori/dist/SearchField.js"; +import "@ui5/webcomponents/dist/Label.js"; +import "@ui5/webcomponents/dist/Text.js"; + +const searchField = document.getElementById("search-loading"); +const resultText = document.getElementById("result-text"); + +searchField.addEventListener("ui5-search", async (event) => { + const query = searchField.value; + + // Show loading indicator + searchField.fieldLoading = true; + resultText.textContent = `Searching for "${query}"...`; + + // Simulate async search operation + await new Promise(resolve => setTimeout(resolve, 2000)); + + // Hide loading indicator and show results + searchField.fieldLoading = false; + resultText.textContent = `Search completed for "${query}". Found 5 results.`; +}); + +searchField.addEventListener("ui5-input", () => { + if (!searchField.value) { + resultText.textContent = "Enter a search term and press Enter or click the search icon"; + } +}); diff --git a/packages/website/docs/_samples/fiori/Search/Loading/sample.html b/packages/website/docs/_samples/fiori/Search/Loading/sample.html new file mode 100644 index 000000000000..3fc621219534 --- /dev/null +++ b/packages/website/docs/_samples/fiori/Search/Loading/sample.html @@ -0,0 +1,4 @@ + + +Result: +Enter a search term and press Enter or click the search icon