diff --git a/packages/field-base/src/input-mixin.d.ts b/packages/field-base/src/input-mixin.d.ts index 98309fab80..f4150fa2d1 100644 --- a/packages/field-base/src/input-mixin.d.ts +++ b/packages/field-base/src/input-mixin.d.ts @@ -68,6 +68,4 @@ export declare class InputMixinClass { protected _toggleHasValue(hasValue: boolean): void; protected _valueChanged(value?: string, oldValue?: string): void; - - protected _setHasInputValue(event: InputEvent): void; } diff --git a/packages/field-base/src/input-mixin.js b/packages/field-base/src/input-mixin.js index 839ada4fc4..57db2ee890 100644 --- a/packages/field-base/src/input-mixin.js +++ b/packages/field-base/src/input-mixin.js @@ -206,7 +206,7 @@ export const InputMixin = dedupingMixin( * @private */ __onInput(event) { - this._setHasInputValue(event); + this._hasInputValue = !!this._inputElementValue; this._onInput(event); } @@ -267,19 +267,5 @@ export const InputMixin = dedupingMixin( // Setting a value programmatically, sync it to input element. this._forwardInputValue(newVal); } - - /** - * Sets the `_hasInputValue` property based on the `input` event. - * - * @param {InputEvent} event - * @protected - */ - _setHasInputValue(event) { - // In the case a custom web component is passed as `inputElement`, - // the actual native input element, on which the event occurred, - // can be inside shadow trees. - const target = event.composedPath()[0]; - this._hasInputValue = target.value.length > 0; - } }, ); diff --git a/packages/number-field/src/vaadin-number-field-mixin.js b/packages/number-field/src/vaadin-number-field-mixin.js index 03214fe85f..7e9ca4658a 100644 --- a/packages/number-field/src/vaadin-number-field-mixin.js +++ b/packages/number-field/src/vaadin-number-field-mixin.js @@ -9,6 +9,15 @@ import { InputController } from '@vaadin/field-base/src/input-controller.js'; import { InputFieldMixin } from '@vaadin/field-base/src/input-field-mixin.js'; import { LabelledInputController } from '@vaadin/field-base/src/labelled-input-controller.js'; +// [type=number] value returns an empty string for invalid numbers, +// while valueAsNumber returns NaN for empty strings, which makes +// invalid and empty values indistinguishable. It's only possible +// to detect unparsable input by checking the validity.badInput +// boolean property. This string is used in _inputElementValue +// as a marker to help Flow detect and clear unparsable values +// through that property. +const BAD_INPUT_STRING = 'NaN'; + /** * A mixin providing common number field functionality. * @@ -111,7 +120,7 @@ export const NumberFieldMixin = (superClass) => * @private */ get __hasUnparsableValue() { - return this.inputElement.validity.badInput; + return this._inputElementValue === BAD_INPUT_STRING; } /** @protected */ @@ -405,22 +414,6 @@ export const NumberFieldMixin = (superClass) => super._onKeyDown(event); } - /** - * Native [type=number] inputs don't update their value - * when you are entering input that the browser is unable to parse - * e.g. "--5", hence we have to override this method from `InputMixin` - * so that, when value is empty, it would additionally check - * for bad input based on the native `validity.badInput` property. - * - * @param {InputEvent} event - * @protected - * @override - */ - _setHasInputValue(event) { - const target = event.composedPath()[0]; - this._hasInputValue = target.value.length > 0 || this.__hasUnparsableValue; - } - /** * Override this method from `InputMixin` to prevent * the value change caused by user input from being treated @@ -527,4 +520,18 @@ export const NumberFieldMixin = (superClass) => this.__committedValue = this.value; this.__committedUnparsableValueStatus = this.__hasUnparsableValue; } + + /** @override */ + get _inputElementValue() { + if (this.inputElement && this.inputElement.validity.badInput) { + return BAD_INPUT_STRING; + } + + return super._inputElementValue; + } + + /** @override */ + set _inputElementValue(value) { + super._inputElementValue = value; + } };