diff --git a/packages/main/cypress/specs/Input.cy.tsx b/packages/main/cypress/specs/Input.cy.tsx index 4081a16b5e9f..a12c68ff999c 100644 --- a/packages/main/cypress/specs/Input.cy.tsx +++ b/packages/main/cypress/specs/Input.cy.tsx @@ -544,6 +544,79 @@ describe("Input general interaction", () => { cy.get("@onChange").should("have.been.calledOnce"); cy.get("@onSelectionChange").should("have.been.calledOnce"); }); + + it("Should control suggestions dynamically based on threshold", () => { + const THRESHOLD = 3; + const countries = [ + "Argentina", "Albania", "Algeria", "Angola", "Austria", "Australia", + "Bulgaria", "Belgium", "Brazil", "Canada", "Colombia", "Croatia" + ]; + + cy.mount(); + + cy.document().then(doc => { + const input = doc.querySelector("#threshold-input")!; + + input.addEventListener("input", () => { + const value = input.value; + + while (input.lastChild) { + input.removeChild(input.lastChild); + } + + if (value.length >= THRESHOLD) { + input.showSuggestions = true; + + const filtered = countries.filter(country => + country.toUpperCase().indexOf(value.toUpperCase()) === 0 + ); + + filtered.forEach(country => { + const item = document.createElement("ui5-suggestion-item"); + item.setAttribute("text", country); + input.appendChild(item); + }); + } else { + input.showSuggestions = false; + } + }); + }); + + cy.get("#threshold-input") + .as("input") + .realClick(); + + cy.get("@input") + .should("be.focused"); + + cy.realType("B"); + + cy.get("@input") + .shadow() + .find("[ui5-responsive-popover]") + .should("not.exist", "true"); + + cy.realType("ul"); + + cy.get("@input") + .shadow() + .find("[ui5-responsive-popover]") + .ui5ResponsivePopoverOpened(); + + cy.get("@input") + .find("[ui5-suggestion-item]") + .should("have.length", 1) + .first() + .should("have.attr", "text", "Bulgaria"); + + cy.realPress("Backspace"); + cy.realPress("Backspace"); + + cy.get("@input") + .shadow() + .find("[ui5-responsive-popover]") + .should("not.exist", "true"); + }); }); describe("Input arrow navigation", () => { diff --git a/packages/main/cypress/specs/Input.mobile.cy.tsx b/packages/main/cypress/specs/Input.mobile.cy.tsx index 1549f598b846..60c97f9e96da 100644 --- a/packages/main/cypress/specs/Input.mobile.cy.tsx +++ b/packages/main/cypress/specs/Input.mobile.cy.tsx @@ -198,6 +198,57 @@ describe("Eventing", () => { cy.get("@onSelectionChange").should("have.been.calledOnce"); }); + + it("Should control suggestions dynamically based on threshold on mobile", () => { + const THRESHOLD = 3; + const countries = [ + "Argentina", "Albania", "Algeria", "Angola", "Austria", "Australia", + "Bulgaria", "Belgium", "Brazil", "Canada", "Colombia", "Croatia" + ]; + + cy.mount(); + + cy.document().then(doc => { + const input = doc.querySelector("#mobile-threshold")!; + + input.addEventListener("input", () => { + const value = input.value; + + while (input.lastChild) { + input.removeChild(input.lastChild); + } + + if (value.length >= THRESHOLD) { + input.showSuggestions = true; + + const filtered = countries.filter(country => + country.toUpperCase().indexOf(value.toUpperCase()) === 0 + ); + + filtered.forEach(country => { + const item = document.createElement("ui5-suggestion-item"); + item.setAttribute("text", country); + input.appendChild(item); + }); + } else { + input.showSuggestions = false; + } + }); + }); + + cy.get("#mobile-threshold") + .as("input") + .realClick(); + + cy.get("@input") + .shadow() + .find("[ui5-responsive-popover]") + .ui5ResponsivePopoverOpened(); + + cy.get("@input").shadow().find(".ui5-input-inner-phone").should("be.focused"); + cy.get("@input").shadow().find(".ui5-input-inner-phone").realType("Bu"); + cy.get("@input").shadow().find("ui5-suggestion-item").should("have.length", 0); + }); }); describe("Typeahead", () => { @@ -390,4 +441,4 @@ describe("Property open", () => { .find("[ui5-responsive-popover]") .ui5ResponsivePopoverClosed(); }); -}); \ No newline at end of file +}); diff --git a/packages/main/src/Input.ts b/packages/main/src/Input.ts index 0b45e9194712..8446558e93b7 100644 --- a/packages/main/src/Input.ts +++ b/packages/main/src/Input.ts @@ -1110,7 +1110,7 @@ class Input extends UI5Element implements SuggestionComponent, IFormInputElement _onfocusout(e: FocusEvent) { const toBeFocused = e.relatedTarget as HTMLElement; - if (this.Suggestions?._getPicker().contains(toBeFocused) || this.contains(toBeFocused) || this.getSlottedNodes("valueStateMessage").some(el => el.contains(toBeFocused))) { + if (this.Suggestions?._getPicker()?.contains(toBeFocused) || this.contains(toBeFocused) || this.getSlottedNodes("valueStateMessage").some(el => el.contains(toBeFocused))) { return; } @@ -1174,7 +1174,7 @@ class Input extends UI5Element implements SuggestionComponent, IFormInputElement if (this.previousValue !== this.getInputDOMRefSync()!.value) { // if picker is open there might be a selected item, wait next tick to get the value applied - if (this.Suggestions?._getPicker().open && this._flattenItems.some(item => item.hasAttribute("ui5-suggestion-item") && (item as SuggestionItem).selected)) { + if (this.Suggestions?._getPicker()?.open && this._flattenItems.some(item => item.hasAttribute("ui5-suggestion-item") && (item as SuggestionItem).selected)) { this._changeToBeFired = true; } else { fireChange(); @@ -1566,15 +1566,21 @@ class Input extends UI5Element implements SuggestionComponent, IFormInputElement getInputDOMRef() { if (isPhone() && this.Suggestions) { - return this.Suggestions._getPicker()!.querySelector(".ui5-input-inner-phone")!; + const picker = this.Suggestions._getPicker(); + if (picker) { + return picker.querySelector(".ui5-input-inner-phone")!; + } } return this.nativeInput; } getInputDOMRefSync() { - if (isPhone() && this.Suggestions?._getPicker()) { - return this.Suggestions._getPicker().querySelector(".ui5-input-inner-phone")!.shadowRoot!.querySelector("input")!; + if (isPhone() && this.Suggestions) { + const picker = this.Suggestions._getPicker(); + if (picker) { + return picker.querySelector(".ui5-input-inner-phone")!.shadowRoot!.querySelector("input")!; + } } return this.nativeInput; diff --git a/packages/main/src/features/InputSuggestionsTemplate.tsx b/packages/main/src/features/InputSuggestionsTemplate.tsx index bd3d917370fa..6bb959dbc065 100644 --- a/packages/main/src/features/InputSuggestionsTemplate.tsx +++ b/packages/main/src/features/InputSuggestionsTemplate.tsx @@ -72,7 +72,7 @@ export default function InputSuggestionsTemplate(this: Input, hooks?: { suggesti } - { suggestionsList.call(this) } + { this.showSuggestions && suggestionsList.call(this) } {this._isPhone &&