@lekoala/date-picker 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -6
- package/custom-elements.json +20 -0
- package/dist/date-picker.css +32 -32
- package/dist/date-picker.js +493 -96
- package/dist/date-picker.min.css +1 -1
- package/dist/date-picker.min.js +13 -13
- package/dist/date-picker.standalone.min.js +46 -46
- package/dist/types/date-calendar.d.ts +34 -3
- package/dist/types/date-calendar.d.ts.map +1 -1
- package/dist/types/date-field.d.ts +12 -4
- package/dist/types/date-field.d.ts.map +1 -1
- package/dist/types/date-picker.d.ts +91 -9
- package/dist/types/date-picker.d.ts.map +1 -1
- package/dist/types/date-range.d.ts +102 -20
- package/dist/types/date-range.d.ts.map +1 -1
- package/dist/types/date.d.ts +10 -0
- package/dist/types/date.d.ts.map +1 -1
- package/dist/types/intl.d.ts.map +1 -1
- package/docs/ACCESSIBILITY.md +6 -2
- package/docs/API.md +51 -1
- package/docs/DECISIONS.md +17 -4
- package/docs/MIGRATION-FLATPICKR.md +1 -1
- package/docs/TESTING.md +1 -1
- package/docs/USE_CASES.md +3 -0
- package/package.json +6 -6
- package/src/date-calendar.js +145 -42
- package/src/date-field.js +8 -4
- package/src/date-picker.css +32 -32
- package/src/date-picker.js +345 -37
- package/src/date-range.js +184 -30
- package/src/date.js +50 -1
- package/src/intl.js +13 -7
package/dist/date-picker.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*** @lekoala/date-picker v0.
|
|
1
|
+
/*** @lekoala/date-picker v0.4.0 - https://github.com/lekoala/date-picker ***/
|
|
2
2
|
(() => {
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -176,15 +176,46 @@
|
|
|
176
176
|
const end = endOfWeek(endOfMonth(value), firstDay);
|
|
177
177
|
const weeks = [];
|
|
178
178
|
let cursor = start;
|
|
179
|
-
|
|
179
|
+
for (;; ) {
|
|
180
180
|
const week = [];
|
|
181
181
|
for (let i = 0;i < 7; i++)
|
|
182
182
|
week.push(addDays(cursor, i));
|
|
183
183
|
weeks.push(week);
|
|
184
|
+
if (compareDates(week[6], end) >= 0)
|
|
185
|
+
break;
|
|
184
186
|
cursor = addDays(cursor, 7);
|
|
185
187
|
}
|
|
186
188
|
return weeks;
|
|
187
189
|
}
|
|
190
|
+
function dayOrdinal(year, month, day) {
|
|
191
|
+
const base = toUTCDate({ year: 1, month: 1, day: 1 });
|
|
192
|
+
return Math.round((toUTCDate({ year, month, day }).getTime() - base.getTime()) / 86400000);
|
|
193
|
+
}
|
|
194
|
+
function clampDisplayMonth(value, firstDay = 1) {
|
|
195
|
+
const normalized = normalizeFirstDay(firstDay);
|
|
196
|
+
const maxOrdinal = dayOrdinal(9999, 12, 31);
|
|
197
|
+
let key = monthKey(value);
|
|
198
|
+
for (;; ) {
|
|
199
|
+
const parsed = parseDate(`${key}-01`);
|
|
200
|
+
if (!parsed)
|
|
201
|
+
throw new TypeError(`Invalid civil date/month: ${value}`);
|
|
202
|
+
const startOrdinal = dayOrdinal(parsed.year, parsed.month, 1);
|
|
203
|
+
const startOffset = (toUTCDate(parsed).getUTCDay() - normalized + 7) % 7;
|
|
204
|
+
if (startOrdinal - startOffset < 0) {
|
|
205
|
+
key = shiftMonth(key, 1);
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
const lastDay = daysInMonth(parsed.year, parsed.month);
|
|
209
|
+
const endParts = { year: parsed.year, month: parsed.month, day: lastDay };
|
|
210
|
+
const endOrdinal = startOrdinal + lastDay - 1;
|
|
211
|
+
const endOffset = (toUTCDate(endParts).getUTCDay() - normalized + 7) % 7;
|
|
212
|
+
if (endOrdinal - endOffset + 6 > maxOrdinal) {
|
|
213
|
+
key = shiftMonth(key, -1);
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
return key;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
188
219
|
function clampDate(value, min = "", max = "") {
|
|
189
220
|
if (!isDate(value))
|
|
190
221
|
throw new TypeError(`Invalid civil date: ${value}`);
|
|
@@ -312,36 +343,140 @@
|
|
|
312
343
|
focus(endpoint) {
|
|
313
344
|
this.activeEndpoint = endpoint;
|
|
314
345
|
}
|
|
315
|
-
|
|
346
|
+
_refuse(endpoint) {
|
|
347
|
+
return {
|
|
348
|
+
status: "refused",
|
|
349
|
+
endpoint,
|
|
350
|
+
changedEndpoints: [],
|
|
351
|
+
range: this.range,
|
|
352
|
+
activeEndpoint: this.activeEndpoint
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
project(date, editable = () => true) {
|
|
316
356
|
if (!isDate(date))
|
|
317
357
|
throw new TypeError(`Invalid range activation: ${date}`);
|
|
318
|
-
|
|
319
|
-
|
|
358
|
+
const { start, end } = this;
|
|
359
|
+
if (this.complete && (compareDates(date, start) < 0 || compareDates(date, end) > 0)) {
|
|
360
|
+
const endpoint = compareDates(date, start) < 0 ? "start" : "end";
|
|
320
361
|
if (!editable(endpoint))
|
|
321
|
-
return
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
362
|
+
return this._refuse(endpoint);
|
|
363
|
+
return {
|
|
364
|
+
status: "complete",
|
|
365
|
+
endpoint,
|
|
366
|
+
changedEndpoints: [endpoint],
|
|
367
|
+
range: endpoint === "start" ? { start: date, end } : { start, end: date },
|
|
368
|
+
activeEndpoint: endpoint
|
|
369
|
+
};
|
|
325
370
|
}
|
|
326
371
|
if (this.activeEndpoint === "end") {
|
|
327
|
-
if (
|
|
328
|
-
|
|
372
|
+
if (start && !end && compareDates(date, start) < 0) {
|
|
373
|
+
if (!editable("start"))
|
|
374
|
+
return this._refuse("start");
|
|
375
|
+
if (!editable("end"))
|
|
376
|
+
return this._refuse("end");
|
|
377
|
+
return {
|
|
378
|
+
status: "complete",
|
|
379
|
+
endpoint: "end",
|
|
380
|
+
changedEndpoints: ["start", "end"],
|
|
381
|
+
range: { start: date, end: start },
|
|
382
|
+
activeEndpoint: "end"
|
|
383
|
+
};
|
|
329
384
|
}
|
|
385
|
+
if (start && compareDates(date, start) < 0)
|
|
386
|
+
return this._refuse("end");
|
|
330
387
|
if (!editable("end"))
|
|
331
|
-
return
|
|
332
|
-
|
|
333
|
-
|
|
388
|
+
return this._refuse("end");
|
|
389
|
+
return {
|
|
390
|
+
status: start ? "complete" : "pending",
|
|
391
|
+
endpoint: "end",
|
|
392
|
+
changedEndpoints: ["end"],
|
|
393
|
+
range: { start, end: date },
|
|
394
|
+
activeEndpoint: "end"
|
|
395
|
+
};
|
|
334
396
|
}
|
|
335
|
-
if (!
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
397
|
+
if (end && !start && compareDates(date, end) > 0) {
|
|
398
|
+
if (!editable("start"))
|
|
399
|
+
return this._refuse("start");
|
|
400
|
+
if (!editable("end"))
|
|
401
|
+
return this._refuse("end");
|
|
402
|
+
return {
|
|
403
|
+
status: "complete",
|
|
404
|
+
endpoint: "start",
|
|
405
|
+
changedEndpoints: ["start", "end"],
|
|
406
|
+
range: { start: end, end: date },
|
|
407
|
+
activeEndpoint: "start"
|
|
408
|
+
};
|
|
340
409
|
}
|
|
341
|
-
|
|
342
|
-
|
|
410
|
+
if (!editable("start"))
|
|
411
|
+
return this._refuse("start");
|
|
412
|
+
const canContinue = editable("end");
|
|
413
|
+
return {
|
|
414
|
+
status: "pending",
|
|
415
|
+
endpoint: "start",
|
|
416
|
+
changedEndpoints: ["start"],
|
|
417
|
+
range: { start: date, end },
|
|
418
|
+
activeEndpoint: canContinue ? "end" : this.activeEndpoint,
|
|
419
|
+
...canContinue ? {} : { close: true }
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
projectEndpoint(date, endpoint, editable = () => true) {
|
|
423
|
+
if (!isDate(date))
|
|
424
|
+
throw new TypeError(`Invalid range activation: ${date}`);
|
|
425
|
+
if (!this.complete || !editable(endpoint))
|
|
426
|
+
return this._refuse(endpoint);
|
|
427
|
+
const { start, end } = this;
|
|
428
|
+
const previous = endpoint === "start" ? start : end;
|
|
429
|
+
const target = endpoint === "start" ? earlier(date, end) : later(date, start);
|
|
430
|
+
return {
|
|
431
|
+
status: "complete",
|
|
432
|
+
endpoint,
|
|
433
|
+
changedEndpoints: target === previous ? [] : [endpoint],
|
|
434
|
+
range: endpoint === "start" ? { start: target, end } : { start, end: target },
|
|
435
|
+
activeEndpoint: endpoint
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
previewRange(date, endpoint = "", editable = () => true) {
|
|
439
|
+
if (!isDate(date))
|
|
440
|
+
return null;
|
|
441
|
+
if (!endpoint && Boolean(this.start) === Boolean(this.end))
|
|
442
|
+
return null;
|
|
443
|
+
const transition = endpoint ? this.projectEndpoint(date, endpoint, editable) : this.project(date, editable);
|
|
444
|
+
if (transition.status === "refused")
|
|
445
|
+
return null;
|
|
446
|
+
const { start, end } = transition.range;
|
|
447
|
+
if (!start || end && compareDates(end, start) < 0)
|
|
448
|
+
return null;
|
|
449
|
+
return { start, end };
|
|
450
|
+
}
|
|
451
|
+
_apply(transition) {
|
|
452
|
+
if (transition.status === "refused")
|
|
453
|
+
return transition;
|
|
454
|
+
this.start = transition.range.start;
|
|
455
|
+
this.end = transition.range.end;
|
|
456
|
+
this.activeEndpoint = transition.activeEndpoint;
|
|
457
|
+
return transition;
|
|
458
|
+
}
|
|
459
|
+
activate(date, editable = () => true) {
|
|
460
|
+
return this._apply(this.project(date, editable));
|
|
461
|
+
}
|
|
462
|
+
moveEndpoint(date, endpoint, editable = () => true) {
|
|
463
|
+
return this._apply(this.projectEndpoint(date, endpoint, editable));
|
|
343
464
|
}
|
|
344
465
|
}
|
|
466
|
+
function later(a, b) {
|
|
467
|
+
if (!a)
|
|
468
|
+
return b;
|
|
469
|
+
if (!b)
|
|
470
|
+
return a;
|
|
471
|
+
return compareDates(a, b) >= 0 ? a : b;
|
|
472
|
+
}
|
|
473
|
+
function earlier(a, b) {
|
|
474
|
+
if (!a)
|
|
475
|
+
return b;
|
|
476
|
+
if (!b)
|
|
477
|
+
return a;
|
|
478
|
+
return compareDates(a, b) <= 0 ? a : b;
|
|
479
|
+
}
|
|
345
480
|
|
|
346
481
|
// src/intl.js
|
|
347
482
|
var BIDI = /[\u200e\u200f\u061c\u202a-\u202e\u2066-\u2069]/g;
|
|
@@ -361,8 +496,10 @@
|
|
|
361
496
|
map.set(formatter.format(i), String(i));
|
|
362
497
|
return map;
|
|
363
498
|
}
|
|
364
|
-
function normalizeDigits(text, locale) {
|
|
365
|
-
let result = String(text || "").replace(BIDI, "")
|
|
499
|
+
function normalizeDigits(text, locale, options = {}) {
|
|
500
|
+
let result = String(text || "").replace(BIDI, "");
|
|
501
|
+
if (options.trim !== false)
|
|
502
|
+
result = result.trim();
|
|
366
503
|
for (const [local, ascii] of digitMap(locale))
|
|
367
504
|
result = result.split(local).join(ascii);
|
|
368
505
|
return result;
|
|
@@ -462,8 +599,8 @@
|
|
|
462
599
|
return "(\\d{1,2})";
|
|
463
600
|
if (part.type === "year")
|
|
464
601
|
return "(\\d{4})";
|
|
465
|
-
const literal = normalizeDigits(part.value, resolved
|
|
466
|
-
return escapeRegExp(literal).replace(
|
|
602
|
+
const literal = normalizeDigits(part.value, resolved, { trim: false });
|
|
603
|
+
return escapeRegExp(literal).replace(/\s+/g, "\\s*");
|
|
467
604
|
}).join("");
|
|
468
605
|
const regex = new RegExp(`^\\s*${pattern}\\s*$`);
|
|
469
606
|
return {
|
|
@@ -557,19 +694,24 @@
|
|
|
557
694
|
function yearOf(month) {
|
|
558
695
|
return Number(month.slice(0, 4));
|
|
559
696
|
}
|
|
697
|
+
function stepMonthKey(month, amount) {
|
|
698
|
+
const [year, index] = month.split("-").map(Number);
|
|
699
|
+
const absolute = year * 12 + (index - 1) + amount;
|
|
700
|
+
const stepYear = Math.floor(absolute / 12);
|
|
701
|
+
const stepMonth = (absolute % 12 + 12) % 12 + 1;
|
|
702
|
+
if (stepYear < 1 || stepYear > 9999)
|
|
703
|
+
return null;
|
|
704
|
+
return `${String(stepYear).padStart(4, "0")}-${String(stepMonth).padStart(2, "0")}`;
|
|
705
|
+
}
|
|
706
|
+
function rangeAttributeMap(position) {
|
|
707
|
+
return {
|
|
708
|
+
"data-range-start": position === "start" || position === "single",
|
|
709
|
+
"data-range-end": position === "end" || position === "single",
|
|
710
|
+
"data-in-range": position === "in"
|
|
711
|
+
};
|
|
712
|
+
}
|
|
560
713
|
function rangeAttributes(position) {
|
|
561
|
-
|
|
562
|
-
case "single":
|
|
563
|
-
return ' data-range-start="true" data-range-end="true"';
|
|
564
|
-
case "start":
|
|
565
|
-
return ' data-range-start="true"';
|
|
566
|
-
case "end":
|
|
567
|
-
return ' data-range-end="true"';
|
|
568
|
-
case "in":
|
|
569
|
-
return ' data-in-range="true"';
|
|
570
|
-
default:
|
|
571
|
-
return "";
|
|
572
|
-
}
|
|
714
|
+
return Object.entries(rangeAttributeMap(position)).filter(([, on]) => on).map(([name]) => ` ${name}="true"`).join("");
|
|
573
715
|
}
|
|
574
716
|
function rangeLabelKey(position) {
|
|
575
717
|
if (position === "single")
|
|
@@ -612,6 +754,8 @@
|
|
|
612
754
|
this._renderDay = null;
|
|
613
755
|
this._isDateDisabled = null;
|
|
614
756
|
this._highlightedRange = { start: "", end: "" };
|
|
757
|
+
this._paintedRange = { start: "", end: "" };
|
|
758
|
+
this._paintedPreview = false;
|
|
615
759
|
this._messages = getDefaultMessages();
|
|
616
760
|
this._onClick = this._onClick.bind(this);
|
|
617
761
|
this._onChange = this._onChange.bind(this);
|
|
@@ -730,11 +874,12 @@
|
|
|
730
874
|
}
|
|
731
875
|
set highlightedRange(value) {
|
|
732
876
|
const next = normalizeRange(value);
|
|
733
|
-
|
|
877
|
+
const preview = this.hasAttribute("data-range-preview");
|
|
878
|
+
if (next.start === this._paintedRange.start && next.end === this._paintedRange.end && preview === this._paintedPreview)
|
|
734
879
|
return;
|
|
735
880
|
this._highlightedRange = next;
|
|
736
881
|
if (this._connected)
|
|
737
|
-
this.
|
|
882
|
+
this._updateRangeDom();
|
|
738
883
|
}
|
|
739
884
|
get fixedWeeks() {
|
|
740
885
|
return this.hasAttribute("fixed-weeks");
|
|
@@ -796,7 +941,7 @@
|
|
|
796
941
|
const attrDisplay = this.getAttribute("display") || "";
|
|
797
942
|
if (attrDisplay) {
|
|
798
943
|
try {
|
|
799
|
-
this._model.setDisplay(attrDisplay);
|
|
944
|
+
this._model.setDisplay(clampDisplayMonth(attrDisplay, firstDay));
|
|
800
945
|
} catch {}
|
|
801
946
|
} else if (this._model.value) {
|
|
802
947
|
this._model.display = monthKey(this._model.value);
|
|
@@ -817,10 +962,18 @@
|
|
|
817
962
|
this._rendering = false;
|
|
818
963
|
}
|
|
819
964
|
_clamp(value) {
|
|
820
|
-
|
|
965
|
+
const bounded = clampDate(value, this.min, this.max);
|
|
966
|
+
const month = monthKey(bounded);
|
|
967
|
+
const safeMonth = clampDisplayMonth(month, this.firstDay);
|
|
968
|
+
if (safeMonth === month)
|
|
969
|
+
return bounded;
|
|
970
|
+
const day = Number(bounded.slice(8, 10)) || 1;
|
|
971
|
+
const candidate = addDays(`${safeMonth}-01`, day - 1);
|
|
972
|
+
const last = endOfMonth(safeMonth);
|
|
973
|
+
return compareDates(candidate, last) > 0 ? last : candidate;
|
|
821
974
|
}
|
|
822
975
|
_weeks(display = this.display) {
|
|
823
|
-
const weeks = getMonthWeeks(display, { firstDay: this.firstDay });
|
|
976
|
+
const weeks = getMonthWeeks(clampDisplayMonth(display, this.firstDay), { firstDay: this.firstDay });
|
|
824
977
|
if (!this.fixedWeeks || weeks.length >= 6)
|
|
825
978
|
return weeks;
|
|
826
979
|
let cursor = weeks[weeks.length - 1]?.[6] || "";
|
|
@@ -934,7 +1087,7 @@
|
|
|
934
1087
|
}
|
|
935
1088
|
_setDisplay(display, options = {}) {
|
|
936
1089
|
const previous = this._model.display;
|
|
937
|
-
this._model.setDisplay(display);
|
|
1090
|
+
this._model.setDisplay(clampDisplayMonth(display, this.firstDay));
|
|
938
1091
|
this._model.focused = this._clamp(this._model.focused);
|
|
939
1092
|
this._model.display = monthKey(this._model.focused);
|
|
940
1093
|
this._reflect("display", this._model.display);
|
|
@@ -952,10 +1105,10 @@
|
|
|
952
1105
|
}));
|
|
953
1106
|
}
|
|
954
1107
|
previousMonth() {
|
|
955
|
-
return this._setDisplay(
|
|
1108
|
+
return this._setDisplay(stepMonthKey(this.display, -1) ?? this.display);
|
|
956
1109
|
}
|
|
957
1110
|
nextMonth() {
|
|
958
|
-
return this._setDisplay(
|
|
1111
|
+
return this._setDisplay(stepMonthKey(this.display, 1) ?? this.display);
|
|
959
1112
|
}
|
|
960
1113
|
focusDate(date, options = {}) {
|
|
961
1114
|
if (!isDate(date))
|
|
@@ -1007,12 +1160,39 @@
|
|
|
1007
1160
|
}
|
|
1008
1161
|
return false;
|
|
1009
1162
|
}
|
|
1163
|
+
_dayLabel(date, state, position) {
|
|
1164
|
+
const rangeLabel = this.hasAttribute("data-range-preview") ? "" : rangeLabelKey(position);
|
|
1165
|
+
const description = typeof state.description === "string" ? state.description : "";
|
|
1166
|
+
return [
|
|
1167
|
+
formatLongDate(date, this.locale),
|
|
1168
|
+
description,
|
|
1169
|
+
rangeLabel ? this._messages[rangeLabel] : "",
|
|
1170
|
+
state.disabled ? this._messages.unavailable : ""
|
|
1171
|
+
].filter(Boolean).join(". ");
|
|
1172
|
+
}
|
|
1173
|
+
_updateRangeDom() {
|
|
1174
|
+
this._paintedRange = { ...this._highlightedRange };
|
|
1175
|
+
this._paintedPreview = this.hasAttribute("data-range-preview");
|
|
1176
|
+
for (const cell of this.querySelectorAll(".dp-day[data-date]")) {
|
|
1177
|
+
if (!(cell instanceof HTMLTableCellElement))
|
|
1178
|
+
continue;
|
|
1179
|
+
const date = cell.dataset.date || "";
|
|
1180
|
+
const position = rangePosition(date, this._highlightedRange);
|
|
1181
|
+
for (const [name, on] of Object.entries(rangeAttributeMap(position))) {
|
|
1182
|
+
if (on)
|
|
1183
|
+
cell.setAttribute(name, "true");
|
|
1184
|
+
else
|
|
1185
|
+
cell.removeAttribute(name);
|
|
1186
|
+
}
|
|
1187
|
+
cell.setAttribute("aria-label", this._dayLabel(date, this.getDateState(date), position));
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1010
1190
|
focusGrid() {
|
|
1011
1191
|
const target = this.querySelector(`.dp-day[data-date="${CSS.escape(this.focusedDate)}"]`);
|
|
1012
1192
|
if (target instanceof HTMLElement)
|
|
1013
1193
|
target.focus();
|
|
1014
1194
|
}
|
|
1015
|
-
async
|
|
1195
|
+
async activateDate(date) {
|
|
1016
1196
|
const confirmed = await this.ensureDate(date);
|
|
1017
1197
|
const state = this.getDateState(date);
|
|
1018
1198
|
if (!confirmed || state.disabled) {
|
|
@@ -1068,7 +1248,7 @@
|
|
|
1068
1248
|
this._reflect("display", this._model.display);
|
|
1069
1249
|
if (previousDisplay !== this.display)
|
|
1070
1250
|
this._emitDisplayChange();
|
|
1071
|
-
this.
|
|
1251
|
+
this.activateDate(date);
|
|
1072
1252
|
}
|
|
1073
1253
|
_onChange(event) {
|
|
1074
1254
|
const target = event.target;
|
|
@@ -1078,7 +1258,7 @@
|
|
|
1078
1258
|
}
|
|
1079
1259
|
if (target instanceof HTMLInputElement && target.matches(".dp-year-input")) {
|
|
1080
1260
|
const year = Number(target.value);
|
|
1081
|
-
if (!Number.isInteger(year) || year < 1 || year >
|
|
1261
|
+
if (!Number.isInteger(year) || year < 1 || year > 9998) {
|
|
1082
1262
|
if (this._connected)
|
|
1083
1263
|
this.render(false);
|
|
1084
1264
|
return;
|
|
@@ -1091,8 +1271,10 @@
|
|
|
1091
1271
|
if (!(target instanceof HTMLTableCellElement) || !target.matches(".dp-day[data-date]"))
|
|
1092
1272
|
return;
|
|
1093
1273
|
const date = target.dataset.date || "";
|
|
1094
|
-
if (isDate(date))
|
|
1095
|
-
|
|
1274
|
+
if (!isDate(date))
|
|
1275
|
+
return;
|
|
1276
|
+
this._model.focused = date;
|
|
1277
|
+
this.dispatchEvent(new CustomEvent("datefocus", { detail: { date, state: this.getDateState(date) }, bubbles: true }));
|
|
1096
1278
|
}
|
|
1097
1279
|
_onKeyDown(event) {
|
|
1098
1280
|
const target = event.target;
|
|
@@ -1101,7 +1283,7 @@
|
|
|
1101
1283
|
const date = target.dataset.date || this.focusedDate;
|
|
1102
1284
|
if (event.key === "Enter" || event.key === " ") {
|
|
1103
1285
|
event.preventDefault();
|
|
1104
|
-
this.
|
|
1286
|
+
this.activateDate(date);
|
|
1105
1287
|
return;
|
|
1106
1288
|
}
|
|
1107
1289
|
const anchorFocused = this._model.focused;
|
|
@@ -1150,8 +1332,10 @@
|
|
|
1150
1332
|
const gridId = `${this._id}-grid`;
|
|
1151
1333
|
const minMonth = this.min ? monthKey(this.min) : "";
|
|
1152
1334
|
const maxMonth = this.max ? monthKey(this.max) : "";
|
|
1153
|
-
const
|
|
1154
|
-
const
|
|
1335
|
+
const prevKey = stepMonthKey(display, -1);
|
|
1336
|
+
const nextKey = stepMonthKey(display, 1);
|
|
1337
|
+
const prevDisabled = Boolean(minMonth && prevKey !== null && prevKey < minMonth);
|
|
1338
|
+
const nextDisabled = Boolean(maxMonth && nextKey !== null && nextKey > maxMonth);
|
|
1155
1339
|
const minYearAttr = this.min ? ` min="${Number(this.min.slice(0, 4))}"` : "";
|
|
1156
1340
|
const maxYearAttr = this.max ? ` max="${Number(this.max.slice(0, 4))}"` : "";
|
|
1157
1341
|
const showWeeks = this.showWeekNumbers && this.firstDay === 1;
|
|
@@ -1172,14 +1356,7 @@
|
|
|
1172
1356
|
const focused = this.focusedDate === date;
|
|
1173
1357
|
const isToday = date === today;
|
|
1174
1358
|
const position = rangePosition(date, this._highlightedRange);
|
|
1175
|
-
const
|
|
1176
|
-
const description = typeof state.description === "string" ? state.description : "";
|
|
1177
|
-
const label = [
|
|
1178
|
-
formatLongDate(date, locale),
|
|
1179
|
-
description,
|
|
1180
|
-
rangeLabel ? this._messages[rangeLabel] : "",
|
|
1181
|
-
state.disabled ? this._messages.unavailable : ""
|
|
1182
|
-
].filter(Boolean).join(". ");
|
|
1359
|
+
const label = this._dayLabel(date, state, position);
|
|
1183
1360
|
return `<td class="dp-day" data-date="${date}"${outside ? ' data-outside-month="true"' : ""}${isToday ? ' data-today="true" aria-current="date"' : ""}${selected ? ' data-selected="true" aria-selected="true"' : ""}${rangeAttributes(position)}${state.disabled ? ' data-disabled="true" aria-disabled="true"' : ""} tabindex="${focused ? "0" : "-1"}" aria-label="${escapeHtml(label)}"><span class="dp-day-number" aria-hidden="true">${Number(date.slice(8, 10))}</span><span class="dp-day-extra" aria-hidden="true"></span></td>`;
|
|
1184
1361
|
}).join("");
|
|
1185
1362
|
return `<tr>${weekNumber}${cells}</tr>`;
|
|
@@ -1198,8 +1375,8 @@
|
|
|
1198
1375
|
<div class="dp-calendar-header">
|
|
1199
1376
|
${yearFirst ? yearControl : monthControl}
|
|
1200
1377
|
${yearFirst ? monthControl : yearControl}
|
|
1201
|
-
<button type="button" class="dp-nav dp-prev" data-calendar-action="previous" aria-label="${escapeHtml(this._messages.previousMonth)}"${prevDisabled ? " disabled" : ""}><svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="
|
|
1202
|
-
<button type="button" class="dp-nav dp-next" data-calendar-action="next" aria-label="${escapeHtml(this._messages.nextMonth)}"${nextDisabled ? " disabled" : ""}><svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="
|
|
1378
|
+
<button type="button" class="dp-nav dp-prev" data-calendar-action="previous" aria-label="${escapeHtml(this._messages.previousMonth)}"${prevDisabled ? " disabled" : ""}><svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="m4 10 4-4 4 4"/></svg></button>
|
|
1379
|
+
<button type="button" class="dp-nav dp-next" data-calendar-action="next" aria-label="${escapeHtml(this._messages.nextMonth)}"${nextDisabled ? " disabled" : ""}><svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="m4 6 4 4 4-4"/></svg></button>
|
|
1203
1380
|
</div>
|
|
1204
1381
|
<h2 id="${headingId}" class="dp-calendar-heading dp-visually-hidden" aria-live="polite">${escapeHtml(formatMonthYear(`${display}-15`, locale))}</h2>
|
|
1205
1382
|
<table id="${gridId}" class="dp-grid" role="grid" aria-labelledby="${headingId}">
|
|
@@ -1208,6 +1385,8 @@
|
|
|
1208
1385
|
</table>
|
|
1209
1386
|
</div>`;
|
|
1210
1387
|
this._rendering = false;
|
|
1388
|
+
this._paintedRange = { ...this._highlightedRange };
|
|
1389
|
+
this._paintedPreview = this.hasAttribute("data-range-preview");
|
|
1211
1390
|
if (focusKey) {
|
|
1212
1391
|
queueMicrotask(() => {
|
|
1213
1392
|
let selector = focusKey;
|
|
@@ -1686,7 +1865,7 @@
|
|
|
1686
1865
|
}
|
|
1687
1866
|
input.setCustomValidity(text === canonical ? "" : this.messages.invalidDate);
|
|
1688
1867
|
}
|
|
1689
|
-
async commit() {
|
|
1868
|
+
async commit(options = {}) {
|
|
1690
1869
|
const input = this.input;
|
|
1691
1870
|
const commitId = ++this._commitId;
|
|
1692
1871
|
const text = input.value.trim();
|
|
@@ -1706,7 +1885,7 @@
|
|
|
1706
1885
|
return { status: "invalid" };
|
|
1707
1886
|
}
|
|
1708
1887
|
if (this.confirm) {
|
|
1709
|
-
const result = await this.confirm(parsed);
|
|
1888
|
+
const result = await this.confirm(parsed, options);
|
|
1710
1889
|
if (commitId !== this._commitId)
|
|
1711
1890
|
return { status: "stale" };
|
|
1712
1891
|
if (!result?.ok) {
|
|
@@ -1778,6 +1957,7 @@
|
|
|
1778
1957
|
|
|
1779
1958
|
// src/date-picker.js
|
|
1780
1959
|
var uid2 = 0;
|
|
1960
|
+
var DRAG_THRESHOLD = 4;
|
|
1781
1961
|
|
|
1782
1962
|
class DatePickerElement extends HTMLElement {
|
|
1783
1963
|
static observedAttributes = ["value", "locale", "min", "max", "open-on-focus", "month-format"];
|
|
@@ -1797,6 +1977,9 @@
|
|
|
1797
1977
|
this._lastFocusEndpoint = "";
|
|
1798
1978
|
this._rangeCommitId = 0;
|
|
1799
1979
|
this._pendingIntents = new Map;
|
|
1980
|
+
this._previewDate = "";
|
|
1981
|
+
this._drag = null;
|
|
1982
|
+
this._suppressGridClick = false;
|
|
1800
1983
|
this._buttons = [];
|
|
1801
1984
|
this._returnFocus = null;
|
|
1802
1985
|
this._panel = null;
|
|
@@ -1839,7 +2022,7 @@
|
|
|
1839
2022
|
this._discoverTimeFields();
|
|
1840
2023
|
this._field = new DateFieldController(input, { messages: this._messages, locale: this.locale });
|
|
1841
2024
|
this._field.onAttributesChanged = () => this._syncInputState();
|
|
1842
|
-
this._field.confirm = (date) => this._confirmDate(date);
|
|
2025
|
+
this._field.confirm = (date, options) => this._confirmDate(date, options);
|
|
1843
2026
|
this._setupFormValue();
|
|
1844
2027
|
this._build();
|
|
1845
2028
|
this._syncInputState();
|
|
@@ -1903,7 +2086,7 @@
|
|
|
1903
2086
|
];
|
|
1904
2087
|
for (const field of this._fields) {
|
|
1905
2088
|
field.onAttributesChanged = () => this._syncRangeFields();
|
|
1906
|
-
field.confirm = (date) => this._confirmDate(date);
|
|
2089
|
+
field.confirm = (date, options) => this._confirmDate(date, options);
|
|
1907
2090
|
field.setupFormValue();
|
|
1908
2091
|
}
|
|
1909
2092
|
this._build();
|
|
@@ -2148,6 +2331,7 @@
|
|
|
2148
2331
|
const field = this._fields[index];
|
|
2149
2332
|
button.disabled = Boolean(field?.input.disabled || field?.input.readOnly);
|
|
2150
2333
|
}
|
|
2334
|
+
this._syncDragAffordance();
|
|
2151
2335
|
const active = this._range?.activeEndpoint === "end" ? 1 : 0;
|
|
2152
2336
|
if (this._open && (this._fields[active]?.input.disabled || this._fields[active]?.input.readOnly)) {
|
|
2153
2337
|
this.hide(false);
|
|
@@ -2331,7 +2515,15 @@
|
|
|
2331
2515
|
signal
|
|
2332
2516
|
});
|
|
2333
2517
|
}
|
|
2334
|
-
calendar.addEventListener("click", (event) =>
|
|
2518
|
+
calendar.addEventListener("click", (event) => {
|
|
2519
|
+
if (this._suppressGridClick) {
|
|
2520
|
+
this._suppressGridClick = false;
|
|
2521
|
+
event.preventDefault();
|
|
2522
|
+
event.stopImmediatePropagation();
|
|
2523
|
+
return;
|
|
2524
|
+
}
|
|
2525
|
+
this._captureGridIntent(event);
|
|
2526
|
+
}, { capture: true, signal });
|
|
2335
2527
|
calendar.addEventListener("keydown", (event) => this._captureGridIntent(event), {
|
|
2336
2528
|
capture: true,
|
|
2337
2529
|
signal
|
|
@@ -2344,15 +2536,12 @@
|
|
|
2344
2536
|
queueMicrotask(() => {
|
|
2345
2537
|
if (custom.defaultPrevented || !this._connected || !this._range)
|
|
2346
2538
|
return;
|
|
2347
|
-
const
|
|
2348
|
-
if (
|
|
2539
|
+
const intent = this._pendingIntents.get(date);
|
|
2540
|
+
if (intent === undefined || intent.id !== this._rangeCommitId)
|
|
2349
2541
|
return;
|
|
2350
2542
|
this._pendingIntents.delete(date);
|
|
2351
|
-
const
|
|
2352
|
-
|
|
2353
|
-
const field = this._fields?.[index];
|
|
2354
|
-
return field != null && !field.input.disabled && !field.input.readOnly;
|
|
2355
|
-
});
|
|
2543
|
+
const editable = (bound) => this._boundEditable(bound);
|
|
2544
|
+
const result = intent.endpoint ? this._range.moveEndpoint(date, intent.endpoint, editable) : this._range.activate(date, editable);
|
|
2356
2545
|
if (result.status === "refused") {
|
|
2357
2546
|
this._calendar?.dispatchEvent(new CustomEvent("dateinvalid", {
|
|
2358
2547
|
detail: { date, state: this._calendar.getDateState(date) },
|
|
@@ -2360,13 +2549,23 @@
|
|
|
2360
2549
|
}));
|
|
2361
2550
|
return;
|
|
2362
2551
|
}
|
|
2363
|
-
this.
|
|
2552
|
+
this._applyRangeTransition(result);
|
|
2553
|
+
if (intent.endpoint)
|
|
2554
|
+
return;
|
|
2364
2555
|
if (result.close || result.status === "complete") {
|
|
2365
2556
|
this.hide(false);
|
|
2366
2557
|
this._focusField(result.endpoint);
|
|
2367
2558
|
}
|
|
2368
2559
|
});
|
|
2369
2560
|
}, { signal });
|
|
2561
|
+
calendar.addEventListener("datefocus", (event) => this._onGridDateFocus(event), { signal });
|
|
2562
|
+
calendar.addEventListener("pointerover", (event) => this._onGridPointerOver(event), { signal });
|
|
2563
|
+
calendar.addEventListener("pointerleave", () => this._onGridPointerLeave(), { signal });
|
|
2564
|
+
calendar.addEventListener("pointerdown", (event) => this._onGridPointerDown(event), { signal });
|
|
2565
|
+
calendar.addEventListener("pointermove", (event) => this._onGridPointerMove(event), { signal });
|
|
2566
|
+
calendar.addEventListener("pointerup", (event) => this._onGridPointerUp(event), { signal });
|
|
2567
|
+
calendar.addEventListener("pointercancel", (event) => this._onGridPointerCancel(event), { signal });
|
|
2568
|
+
calendar.addEventListener("lostpointercapture", (event) => this._onGridPointerCancel(event), { signal });
|
|
2370
2569
|
calendar.addEventListener("dateloadend", () => void this.validate(), { signal });
|
|
2371
2570
|
this.ownerDocument.addEventListener("pointerdown", (event) => {
|
|
2372
2571
|
if (!this._open || event.composedPath().includes(this))
|
|
@@ -2396,6 +2595,7 @@
|
|
|
2396
2595
|
const target = this._boundCanonical(endpoint) || todayISO();
|
|
2397
2596
|
calendar.display = monthKey(target);
|
|
2398
2597
|
calendar.focusedDate = target;
|
|
2598
|
+
this._clearPreview();
|
|
2399
2599
|
}
|
|
2400
2600
|
_onRangeTriggerClick(endpoint, event) {
|
|
2401
2601
|
if (!this._open) {
|
|
@@ -2478,7 +2678,190 @@
|
|
|
2478
2678
|
if (!isDate(date))
|
|
2479
2679
|
return;
|
|
2480
2680
|
this._pendingIntents.clear();
|
|
2481
|
-
this._pendingIntents.set(date, ++this._rangeCommitId);
|
|
2681
|
+
this._pendingIntents.set(date, { id: ++this._rangeCommitId, endpoint: "" });
|
|
2682
|
+
}
|
|
2683
|
+
_boundEditable(bound) {
|
|
2684
|
+
const field = this._fields?.[bound === "end" ? 1 : 0];
|
|
2685
|
+
return field != null && !field.input.disabled && !field.input.readOnly;
|
|
2686
|
+
}
|
|
2687
|
+
_applyRangeTransition(transition) {
|
|
2688
|
+
const fields = this._fields;
|
|
2689
|
+
if (!fields || !this._range || transition.status === "refused")
|
|
2690
|
+
return;
|
|
2691
|
+
const moved = [];
|
|
2692
|
+
for (const which of transition.changedEndpoints) {
|
|
2693
|
+
const field = fields[which === "end" ? 1 : 0];
|
|
2694
|
+
const next = which === "end" ? transition.range.end : transition.range.start;
|
|
2695
|
+
if (!field || field.canonical === next)
|
|
2696
|
+
continue;
|
|
2697
|
+
field.setCanonical(next, { format: true });
|
|
2698
|
+
moved.push(field);
|
|
2699
|
+
}
|
|
2700
|
+
this._syncHighlight();
|
|
2701
|
+
this._refreshRangeButtonLabel();
|
|
2702
|
+
this._revalidateRange(transition.endpoint);
|
|
2703
|
+
if (!moved.length)
|
|
2704
|
+
return;
|
|
2705
|
+
this._emitRangeChange();
|
|
2706
|
+
for (const field of moved) {
|
|
2707
|
+
field.input.dispatchEvent(new Event("input", { bubbles: true }));
|
|
2708
|
+
field.input.dispatchEvent(new Event("change", { bubbles: true }));
|
|
2709
|
+
}
|
|
2710
|
+
}
|
|
2711
|
+
_setPreview(date, endpoint = "") {
|
|
2712
|
+
const calendar = this._calendar;
|
|
2713
|
+
if (!calendar || !this._range || !this._open)
|
|
2714
|
+
return;
|
|
2715
|
+
const candidate = isDate(date) && !calendar.getDateState(date).disabled ? date : "";
|
|
2716
|
+
const preview = candidate ? this._range.previewRange(candidate, endpoint, (bound) => this._boundEditable(bound)) : null;
|
|
2717
|
+
if (!preview) {
|
|
2718
|
+
this._clearPreview();
|
|
2719
|
+
return;
|
|
2720
|
+
}
|
|
2721
|
+
this._previewDate = candidate;
|
|
2722
|
+
calendar.toggleAttribute("data-range-preview", true);
|
|
2723
|
+
calendar.highlightedRange = preview;
|
|
2724
|
+
}
|
|
2725
|
+
_clearPreview() {
|
|
2726
|
+
if (!this._previewDate)
|
|
2727
|
+
return;
|
|
2728
|
+
this._syncHighlight();
|
|
2729
|
+
}
|
|
2730
|
+
_onGridDateFocus(event) {
|
|
2731
|
+
if (this._drag)
|
|
2732
|
+
return;
|
|
2733
|
+
const date = event.detail?.date;
|
|
2734
|
+
if (isDate(date))
|
|
2735
|
+
this._setPreview(date);
|
|
2736
|
+
}
|
|
2737
|
+
_onGridPointerOver(event) {
|
|
2738
|
+
const pointer = event;
|
|
2739
|
+
if (this._drag || pointer.pointerType === "touch")
|
|
2740
|
+
return;
|
|
2741
|
+
this._setPreview(this._cellDate(pointer.target));
|
|
2742
|
+
}
|
|
2743
|
+
_onGridPointerLeave() {
|
|
2744
|
+
if (this._drag?.active === false)
|
|
2745
|
+
this._drag = null;
|
|
2746
|
+
if (this._drag)
|
|
2747
|
+
return;
|
|
2748
|
+
this._clearPreview();
|
|
2749
|
+
}
|
|
2750
|
+
_cellDate(target) {
|
|
2751
|
+
const cell = target instanceof Element ? target.closest(".dp-day[data-date]") : null;
|
|
2752
|
+
const date = cell?.getAttribute("data-date") || "";
|
|
2753
|
+
return isDate(date) ? date : "";
|
|
2754
|
+
}
|
|
2755
|
+
_dateAtPoint(x, y) {
|
|
2756
|
+
const element = this.ownerDocument.elementFromPoint(x, y);
|
|
2757
|
+
if (!(element instanceof Element) || !this._calendar?.contains(element))
|
|
2758
|
+
return "";
|
|
2759
|
+
return this._cellDate(element);
|
|
2760
|
+
}
|
|
2761
|
+
_onGridPointerDown(event) {
|
|
2762
|
+
const pointer = event;
|
|
2763
|
+
this._suppressGridClick = false;
|
|
2764
|
+
if (this._drag?.active === false)
|
|
2765
|
+
this._drag = null;
|
|
2766
|
+
if (!this._open || !this._range || this._drag)
|
|
2767
|
+
return;
|
|
2768
|
+
if (!pointer.isPrimary || pointer.button !== 0)
|
|
2769
|
+
return;
|
|
2770
|
+
if (pointer.pointerType !== "mouse" && pointer.pointerType !== "pen")
|
|
2771
|
+
return;
|
|
2772
|
+
if (!this._range.complete)
|
|
2773
|
+
return;
|
|
2774
|
+
const cell = pointer.target instanceof Element ? pointer.target.closest(".dp-day[data-date]") : null;
|
|
2775
|
+
if (!(cell instanceof HTMLElement))
|
|
2776
|
+
return;
|
|
2777
|
+
const isStart = cell.hasAttribute("data-range-start");
|
|
2778
|
+
const isEnd = cell.hasAttribute("data-range-end");
|
|
2779
|
+
if (isStart === isEnd)
|
|
2780
|
+
return;
|
|
2781
|
+
const endpoint = isStart ? "start" : "end";
|
|
2782
|
+
const date = this._cellDate(cell);
|
|
2783
|
+
if (!date || !this._boundEditable(endpoint))
|
|
2784
|
+
return;
|
|
2785
|
+
this._drag = {
|
|
2786
|
+
pointerId: pointer.pointerId,
|
|
2787
|
+
endpoint,
|
|
2788
|
+
x: pointer.clientX,
|
|
2789
|
+
y: pointer.clientY,
|
|
2790
|
+
date,
|
|
2791
|
+
active: false
|
|
2792
|
+
};
|
|
2793
|
+
}
|
|
2794
|
+
_onGridPointerMove(event) {
|
|
2795
|
+
const pointer = event;
|
|
2796
|
+
const drag = this._drag;
|
|
2797
|
+
if (!drag || pointer.pointerId !== drag.pointerId)
|
|
2798
|
+
return;
|
|
2799
|
+
if (!drag.active) {
|
|
2800
|
+
const travelled = Math.abs(pointer.clientX - drag.x) > DRAG_THRESHOLD || Math.abs(pointer.clientY - drag.y) > DRAG_THRESHOLD;
|
|
2801
|
+
if (!travelled)
|
|
2802
|
+
return;
|
|
2803
|
+
drag.active = true;
|
|
2804
|
+
try {
|
|
2805
|
+
this._calendar?.setPointerCapture(drag.pointerId);
|
|
2806
|
+
} catch {}
|
|
2807
|
+
this._syncDragAffordance();
|
|
2808
|
+
}
|
|
2809
|
+
const date = this._dateAtPoint(pointer.clientX, pointer.clientY);
|
|
2810
|
+
if (!date || this._calendar?.getDateState(date).disabled)
|
|
2811
|
+
return;
|
|
2812
|
+
drag.date = date;
|
|
2813
|
+
this._setPreview(date, drag.endpoint);
|
|
2814
|
+
}
|
|
2815
|
+
_onGridPointerUp(event) {
|
|
2816
|
+
const pointer = event;
|
|
2817
|
+
const drag = this._drag;
|
|
2818
|
+
if (!drag || pointer.pointerId !== drag.pointerId)
|
|
2819
|
+
return;
|
|
2820
|
+
this._drag = null;
|
|
2821
|
+
this._releaseDragCapture(drag.pointerId);
|
|
2822
|
+
if (!drag.active) {
|
|
2823
|
+
this._syncDragAffordance();
|
|
2824
|
+
return;
|
|
2825
|
+
}
|
|
2826
|
+
this._suppressGridClick = true;
|
|
2827
|
+
const transition = this._range?.projectEndpoint(drag.date, drag.endpoint, (bound) => this._boundEditable(bound));
|
|
2828
|
+
if (!transition || transition.status === "refused" || !transition.changedEndpoints.length) {
|
|
2829
|
+
this._syncHighlight();
|
|
2830
|
+
return;
|
|
2831
|
+
}
|
|
2832
|
+
const target = drag.endpoint === "start" ? transition.range.start : transition.range.end;
|
|
2833
|
+
this._pendingIntents.clear();
|
|
2834
|
+
this._pendingIntents.set(target, { id: ++this._rangeCommitId, endpoint: drag.endpoint });
|
|
2835
|
+
this._calendar?.activateDate(target);
|
|
2836
|
+
}
|
|
2837
|
+
_onGridPointerCancel(event) {
|
|
2838
|
+
const pointer = event;
|
|
2839
|
+
const drag = this._drag;
|
|
2840
|
+
if (!drag || pointer.pointerId !== drag.pointerId)
|
|
2841
|
+
return;
|
|
2842
|
+
this._drag = null;
|
|
2843
|
+
this._releaseDragCapture(drag.pointerId);
|
|
2844
|
+
this._syncHighlight();
|
|
2845
|
+
}
|
|
2846
|
+
_releaseDragCapture(pointerId) {
|
|
2847
|
+
const calendar = this._calendar;
|
|
2848
|
+
if (calendar?.hasPointerCapture(pointerId))
|
|
2849
|
+
calendar.releasePointerCapture(pointerId);
|
|
2850
|
+
}
|
|
2851
|
+
_syncDragAffordance() {
|
|
2852
|
+
const calendar = this._calendar;
|
|
2853
|
+
if (!calendar || !this._range)
|
|
2854
|
+
return;
|
|
2855
|
+
if (this._drag?.active) {
|
|
2856
|
+
calendar.setAttribute("data-range-drag", "active");
|
|
2857
|
+
return;
|
|
2858
|
+
}
|
|
2859
|
+
const { start, end } = this._range;
|
|
2860
|
+
const draggable = this._range.complete && start !== end && (this._boundEditable("start") || this._boundEditable("end"));
|
|
2861
|
+
if (draggable)
|
|
2862
|
+
calendar.setAttribute("data-range-drag", "ready");
|
|
2863
|
+
else
|
|
2864
|
+
calendar.removeAttribute("data-range-drag");
|
|
2482
2865
|
}
|
|
2483
2866
|
_onEscape(event) {
|
|
2484
2867
|
if (event.key === "Escape" && this._open) {
|
|
@@ -2581,7 +2964,7 @@
|
|
|
2581
2964
|
this._field?.setCanonical(this._value, { format: options.format !== false });
|
|
2582
2965
|
if (this._calendar) {
|
|
2583
2966
|
this._calendar.value = this._value;
|
|
2584
|
-
if (this._value)
|
|
2967
|
+
if (this._value && options.moveDisplay !== false)
|
|
2585
2968
|
this._calendar.focusedDate = this._value;
|
|
2586
2969
|
}
|
|
2587
2970
|
this._refreshButtonLabel();
|
|
@@ -2594,13 +2977,15 @@
|
|
|
2594
2977
|
}
|
|
2595
2978
|
}
|
|
2596
2979
|
}
|
|
2597
|
-
async _confirmDate(date) {
|
|
2980
|
+
async _confirmDate(date, options = {}) {
|
|
2598
2981
|
const calendar = this._calendar;
|
|
2599
2982
|
if (!calendar)
|
|
2600
2983
|
return { ok: true };
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
calendar.display
|
|
2984
|
+
if (options.moveDisplay !== false) {
|
|
2985
|
+
const display = monthKey(date);
|
|
2986
|
+
if (calendar.display !== display)
|
|
2987
|
+
calendar.display = display;
|
|
2988
|
+
}
|
|
2604
2989
|
const confirmed = await calendar.ensureDate(date);
|
|
2605
2990
|
const state = calendar.getDateState(date);
|
|
2606
2991
|
if (!confirmed || state.disabled)
|
|
@@ -2613,10 +2998,14 @@
|
|
|
2613
2998
|
return false;
|
|
2614
2999
|
if (!options.force && !field.isDirty)
|
|
2615
3000
|
return false;
|
|
2616
|
-
const result = await field.commit();
|
|
3001
|
+
const result = await field.commit(options);
|
|
2617
3002
|
if (result.status === "stale" || result.status === "invalid")
|
|
2618
3003
|
return false;
|
|
2619
|
-
this._setValue(result.value || "", {
|
|
3004
|
+
this._setValue(result.value || "", {
|
|
3005
|
+
emit,
|
|
3006
|
+
format: result.status === "ok",
|
|
3007
|
+
moveDisplay: options.moveDisplay
|
|
3008
|
+
});
|
|
2620
3009
|
return true;
|
|
2621
3010
|
}
|
|
2622
3011
|
async _commitFieldText(which) {
|
|
@@ -2691,19 +3080,21 @@
|
|
|
2691
3080
|
return;
|
|
2692
3081
|
this.dispatchEvent(new CustomEvent("rangechange", { detail: { ...this._range.range }, bubbles: true }));
|
|
2693
3082
|
}
|
|
3083
|
+
_displayRange() {
|
|
3084
|
+
const { start, end } = this._range?.range ?? { start: "", end: "" };
|
|
3085
|
+
if (!start)
|
|
3086
|
+
return { start: "", end: "" };
|
|
3087
|
+
if (end && compareDates(end, start) < 0)
|
|
3088
|
+
return { start, end: "" };
|
|
3089
|
+
return { start, end };
|
|
3090
|
+
}
|
|
2694
3091
|
_syncHighlight() {
|
|
2695
3092
|
if (!this._calendar || !this._range)
|
|
2696
3093
|
return;
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
}
|
|
2702
|
-
if (end && compareDates(end, start) < 0) {
|
|
2703
|
-
this._calendar.highlightedRange = { start, end: "" };
|
|
2704
|
-
} else {
|
|
2705
|
-
this._calendar.highlightedRange = { start, end };
|
|
2706
|
-
}
|
|
3094
|
+
this._previewDate = "";
|
|
3095
|
+
this._calendar.removeAttribute("data-range-preview");
|
|
3096
|
+
this._calendar.highlightedRange = this._displayRange();
|
|
3097
|
+
this._syncDragAffordance();
|
|
2707
3098
|
}
|
|
2708
3099
|
_revalidateRange(which) {
|
|
2709
3100
|
if (!this._fields || !this._range)
|
|
@@ -2825,7 +3216,7 @@
|
|
|
2825
3216
|
if (!fields)
|
|
2826
3217
|
return true;
|
|
2827
3218
|
for (const [index, field] of fields.entries()) {
|
|
2828
|
-
const result = await field.commit();
|
|
3219
|
+
const result = await field.commit({ moveDisplay: false });
|
|
2829
3220
|
if (result.status === "ok" || result.status === "clear") {
|
|
2830
3221
|
const which = index === 1 ? "end" : "start";
|
|
2831
3222
|
this._setBound(which, result.value || "", { format: result.status === "ok" });
|
|
@@ -2841,7 +3232,7 @@
|
|
|
2841
3232
|
if (!input.value.trim()) {
|
|
2842
3233
|
input.setCustomValidity("");
|
|
2843
3234
|
} else {
|
|
2844
|
-
await this._commitText(false, { force: true });
|
|
3235
|
+
await this._commitText(false, { force: true, moveDisplay: false });
|
|
2845
3236
|
}
|
|
2846
3237
|
this._revalidateTimeOrder("start");
|
|
2847
3238
|
this._revalidateTimeOrder("end");
|
|
@@ -2904,6 +3295,12 @@
|
|
|
2904
3295
|
this._setExpanded(false);
|
|
2905
3296
|
this._rangeCommitId++;
|
|
2906
3297
|
this._pendingIntents.clear();
|
|
3298
|
+
this._suppressGridClick = false;
|
|
3299
|
+
if (this._drag) {
|
|
3300
|
+
this._releaseDragCapture(this._drag.pointerId);
|
|
3301
|
+
this._drag = null;
|
|
3302
|
+
}
|
|
3303
|
+
this._syncHighlight();
|
|
2907
3304
|
if (restoreFocus) {
|
|
2908
3305
|
if (this._rangeMode()) {
|
|
2909
3306
|
const endpoint = this._restoreFocusEndpoint();
|