diff --git a/packages/main/cypress/specs/MultiComboBox.cy.tsx b/packages/main/cypress/specs/MultiComboBox.cy.tsx index cbaf5b490727..4e51fb2029e5 100644 --- a/packages/main/cypress/specs/MultiComboBox.cy.tsx +++ b/packages/main/cypress/specs/MultiComboBox.cy.tsx @@ -1495,18 +1495,18 @@ describe("Validation & Value State", () => { cy.realType("4"); cy.get("@input") - .should("have.value", "1"); + .should("have.value", "14"); cy.get("@mcb") .should("have.attr", "value-state", "Negative"); }); - it("Reset value state validation after 2500ms", () => { + it("Invalid input persists - no automatic clearing", () => { cy.mount( - - - + + + ); @@ -1517,21 +1517,73 @@ describe("Validation & Value State", () => { cy.get("@mcb") .should("be.focused"); - cy.realType("4"); + cy.realType("InvalidText"); cy.get("@mcb") .should("have.attr", "value-state", "Negative"); - cy.wait(2500); + cy.get("@mcb") + .shadow() + .find("input") + .as("input") + .should("have.value", "InvalidText"); + + // Wait to test that the value state persists after some time + cy.wait(2500) + + cy.get("@input") + .should("have.value", "InvalidText"); + + cy.get("@mcb") + .should("have.attr", "value-state", "Negative"); + }); + + it("Value state resets when valid entry is entered after invalid input", () => { + cy.mount( + + + + + + ); + + cy.get("[ui5-multi-combobox]") + .as("mcb") + .realClick(); + + cy.get("@mcb") + .should("be.focused"); + + // Type invalid text + cy.realType("xyz"); + + cy.get("@mcb") + .should("have.attr", "value-state", "Negative"); + + cy.get("@mcb") + .shadow() + .find("input") + .as("input") + .should("have.value", "xyz"); + + // Clear and type valid text + cy.get("@input") + .clear(); + + cy.realType("Item"); cy.get("@mcb") .should("have.attr", "value-state", "None"); + + cy.get("@input") + .should("have.value", "Item 1"); }); - it("Built in validation by typing a non existing option", () => { + it("Value state resets when input is cleared after invalid entry", () => { cy.mount( - + + ); @@ -1542,12 +1594,64 @@ describe("Validation & Value State", () => { cy.get("@mcb") .should("be.focused"); - cy.realType("CCo"); + // Type invalid text + cy.realType("InvalidValue"); + + cy.get("@mcb") + .should("have.attr", "value-state", "Negative"); cy.get("@mcb") .shadow() .find("input") - .should("have.value", "Cosy"); + .as("input") + .should("have.value", "InvalidValue"); + + // Clear the input + cy.get("@input") + .clear(); + + cy.get("@mcb") + .should("have.attr", "value-state", "None"); + + cy.get("@input") + .should("have.value", ""); + }); + + it("Value state preserved when switching between valid and invalid", () => { + cy.mount( + + + + + ); + + cy.get("[ui5-multi-combobox]") + .as("mcb") + .realClick(); + + cy.get("@mcb") + .should("be.focused"); + + cy.get("@mcb") + .should("have.attr", "value-state", "Critical"); + + // Type invalid text + cy.realType("xyz"); + + cy.get("@mcb") + .should("have.attr", "value-state", "Negative"); + + cy.get("@mcb") + .shadow() + .find("input") + .as("input"); + + // Clear and verify original state is restored + cy.get("@input") + .clear(); + + cy.get("@mcb") + .should("have.attr", "value-state", "Critical"); }); it("Tests if item is created when enter is pressed while validation is ongoing", () => { @@ -4214,7 +4318,6 @@ describe("MultiComboBox Composition", () => { simulateCompositionStages(["ㄲ", "ㄲㅏ"], "까"); cy.get("@mcb").should("have.attr", "value-state", "Negative"); - cy.get("@input").should("have.value", ""); cy.get("@mcb") .shadow() .find("[ui5-tokenizer] [ui5-token]") @@ -4248,7 +4351,6 @@ describe("MultiComboBox Composition", () => { simulateCompositionStages(["ず", "ずx"], "ずx"); cy.get("@mcb").should("have.attr", "value-state", "Negative"); - cy.get("@input").should("have.value", ""); cy.get("@mcb") .shadow() .find("[ui5-tokenizer] [ui5-token]") @@ -4284,7 +4386,6 @@ describe("MultiComboBox Composition", () => { simulateCompositionStages(["p", "pi", "pin"], "品味"); cy.get("@mcb").should("have.attr", "value-state", "Negative"); - cy.get("@input").should("have.value", ""); cy.get("@mcb") .shadow() .find("[ui5-tokenizer] [ui5-token]") diff --git a/packages/main/src/MultiComboBox.ts b/packages/main/src/MultiComboBox.ts index c941d6eaf633..b538b57b1081 100644 --- a/packages/main/src/MultiComboBox.ts +++ b/packages/main/src/MultiComboBox.ts @@ -708,7 +708,6 @@ class MultiComboBox extends UI5Element implements IFormInputElement { const input = e.target as HTMLInputElement; const value: string = input.value; const filteredItems: Array = this._filterItems(value); - const oldValueState: `${ValueState}` = this.valueState; this._shouldFilterItems = true; @@ -721,24 +720,20 @@ class MultiComboBox extends UI5Element implements IFormInputElement { this.valueState = this._effectiveValueState; this._validationTimeout = null; } else { - input.value = this._inputLastValue; return; } } - this._effectiveValueState = this.valueState; + // Save the original value state before setting validation error + if (this.valueState !== ValueState.Negative) { + this._effectiveValueState = this.valueState; + } if (!this._isComposing && !filteredItems.length && value && !this.noValidation) { - const newValue = this.valueBeforeAutoComplete || this._inputLastValue; - - input.value = newValue; - this.value = newValue; this.valueState = ValueState.Negative; - this._shouldAutocomplete = false; - this._resetValueState(oldValueState); - - return; + } else if ((filteredItems.length || !value) && this.valueState === ValueState.Negative) { + this.valueState = this._effectiveValueState; } if (!this._isComposing) { @@ -1938,10 +1933,6 @@ class MultiComboBox extends UI5Element implements IFormInputElement { } this._tokenizer.expanded = this.open; - // remove the value if user focus out the input and focus is not going in the popover - if (!isPhone() && !this.noValidation && !focusIsGoingInPopover) { - this.value = ""; - } } } /**