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:
+43
-15
@@ -212,8 +212,20 @@ class TpDateInput extends EventHelpers(ControlState(FormElement(LitElement))) {
|
||||
|
||||
const maxDate = this._getMaxDate(this.maxDate);
|
||||
|
||||
if ((this.inputs[0].invalid || this.inputs[1].invalid || this.inputs[2].invalid) ||
|
||||
!this.dateValid(this.value, maxDate)) {
|
||||
if (this.inputs[0].invalid || this.inputs[1].invalid || this.inputs[2].invalid) {
|
||||
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;
|
||||
return false;
|
||||
}
|
||||
@@ -222,6 +234,31 @@ class TpDateInput extends EventHelpers(ControlState(FormElement(LitElement))) {
|
||||
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() {
|
||||
this.inputs[0].select();
|
||||
}
|
||||
@@ -291,26 +328,15 @@ class TpDateInput extends EventHelpers(ControlState(FormElement(LitElement))) {
|
||||
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.
|
||||
// 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[1].invalid = false;
|
||||
this.inputs[2].invalid = false;
|
||||
|
||||
const utcMidnight = DateTime.utc(dt.year, dt.month, dt.day);
|
||||
this.date = utcMidnight.toJSDate();
|
||||
this.value = utcMidnight.toISO();
|
||||
this.invalid = false;
|
||||
@@ -450,6 +476,8 @@ class TpDateInput extends EventHelpers(ControlState(FormElement(LitElement))) {
|
||||
// Reset invalid state if value was changed.
|
||||
// This clears up old invalid states if the value was changed programmatically.
|
||||
_onValueChanged() {
|
||||
console.log(this.value);
|
||||
|
||||
// We skip if the user was just inputting values.
|
||||
if (this._skipOnValueChanged) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user