fix(tp-date-input): validate correctly when change event hasn't fired yet

validate() relied on this.value, which is only set by _inputChanged on
the change event. Submitting via Enter while focus is still in an input
field skips that event, leaving this.value undefined and causing valid
dates to fail validation.

Introduce _valueFromInputs() as the single parsing source: it reads the
three sub-inputs directly and returns a UTC-midnight DateTime.
validate()
now falls back to it when this.value is not set. _inputChanged is
refactored to call _valueFromInputs() as well, removing the duplicated
format-mapping logic.
This commit is contained in:
2026-06-10 22:42:27 +02:00
parent e189cb3b73
commit b32fd403ec
2 changed files with 44 additions and 16 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@tp/tp-date-input", "name": "@tp/tp-date-input",
"version": "2.1.1", "version": "2.1.2",
"description": "", "description": "",
"main": "tp-date-input.js", "main": "tp-date-input.js",
"scripts": { "scripts": {
+43 -15
View File
@@ -212,8 +212,20 @@ class TpDateInput extends EventHelpers(ControlState(FormElement(LitElement))) {
const maxDate = this._getMaxDate(this.maxDate); const maxDate = this._getMaxDate(this.maxDate);
if ((this.inputs[0].invalid || this.inputs[1].invalid || this.inputs[2].invalid) || if (this.inputs[0].invalid || this.inputs[1].invalid || this.inputs[2].invalid) {
!this.dateValid(this.value, maxDate)) { this.invalid = true;
return false;
}
// this.value is only set by _inputChanged which fires on the change event.
// When validate() is triggered before the change event fires (e.g. submitting
// via Enter while focus is still in the year field), this.value can be
// undefined/null even though the inputs contain a fully valid date.
// Fall back to computing the ISO value directly from the inputs in that case.
const utcDt = this._valueFromInputs();
const value = this.value || (utcDt ? utcDt.toISO() : null);
if (!this.dateValid(value, maxDate)) {
this.invalid = true; this.invalid = true;
return false; return false;
} }
@@ -222,6 +234,31 @@ class TpDateInput extends EventHelpers(ControlState(FormElement(LitElement))) {
return true; return true;
} }
// Parses the three input fields into a UTC-midnight DateTime.
// Returns the DateTime on success, or null if any field is empty or the date is invalid.
_valueFromInputs() {
const i0 = this.inputs[0]?.value;
const i1 = this.inputs[1]?.value;
const i2 = this.inputs[2]?.value;
if (!i0 || !i1 || !i2) return null;
const format = this._inputAssign.map(part => {
switch (part) {
case 'MM': return 'LL';
case 'dd': return 'dd';
case 'y': return 'yyyy';
default: return part;
}
}).join('-');
const dt = DateTime.fromFormat(`${i0}-${i1}-${i2}`, format);
if (!dt.isValid) return null;
return DateTime.utc(dt.year, dt.month, dt.day);
}
focus() { focus() {
this.inputs[0].select(); this.inputs[0].select();
} }
@@ -291,26 +328,15 @@ class TpDateInput extends EventHelpers(ControlState(FormElement(LitElement))) {
return; return;
} }
// Convert luxon format to match input assignment
const format = this._inputAssign.map(part => {
switch (part) {
case 'MM': return 'LL';
case 'dd': return 'dd';
case 'y': return 'yyyy';
default: return part;
}
}).join('-');
// Parse the entered values as a plain calendar date, then store as UTC midnight. // Parse the entered values as a plain calendar date, then store as UTC midnight.
// Date-only fields are timezone-agnostic — April 7 means April 7 for everyone. // Date-only fields are timezone-agnostic — April 7 means April 7 for everyone.
const dt = DateTime.fromFormat(i0 + '-' + i1 + '-' + i2, format); const utcMidnight = this._valueFromInputs();
if (dt.isValid) { if (utcMidnight) {
this.inputs[0].invalid = false; this.inputs[0].invalid = false;
this.inputs[1].invalid = false; this.inputs[1].invalid = false;
this.inputs[2].invalid = false; this.inputs[2].invalid = false;
const utcMidnight = DateTime.utc(dt.year, dt.month, dt.day);
this.date = utcMidnight.toJSDate(); this.date = utcMidnight.toJSDate();
this.value = utcMidnight.toISO(); this.value = utcMidnight.toISO();
this.invalid = false; this.invalid = false;
@@ -450,6 +476,8 @@ class TpDateInput extends EventHelpers(ControlState(FormElement(LitElement))) {
// Reset invalid state if value was changed. // Reset invalid state if value was changed.
// This clears up old invalid states if the value was changed programmatically. // This clears up old invalid states if the value was changed programmatically.
_onValueChanged() { _onValueChanged() {
console.log(this.value);
// We skip if the user was just inputting values. // We skip if the user was just inputting values.
if (this._skipOnValueChanged) { if (this._skipOnValueChanged) {
return; return;