7 Commits

2 changed files with 56 additions and 25 deletions
+2 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "@tp/tp-date-input", "name": "@tp/tp-date-input",
"version": "1.1.1", "version": "2.1.0",
"description": "", "description": "",
"main": "tp-date-input.js", "main": "tp-date-input.js",
"scripts": { "scripts": {
@@ -13,8 +13,7 @@
"author": "trading_peter", "author": "trading_peter",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"date-fns": "^2.0.0", "luxon": "^3.0.0",
"date-fns-tz": "^2.0.0",
"lit": "^3.0.0" "lit": "^3.0.0"
} }
} }
+54 -22
View File
@@ -1,6 +1,6 @@
/** /**
@license @license
Copyright (c) 2022 trading_peter Copyright (c) 2025 trading_peter
This program is available under Apache License Version 2.0 This program is available under Apache License Version 2.0
*/ */
@@ -9,8 +9,7 @@ import { ControlState } from '@tp/helpers/control-state.js';
import { EventHelpers } from '@tp/helpers/event-helpers.js'; import { EventHelpers } from '@tp/helpers/event-helpers.js';
import { FormElement } from '@tp/helpers/form-element.js'; import { FormElement } from '@tp/helpers/form-element.js';
import { LitElement, html, css } from 'lit'; import { LitElement, html, css } from 'lit';
import { format, parse, parseISO, isAfter, isValid, endOfDay } from 'date-fns/esm'; import { DateTime } from 'luxon';
import { zonedTimeToUtc } from 'date-fns-tz';
import { closest } from '@tp/helpers'; import { closest } from '@tp/helpers';
class TpDateInput extends EventHelpers(ControlState(FormElement(LitElement))) { class TpDateInput extends EventHelpers(ControlState(FormElement(LitElement))) {
@@ -232,14 +231,14 @@ class TpDateInput extends EventHelpers(ControlState(FormElement(LitElement))) {
* of the control, like allowedDates, maxDate, ... * of the control, like allowedDates, maxDate, ...
*/ */
dateValid(date, maxDate = this.maxDate, allowedDates = this.allowedDates) { dateValid(date, maxDate = this.maxDate, allowedDates = this.allowedDates) {
date = this._toDate(date); const dt = this._toDateTime(date);
if (isValid(date) === false) { if (!dt || !dt.isValid) {
return false; return false;
} }
if ((allowedDates.length > 0 && allowedDates.indexOf(date) === -1) || if ((allowedDates.length > 0 && allowedDates.indexOf(date) === -1) ||
(maxDate && isAfter(date, maxDate))) { (maxDate && dt > this._toDateTime(maxDate))) {
return false; return false;
} }
return true; return true;
@@ -292,14 +291,27 @@ class TpDateInput extends EventHelpers(ControlState(FormElement(LitElement))) {
return; return;
} }
const date = parse(i0 + '-' + i1 + '-' + i2, this._inputAssign.join('-'), new Date()); // Convert luxon format to match input assignment
const luxonFormat = this._inputAssign.map(part => {
switch (part) {
case 'MM': return 'LL';
case 'dd': return 'dd';
case 'y': return 'yyyy';
default: return part;
}
}).join('-');
if (isValid(date)) { // Parse the date in the specified timezone (or local if not set).
// This interprets the entered values as being in that timezone.
const dt = DateTime.fromFormat(i0 + '-' + i1 + '-' + i2, luxonFormat, { zone: this.timeZone || 'local' });
if (dt.isValid) {
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;
this.date = this.timeZone ? zonedTimeToUtc(date, this.timeZone) : date;
this.value = this.date.toISOString(); this.date = dt.toJSDate();
this.value = dt.toUTC().toISO();
this.invalid = false; this.invalid = false;
this.dispatchEvent(new CustomEvent('value-changed', { detail: this.value, bubbles: true, composed: true })); this.dispatchEvent(new CustomEvent('value-changed', { detail: this.value, bubbles: true, composed: true }));
} else { } else {
@@ -453,18 +465,35 @@ class TpDateInput extends EventHelpers(ControlState(FormElement(LitElement))) {
return; return;
} }
const date = this._toDate(this.value); let dt = this._toDateTime(this.value);
this._input0 = format(date, this._inputAssign[0]); if (dt && dt.isValid) {
this._input1 = format(date, this._inputAssign[1]); // Convert to user's timezone for display (input values are expected to be UTC)
this._input2 = format(date, this._inputAssign[2]); if (this.timeZone) {
this.date = date; dt = dt.setZone(this.timeZone);
}
// Convert luxon format parts to match display format
this._input0 = dt.toFormat(this._getLuxonFormat(this._inputAssign[0]));
this._input1 = dt.toFormat(this._getLuxonFormat(this._inputAssign[1]));
this._input2 = dt.toFormat(this._getLuxonFormat(this._inputAssign[2]));
this.date = dt.toJSDate();
}
}
_getLuxonFormat(inputFormat) {
switch (inputFormat) {
case 'MM': return 'LL';
case 'dd': return 'dd';
case 'y': return 'yyyy';
default: return inputFormat;
}
} }
_setToday() { _setToday() {
if (this.today) { if (this.today) {
setTimeout(() => { setTimeout(() => {
if (!this.value) { if (!this.value) {
this.value = new Date().toISOString(); this.value = DateTime.now().toISO();
} }
}); });
} }
@@ -473,9 +502,9 @@ class TpDateInput extends EventHelpers(ControlState(FormElement(LitElement))) {
_getMaxDate(maxDate) { _getMaxDate(maxDate) {
if (typeof maxDate !== 'string') return null; if (typeof maxDate !== 'string') return null;
if (maxDate.toLowerCase() === 'today') { if (maxDate.toLowerCase() === 'today') {
return endOfDay(new Date()); return DateTime.now().endOf('day');
} }
return this._toDate(maxDate); return this._toDateTime(maxDate);
} }
_autoMoveCursor(e) { _autoMoveCursor(e) {
@@ -486,13 +515,16 @@ class TpDateInput extends EventHelpers(ControlState(FormElement(LitElement))) {
} }
} }
_toDate(value) { _toDateTime(value) {
if (typeof value === 'string') { if (typeof value === 'string') {
return parseISO(value); return DateTime.fromISO(value);
} else { } else if (value instanceof Date) {
return DateTime.fromJSDate(value);
} else if (value && typeof value === 'object' && value.isLuxonDateTime) {
return value; return value;
} }
return null;
} }
} }
window.customElements.define('tp-date-input', TpDateInput); window.customElements.define('tp-date-input', TpDateInput);