@lekoala/date-picker 0.2.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 +12 -8
- package/custom-elements.json +32 -2
- package/dist/date-picker.css +163 -115
- package/dist/date-picker.js +656 -171
- package/dist/date-picker.min.css +1 -1
- package/dist/date-picker.min.js +13 -13
- package/dist/date-picker.standalone.min.js +177 -129
- 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 +15 -5
- package/dist/types/date-field.d.ts.map +1 -1
- package/dist/types/date-picker.d.ts +153 -14
- 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 +22 -10
- package/docs/API.md +72 -3
- package/docs/ARCHITECTURE.md +16 -2
- package/docs/AT-CHECKLIST.md +1 -1
- package/docs/DECISIONS.md +19 -4
- package/docs/MIGRATION-FLATPICKR.md +2 -2
- package/docs/TESTING.md +1 -1
- package/docs/USE_CASES.md +3 -0
- package/package.json +7 -7
- package/src/date-calendar.js +148 -48
- package/src/date-field.js +20 -8
- package/src/date-picker.css +163 -115
- package/src/date-picker.js +549 -110
- 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] || "";
|
|
@@ -834,7 +987,7 @@
|
|
|
834
987
|
return weeks;
|
|
835
988
|
}
|
|
836
989
|
_focusTargetKey(element) {
|
|
837
|
-
if (element.matches(".dp-month-select, .dp-year-
|
|
990
|
+
if (element.matches(".dp-month-select, .dp-year-input") && element.id) {
|
|
838
991
|
return `#${CSS.escape(element.id)}`;
|
|
839
992
|
}
|
|
840
993
|
if (element.matches(".dp-nav[data-calendar-action]")) {
|
|
@@ -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;
|
|
@@ -1076,13 +1256,9 @@
|
|
|
1076
1256
|
this._setDisplay(`${this.display.slice(0, 4)}-${target.value}`);
|
|
1077
1257
|
return;
|
|
1078
1258
|
}
|
|
1079
|
-
if (target instanceof HTMLSelectElement && target.matches(".dp-year-select")) {
|
|
1080
|
-
this._setDisplay(`${target.value}-${this.display.slice(5, 7)}`);
|
|
1081
|
-
return;
|
|
1082
|
-
}
|
|
1083
1259
|
if (target instanceof HTMLInputElement && target.matches(".dp-year-input")) {
|
|
1084
1260
|
const year = Number(target.value);
|
|
1085
|
-
if (!Number.isInteger(year) || year < 1 || year >
|
|
1261
|
+
if (!Number.isInteger(year) || year < 1 || year > 9998) {
|
|
1086
1262
|
if (this._connected)
|
|
1087
1263
|
this.render(false);
|
|
1088
1264
|
return;
|
|
@@ -1095,8 +1271,10 @@
|
|
|
1095
1271
|
if (!(target instanceof HTMLTableCellElement) || !target.matches(".dp-day[data-date]"))
|
|
1096
1272
|
return;
|
|
1097
1273
|
const date = target.dataset.date || "";
|
|
1098
|
-
if (isDate(date))
|
|
1099
|
-
|
|
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 }));
|
|
1100
1278
|
}
|
|
1101
1279
|
_onKeyDown(event) {
|
|
1102
1280
|
const target = event.target;
|
|
@@ -1105,7 +1283,7 @@
|
|
|
1105
1283
|
const date = target.dataset.date || this.focusedDate;
|
|
1106
1284
|
if (event.key === "Enter" || event.key === " ") {
|
|
1107
1285
|
event.preventDefault();
|
|
1108
|
-
this.
|
|
1286
|
+
this.activateDate(date);
|
|
1109
1287
|
return;
|
|
1110
1288
|
}
|
|
1111
1289
|
const anchorFocused = this._model.focused;
|
|
@@ -1154,8 +1332,10 @@
|
|
|
1154
1332
|
const gridId = `${this._id}-grid`;
|
|
1155
1333
|
const minMonth = this.min ? monthKey(this.min) : "";
|
|
1156
1334
|
const maxMonth = this.max ? monthKey(this.max) : "";
|
|
1157
|
-
const
|
|
1158
|
-
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);
|
|
1159
1339
|
const minYearAttr = this.min ? ` min="${Number(this.min.slice(0, 4))}"` : "";
|
|
1160
1340
|
const maxYearAttr = this.max ? ` max="${Number(this.max.slice(0, 4))}"` : "";
|
|
1161
1341
|
const showWeeks = this.showWeekNumbers && this.firstDay === 1;
|
|
@@ -1176,14 +1356,7 @@
|
|
|
1176
1356
|
const focused = this.focusedDate === date;
|
|
1177
1357
|
const isToday = date === today;
|
|
1178
1358
|
const position = rangePosition(date, this._highlightedRange);
|
|
1179
|
-
const
|
|
1180
|
-
const description = typeof state.description === "string" ? state.description : "";
|
|
1181
|
-
const label = [
|
|
1182
|
-
formatLongDate(date, locale),
|
|
1183
|
-
description,
|
|
1184
|
-
rangeLabel ? this._messages[rangeLabel] : "",
|
|
1185
|
-
state.disabled ? this._messages.unavailable : ""
|
|
1186
|
-
].filter(Boolean).join(". ");
|
|
1359
|
+
const label = this._dayLabel(date, state, position);
|
|
1187
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>`;
|
|
1188
1361
|
}).join("");
|
|
1189
1362
|
return `<tr>${weekNumber}${cells}</tr>`;
|
|
@@ -1202,8 +1375,8 @@
|
|
|
1202
1375
|
<div class="dp-calendar-header">
|
|
1203
1376
|
${yearFirst ? yearControl : monthControl}
|
|
1204
1377
|
${yearFirst ? monthControl : yearControl}
|
|
1205
|
-
<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="
|
|
1206
|
-
<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>
|
|
1207
1380
|
</div>
|
|
1208
1381
|
<h2 id="${headingId}" class="dp-calendar-heading dp-visually-hidden" aria-live="polite">${escapeHtml(formatMonthYear(`${display}-15`, locale))}</h2>
|
|
1209
1382
|
<table id="${gridId}" class="dp-grid" role="grid" aria-labelledby="${headingId}">
|
|
@@ -1212,6 +1385,8 @@
|
|
|
1212
1385
|
</table>
|
|
1213
1386
|
</div>`;
|
|
1214
1387
|
this._rendering = false;
|
|
1388
|
+
this._paintedRange = { ...this._highlightedRange };
|
|
1389
|
+
this._paintedPreview = this.hasAttribute("data-range-preview");
|
|
1215
1390
|
if (focusKey) {
|
|
1216
1391
|
queueMicrotask(() => {
|
|
1217
1392
|
let selector = focusKey;
|
|
@@ -1560,8 +1735,11 @@
|
|
|
1560
1735
|
const availableHeight = `${getAvailableHeight(referenceRect, side, boundary, distance, shiftPadding)}px`;
|
|
1561
1736
|
const { style } = floating;
|
|
1562
1737
|
const roomChanged = style.getPropertyValue("--available-height") !== availableHeight;
|
|
1563
|
-
|
|
1564
|
-
|
|
1738
|
+
const win = options.coordinateSpace === "document" ? reference.ownerDocument.defaultView : null;
|
|
1739
|
+
const originX = win ? win.scrollX : 0;
|
|
1740
|
+
const originY = win ? win.scrollY : 0;
|
|
1741
|
+
style.left = `${coords.x + originX}px`;
|
|
1742
|
+
style.top = `${coords.y + originY}px`;
|
|
1565
1743
|
style.setProperty("--arrow-x", `${arrowX}%`);
|
|
1566
1744
|
style.setProperty("--arrow-y", `${arrowY}%`);
|
|
1567
1745
|
style.setProperty("--available-height", availableHeight);
|
|
@@ -1668,19 +1846,26 @@
|
|
|
1668
1846
|
}
|
|
1669
1847
|
handleInput() {
|
|
1670
1848
|
const input = this.input;
|
|
1671
|
-
|
|
1849
|
+
const text = input.value.trim();
|
|
1850
|
+
const canonical = this.canonical ? this.adapter.format(this.canonical) : "";
|
|
1672
1851
|
this.dirty();
|
|
1852
|
+
if (text === canonical) {
|
|
1853
|
+
this._dirty = false;
|
|
1854
|
+
if (this.hidden)
|
|
1855
|
+
this.hidden.value = this.canonical;
|
|
1856
|
+
input.setCustomValidity("");
|
|
1857
|
+
return;
|
|
1858
|
+
}
|
|
1859
|
+
this._dirty = true;
|
|
1673
1860
|
if (this.hidden)
|
|
1674
1861
|
this.hidden.value = "";
|
|
1675
|
-
const text = input.value.trim();
|
|
1676
1862
|
if (!text) {
|
|
1677
1863
|
input.setCustomValidity("");
|
|
1678
1864
|
return;
|
|
1679
1865
|
}
|
|
1680
|
-
const canonical = this.canonical ? this.adapter.format(this.canonical) : "";
|
|
1681
1866
|
input.setCustomValidity(text === canonical ? "" : this.messages.invalidDate);
|
|
1682
1867
|
}
|
|
1683
|
-
async commit() {
|
|
1868
|
+
async commit(options = {}) {
|
|
1684
1869
|
const input = this.input;
|
|
1685
1870
|
const commitId = ++this._commitId;
|
|
1686
1871
|
const text = input.value.trim();
|
|
@@ -1700,7 +1885,7 @@
|
|
|
1700
1885
|
return { status: "invalid" };
|
|
1701
1886
|
}
|
|
1702
1887
|
if (this.confirm) {
|
|
1703
|
-
const result = await this.confirm(parsed);
|
|
1888
|
+
const result = await this.confirm(parsed, options);
|
|
1704
1889
|
if (commitId !== this._commitId)
|
|
1705
1890
|
return { status: "stale" };
|
|
1706
1891
|
if (!result?.ok) {
|
|
@@ -1772,6 +1957,7 @@
|
|
|
1772
1957
|
|
|
1773
1958
|
// src/date-picker.js
|
|
1774
1959
|
var uid2 = 0;
|
|
1960
|
+
var DRAG_THRESHOLD = 4;
|
|
1775
1961
|
|
|
1776
1962
|
class DatePickerElement extends HTMLElement {
|
|
1777
1963
|
static observedAttributes = ["value", "locale", "min", "max", "open-on-focus", "month-format"];
|
|
@@ -1791,7 +1977,11 @@
|
|
|
1791
1977
|
this._lastFocusEndpoint = "";
|
|
1792
1978
|
this._rangeCommitId = 0;
|
|
1793
1979
|
this._pendingIntents = new Map;
|
|
1794
|
-
this.
|
|
1980
|
+
this._previewDate = "";
|
|
1981
|
+
this._drag = null;
|
|
1982
|
+
this._suppressGridClick = false;
|
|
1983
|
+
this._buttons = [];
|
|
1984
|
+
this._returnFocus = null;
|
|
1795
1985
|
this._panel = null;
|
|
1796
1986
|
this._calendar = null;
|
|
1797
1987
|
this._originalDescribedBy = "";
|
|
@@ -1807,6 +1997,7 @@
|
|
|
1807
1997
|
this._dateState = null;
|
|
1808
1998
|
this._renderDay = null;
|
|
1809
1999
|
this._isDateDisabled = null;
|
|
2000
|
+
this._coordinateSpace = "viewport";
|
|
1810
2001
|
}
|
|
1811
2002
|
_rangeMode() {
|
|
1812
2003
|
return this.hasAttribute("range") && Boolean(this._range);
|
|
@@ -1831,7 +2022,7 @@
|
|
|
1831
2022
|
this._discoverTimeFields();
|
|
1832
2023
|
this._field = new DateFieldController(input, { messages: this._messages, locale: this.locale });
|
|
1833
2024
|
this._field.onAttributesChanged = () => this._syncInputState();
|
|
1834
|
-
this._field.confirm = (date) => this._confirmDate(date);
|
|
2025
|
+
this._field.confirm = (date, options) => this._confirmDate(date, options);
|
|
1835
2026
|
this._setupFormValue();
|
|
1836
2027
|
this._build();
|
|
1837
2028
|
this._syncInputState();
|
|
@@ -1895,10 +2086,10 @@
|
|
|
1895
2086
|
];
|
|
1896
2087
|
for (const field of this._fields) {
|
|
1897
2088
|
field.onAttributesChanged = () => this._syncRangeFields();
|
|
1898
|
-
field.confirm = (date) => this._confirmDate(date);
|
|
2089
|
+
field.confirm = (date, options) => this._confirmDate(date, options);
|
|
1899
2090
|
field.setupFormValue();
|
|
1900
2091
|
}
|
|
1901
|
-
this._build(
|
|
2092
|
+
this._build();
|
|
1902
2093
|
this._setRangeAria();
|
|
1903
2094
|
this._syncRangeFields();
|
|
1904
2095
|
this._bindRange();
|
|
@@ -1938,10 +2129,12 @@
|
|
|
1938
2129
|
this._teardownField(this._field);
|
|
1939
2130
|
}
|
|
1940
2131
|
this._field = null;
|
|
1941
|
-
this.
|
|
2132
|
+
for (const { button } of this._buttons)
|
|
2133
|
+
button.remove();
|
|
2134
|
+
this._buttons = [];
|
|
2135
|
+
this._returnFocus = null;
|
|
1942
2136
|
this._panel?.remove();
|
|
1943
2137
|
this._formatHint?.remove();
|
|
1944
|
-
this._button = null;
|
|
1945
2138
|
this._panel = null;
|
|
1946
2139
|
this._calendar = null;
|
|
1947
2140
|
this._formatHint = null;
|
|
@@ -2105,6 +2298,12 @@
|
|
|
2105
2298
|
if (this._connected)
|
|
2106
2299
|
this.validate();
|
|
2107
2300
|
}
|
|
2301
|
+
get coordinateSpace() {
|
|
2302
|
+
return this._coordinateSpace;
|
|
2303
|
+
}
|
|
2304
|
+
set coordinateSpace(value) {
|
|
2305
|
+
this._coordinateSpace = value === "document" ? "document" : "viewport";
|
|
2306
|
+
}
|
|
2108
2307
|
_adapter() {
|
|
2109
2308
|
return this._field?.adapter ?? this._fields?.[0]?.adapter ?? createDateAdapter(this.locale);
|
|
2110
2309
|
}
|
|
@@ -2116,8 +2315,9 @@
|
|
|
2116
2315
|
if (!input)
|
|
2117
2316
|
return;
|
|
2118
2317
|
this._field?.syncInputState();
|
|
2119
|
-
|
|
2120
|
-
|
|
2318
|
+
const button = this._buttons[0]?.button;
|
|
2319
|
+
if (button)
|
|
2320
|
+
button.disabled = input.disabled || input.readOnly;
|
|
2121
2321
|
if (this._open && (input.disabled || input.readOnly))
|
|
2122
2322
|
this.hide(false);
|
|
2123
2323
|
}
|
|
@@ -2126,10 +2326,13 @@
|
|
|
2126
2326
|
return;
|
|
2127
2327
|
for (const field of this._fields)
|
|
2128
2328
|
field.syncInputState();
|
|
2329
|
+
for (const { button, endpoint } of this._buttons) {
|
|
2330
|
+
const index = endpoint === "end" ? 1 : 0;
|
|
2331
|
+
const field = this._fields[index];
|
|
2332
|
+
button.disabled = Boolean(field?.input.disabled || field?.input.readOnly);
|
|
2333
|
+
}
|
|
2334
|
+
this._syncDragAffordance();
|
|
2129
2335
|
const active = this._range?.activeEndpoint === "end" ? 1 : 0;
|
|
2130
|
-
const disabled = this._fields.every((field) => field.input.disabled || field.input.readOnly);
|
|
2131
|
-
if (this._button)
|
|
2132
|
-
this._button.disabled = disabled;
|
|
2133
2336
|
if (this._open && (this._fields[active]?.input.disabled || this._fields[active]?.input.readOnly)) {
|
|
2134
2337
|
this.hide(false);
|
|
2135
2338
|
}
|
|
@@ -2147,19 +2350,37 @@
|
|
|
2147
2350
|
input.setAttribute("aria-controls", this._panel.id);
|
|
2148
2351
|
}
|
|
2149
2352
|
}
|
|
2150
|
-
|
|
2151
|
-
const input = anchorInput || this._input;
|
|
2152
|
-
if (!input)
|
|
2153
|
-
return;
|
|
2154
|
-
const panelId = `${this._id}-panel`;
|
|
2155
|
-
const hintId = `${this._id}-format`;
|
|
2353
|
+
_createTrigger(endpoint) {
|
|
2156
2354
|
const button = document.createElement("button");
|
|
2157
2355
|
button.type = "button";
|
|
2158
2356
|
button.className = "dp-picker-button";
|
|
2159
2357
|
button.setAttribute("aria-haspopup", "dialog");
|
|
2160
2358
|
button.setAttribute("aria-expanded", "false");
|
|
2161
|
-
button.setAttribute("aria-controls",
|
|
2359
|
+
button.setAttribute("aria-controls", `${this._id}-panel`);
|
|
2360
|
+
if (endpoint)
|
|
2361
|
+
button.dataset.endpoint = endpoint;
|
|
2162
2362
|
button.innerHTML = '<span aria-hidden="true"><svg viewBox="0 0 16 16" width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"><rect x="1.75" y="3" width="12.5" height="11" rx="1.75"/><path d="M1.75 6.75h12.5"/><path d="M5.25 1.75v2.5M10.75 1.75v2.5"/></svg></span>';
|
|
2363
|
+
return button;
|
|
2364
|
+
}
|
|
2365
|
+
_build() {
|
|
2366
|
+
const ranges = this._rangeMode();
|
|
2367
|
+
const targets = [];
|
|
2368
|
+
if (ranges) {
|
|
2369
|
+
for (const [index, field] of (this._fields || []).entries()) {
|
|
2370
|
+
targets.push([field.input, index === 1 ? "end" : "start"]);
|
|
2371
|
+
}
|
|
2372
|
+
} else if (this._input) {
|
|
2373
|
+
targets.push([this._input, ""]);
|
|
2374
|
+
}
|
|
2375
|
+
if (!targets.length)
|
|
2376
|
+
return;
|
|
2377
|
+
const panelId = `${this._id}-panel`;
|
|
2378
|
+
const hintId = `${this._id}-format`;
|
|
2379
|
+
this._buttons = targets.map(([input, endpoint]) => {
|
|
2380
|
+
const button = this._createTrigger(endpoint);
|
|
2381
|
+
input.insertAdjacentElement("afterend", button);
|
|
2382
|
+
return { button, endpoint };
|
|
2383
|
+
});
|
|
2163
2384
|
const panel = document.createElement("div");
|
|
2164
2385
|
panel.id = panelId;
|
|
2165
2386
|
panel.className = "dp-picker-panel";
|
|
@@ -2173,28 +2394,25 @@
|
|
|
2173
2394
|
const hint = document.createElement("span");
|
|
2174
2395
|
hint.id = hintId;
|
|
2175
2396
|
hint.className = "dp-visually-hidden";
|
|
2176
|
-
|
|
2177
|
-
button.insertAdjacentElement("afterend", panel);
|
|
2178
|
-
panel.insertAdjacentElement("afterend", hint);
|
|
2179
|
-
this._button = button;
|
|
2397
|
+
this.append(panel, hint);
|
|
2180
2398
|
this._panel = panel;
|
|
2181
2399
|
this._calendar = calendar;
|
|
2182
2400
|
this._formatHint = hint;
|
|
2183
|
-
if (!this.
|
|
2184
|
-
this._originalDescribedBy =
|
|
2401
|
+
if (!ranges && this._input) {
|
|
2402
|
+
this._originalDescribedBy = this._input.getAttribute("aria-describedby") || "";
|
|
2185
2403
|
const describedBy = [this._originalDescribedBy, hintId].filter(Boolean).join(" ");
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2404
|
+
this._input.setAttribute("aria-describedby", describedBy);
|
|
2405
|
+
this._input.setAttribute("role", "combobox");
|
|
2406
|
+
this._input.setAttribute("aria-haspopup", "dialog");
|
|
2407
|
+
this._input.setAttribute("aria-expanded", "false");
|
|
2408
|
+
this._input.setAttribute("aria-controls", panelId);
|
|
2191
2409
|
}
|
|
2192
2410
|
this._refreshLocale();
|
|
2193
2411
|
this._refreshButtonLabel();
|
|
2194
2412
|
}
|
|
2195
2413
|
_bind() {
|
|
2196
2414
|
const input = this._input;
|
|
2197
|
-
const button = this.
|
|
2415
|
+
const button = this._buttons[0]?.button;
|
|
2198
2416
|
const calendar = this._calendar;
|
|
2199
2417
|
if (!input || !button || !calendar)
|
|
2200
2418
|
return;
|
|
@@ -2234,8 +2452,9 @@
|
|
|
2234
2452
|
this.hide(false);
|
|
2235
2453
|
return;
|
|
2236
2454
|
}
|
|
2237
|
-
this.show();
|
|
2455
|
+
this.show({ returnFocus: button });
|
|
2238
2456
|
}, { signal });
|
|
2457
|
+
button.addEventListener("keydown", (event) => this._onTriggerKeyDown("", event), { signal });
|
|
2239
2458
|
calendar.addEventListener("dateactivate", (event) => {
|
|
2240
2459
|
const custom = event;
|
|
2241
2460
|
const date = custom.detail?.date;
|
|
@@ -2249,7 +2468,7 @@
|
|
|
2249
2468
|
this._field?.dirty();
|
|
2250
2469
|
this._setValue(date, { emit: true, format: true });
|
|
2251
2470
|
this.hide(false);
|
|
2252
|
-
this.
|
|
2471
|
+
this._restoreFocus();
|
|
2253
2472
|
});
|
|
2254
2473
|
}, { signal });
|
|
2255
2474
|
calendar.addEventListener("dateloadend", () => void this.validate(), { signal });
|
|
@@ -2271,9 +2490,8 @@
|
|
|
2271
2490
|
this.addEventListener("keydown", (event) => this._onEscape(event), { signal });
|
|
2272
2491
|
}
|
|
2273
2492
|
_bindRange() {
|
|
2274
|
-
const button = this._button;
|
|
2275
2493
|
const calendar = this._calendar;
|
|
2276
|
-
if (!this._fields || !
|
|
2494
|
+
if (!this._fields || !this._buttons.length || !calendar)
|
|
2277
2495
|
return;
|
|
2278
2496
|
const controller = new AbortController;
|
|
2279
2497
|
this._controller = controller;
|
|
@@ -2286,18 +2504,26 @@
|
|
|
2286
2504
|
field.input.addEventListener("focus", (event) => this._onFieldFocus(endpoint, event), { signal });
|
|
2287
2505
|
field.input.addEventListener("keydown", (event) => this._onFieldKeyDown(endpoint, event), { signal });
|
|
2288
2506
|
}
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2507
|
+
for (const entry of this._buttons) {
|
|
2508
|
+
const endpoint = entry.endpoint;
|
|
2509
|
+
if (endpoint === "")
|
|
2510
|
+
continue;
|
|
2511
|
+
entry.button.addEventListener("click", (event) => this._onRangeTriggerClick(endpoint, event), {
|
|
2512
|
+
signal
|
|
2513
|
+
});
|
|
2514
|
+
entry.button.addEventListener("keydown", (event) => this._onTriggerKeyDown(endpoint, event), {
|
|
2515
|
+
signal
|
|
2516
|
+
});
|
|
2517
|
+
}
|
|
2518
|
+
calendar.addEventListener("click", (event) => {
|
|
2519
|
+
if (this._suppressGridClick) {
|
|
2520
|
+
this._suppressGridClick = false;
|
|
2521
|
+
event.preventDefault();
|
|
2522
|
+
event.stopImmediatePropagation();
|
|
2296
2523
|
return;
|
|
2297
2524
|
}
|
|
2298
|
-
this.
|
|
2299
|
-
}, { signal });
|
|
2300
|
-
calendar.addEventListener("click", (event) => this._captureGridIntent(event), { capture: true, signal });
|
|
2525
|
+
this._captureGridIntent(event);
|
|
2526
|
+
}, { capture: true, signal });
|
|
2301
2527
|
calendar.addEventListener("keydown", (event) => this._captureGridIntent(event), {
|
|
2302
2528
|
capture: true,
|
|
2303
2529
|
signal
|
|
@@ -2310,15 +2536,12 @@
|
|
|
2310
2536
|
queueMicrotask(() => {
|
|
2311
2537
|
if (custom.defaultPrevented || !this._connected || !this._range)
|
|
2312
2538
|
return;
|
|
2313
|
-
const
|
|
2314
|
-
if (
|
|
2539
|
+
const intent = this._pendingIntents.get(date);
|
|
2540
|
+
if (intent === undefined || intent.id !== this._rangeCommitId)
|
|
2315
2541
|
return;
|
|
2316
2542
|
this._pendingIntents.delete(date);
|
|
2317
|
-
const
|
|
2318
|
-
|
|
2319
|
-
const field = this._fields?.[index];
|
|
2320
|
-
return field != null && !field.input.disabled && !field.input.readOnly;
|
|
2321
|
-
});
|
|
2543
|
+
const editable = (bound) => this._boundEditable(bound);
|
|
2544
|
+
const result = intent.endpoint ? this._range.moveEndpoint(date, intent.endpoint, editable) : this._range.activate(date, editable);
|
|
2322
2545
|
if (result.status === "refused") {
|
|
2323
2546
|
this._calendar?.dispatchEvent(new CustomEvent("dateinvalid", {
|
|
2324
2547
|
detail: { date, state: this._calendar.getDateState(date) },
|
|
@@ -2326,13 +2549,23 @@
|
|
|
2326
2549
|
}));
|
|
2327
2550
|
return;
|
|
2328
2551
|
}
|
|
2329
|
-
this.
|
|
2552
|
+
this._applyRangeTransition(result);
|
|
2553
|
+
if (intent.endpoint)
|
|
2554
|
+
return;
|
|
2330
2555
|
if (result.close || result.status === "complete") {
|
|
2331
2556
|
this.hide(false);
|
|
2332
2557
|
this._focusField(result.endpoint);
|
|
2333
2558
|
}
|
|
2334
2559
|
});
|
|
2335
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 });
|
|
2336
2569
|
calendar.addEventListener("dateloadend", () => void this.validate(), { signal });
|
|
2337
2570
|
this.ownerDocument.addEventListener("pointerdown", (event) => {
|
|
2338
2571
|
if (!this._open || event.composedPath().includes(this))
|
|
@@ -2351,8 +2584,52 @@
|
|
|
2351
2584
|
}, { capture: true, signal });
|
|
2352
2585
|
this.addEventListener("keydown", (event) => this._onEscape(event), { signal });
|
|
2353
2586
|
}
|
|
2587
|
+
_activateRangeEndpoint(endpoint) {
|
|
2588
|
+
const calendar = this._calendar;
|
|
2589
|
+
if (!this._range || !calendar)
|
|
2590
|
+
return;
|
|
2591
|
+
this._range.focus(endpoint);
|
|
2592
|
+
this._rangeCommitId++;
|
|
2593
|
+
this._pendingIntents.clear();
|
|
2594
|
+
this._lastFocusEndpoint = endpoint;
|
|
2595
|
+
const target = this._boundCanonical(endpoint) || todayISO();
|
|
2596
|
+
calendar.display = monthKey(target);
|
|
2597
|
+
calendar.focusedDate = target;
|
|
2598
|
+
this._clearPreview();
|
|
2599
|
+
}
|
|
2600
|
+
_onRangeTriggerClick(endpoint, event) {
|
|
2601
|
+
if (!this._open) {
|
|
2602
|
+
this.show({ endpoint });
|
|
2603
|
+
return;
|
|
2604
|
+
}
|
|
2605
|
+
if (event.detail === 0) {
|
|
2606
|
+
this._activateRangeEndpoint(endpoint);
|
|
2607
|
+
setTimeout(() => this._calendar?.focusGrid(), 0);
|
|
2608
|
+
return;
|
|
2609
|
+
}
|
|
2610
|
+
if (endpoint !== this._range?.activeEndpoint) {
|
|
2611
|
+
this._activateRangeEndpoint(endpoint);
|
|
2612
|
+
return;
|
|
2613
|
+
}
|
|
2614
|
+
this.hide(false);
|
|
2615
|
+
}
|
|
2616
|
+
_onTriggerKeyDown(endpoint, event) {
|
|
2617
|
+
if (event.key !== "ArrowDown")
|
|
2618
|
+
return;
|
|
2619
|
+
event.preventDefault();
|
|
2620
|
+
if (this._open) {
|
|
2621
|
+
if (this._rangeMode() && endpoint)
|
|
2622
|
+
this._activateRangeEndpoint(endpoint);
|
|
2623
|
+
setTimeout(() => this._calendar?.focusGrid(), 0);
|
|
2624
|
+
return;
|
|
2625
|
+
}
|
|
2626
|
+
if (this._rangeMode())
|
|
2627
|
+
this.show({ endpoint: endpoint || undefined });
|
|
2628
|
+
else
|
|
2629
|
+
this.show({ returnFocus: this._buttons[0]?.button });
|
|
2630
|
+
}
|
|
2354
2631
|
_onFieldKeyDown(endpoint, event) {
|
|
2355
|
-
if (event.key === "ArrowDown"
|
|
2632
|
+
if (event.key === "ArrowDown") {
|
|
2356
2633
|
event.preventDefault();
|
|
2357
2634
|
if (this._rangeMode() && endpoint) {
|
|
2358
2635
|
this._lastFocusEndpoint = endpoint;
|
|
@@ -2400,7 +2677,191 @@
|
|
|
2400
2677
|
const date = cell?.getAttribute("data-date") || "";
|
|
2401
2678
|
if (!isDate(date))
|
|
2402
2679
|
return;
|
|
2403
|
-
this._pendingIntents.
|
|
2680
|
+
this._pendingIntents.clear();
|
|
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");
|
|
2404
2865
|
}
|
|
2405
2866
|
_onEscape(event) {
|
|
2406
2867
|
if (event.key === "Escape" && this._open) {
|
|
@@ -2462,7 +2923,8 @@
|
|
|
2462
2923
|
this._refreshButtonLabel();
|
|
2463
2924
|
}
|
|
2464
2925
|
_refreshButtonLabel() {
|
|
2465
|
-
|
|
2926
|
+
const single = this._buttons[0]?.button;
|
|
2927
|
+
if (!single)
|
|
2466
2928
|
return;
|
|
2467
2929
|
if (this._rangeMode()) {
|
|
2468
2930
|
this._refreshRangeButtonLabel();
|
|
@@ -2470,16 +2932,19 @@
|
|
|
2470
2932
|
}
|
|
2471
2933
|
const prefix = this._value ? this._messages.changeDate : this._messages.chooseDate;
|
|
2472
2934
|
const suffix = this._value ? `, ${formatLongDate(this._value, this.locale)}` : "";
|
|
2473
|
-
|
|
2935
|
+
single.setAttribute("aria-label", `${prefix}${suffix}`);
|
|
2474
2936
|
}
|
|
2475
2937
|
_refreshRangeButtonLabel() {
|
|
2476
|
-
if (!this.
|
|
2938
|
+
if (!this._range)
|
|
2477
2939
|
return;
|
|
2478
2940
|
const { start, end } = this._range;
|
|
2479
|
-
const
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2941
|
+
for (const { button, endpoint } of this._buttons) {
|
|
2942
|
+
const bound = endpoint === "end" ? end : start;
|
|
2943
|
+
const prefix = bound ? this._messages.changeDate : this._messages.chooseDate;
|
|
2944
|
+
const suffix = bound ? `, ${formatLongDate(bound, this.locale)}` : "";
|
|
2945
|
+
const boundLabel = endpoint === "end" ? this._messages.rangeEnd : this._messages.rangeStart;
|
|
2946
|
+
button.setAttribute("aria-label", `${prefix}${suffix}, ${boundLabel}`);
|
|
2947
|
+
}
|
|
2483
2948
|
}
|
|
2484
2949
|
_reflectValue(value) {
|
|
2485
2950
|
this._reflecting = true;
|
|
@@ -2499,7 +2964,7 @@
|
|
|
2499
2964
|
this._field?.setCanonical(this._value, { format: options.format !== false });
|
|
2500
2965
|
if (this._calendar) {
|
|
2501
2966
|
this._calendar.value = this._value;
|
|
2502
|
-
if (this._value)
|
|
2967
|
+
if (this._value && options.moveDisplay !== false)
|
|
2503
2968
|
this._calendar.focusedDate = this._value;
|
|
2504
2969
|
}
|
|
2505
2970
|
this._refreshButtonLabel();
|
|
@@ -2512,13 +2977,15 @@
|
|
|
2512
2977
|
}
|
|
2513
2978
|
}
|
|
2514
2979
|
}
|
|
2515
|
-
async _confirmDate(date) {
|
|
2980
|
+
async _confirmDate(date, options = {}) {
|
|
2516
2981
|
const calendar = this._calendar;
|
|
2517
2982
|
if (!calendar)
|
|
2518
2983
|
return { ok: true };
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
calendar.display
|
|
2984
|
+
if (options.moveDisplay !== false) {
|
|
2985
|
+
const display = monthKey(date);
|
|
2986
|
+
if (calendar.display !== display)
|
|
2987
|
+
calendar.display = display;
|
|
2988
|
+
}
|
|
2522
2989
|
const confirmed = await calendar.ensureDate(date);
|
|
2523
2990
|
const state = calendar.getDateState(date);
|
|
2524
2991
|
if (!confirmed || state.disabled)
|
|
@@ -2531,10 +2998,14 @@
|
|
|
2531
2998
|
return false;
|
|
2532
2999
|
if (!options.force && !field.isDirty)
|
|
2533
3000
|
return false;
|
|
2534
|
-
const result = await field.commit();
|
|
3001
|
+
const result = await field.commit(options);
|
|
2535
3002
|
if (result.status === "stale" || result.status === "invalid")
|
|
2536
3003
|
return false;
|
|
2537
|
-
this._setValue(result.value || "", {
|
|
3004
|
+
this._setValue(result.value || "", {
|
|
3005
|
+
emit,
|
|
3006
|
+
format: result.status === "ok",
|
|
3007
|
+
moveDisplay: options.moveDisplay
|
|
3008
|
+
});
|
|
2538
3009
|
return true;
|
|
2539
3010
|
}
|
|
2540
3011
|
async _commitFieldText(which) {
|
|
@@ -2552,7 +3023,7 @@
|
|
|
2552
3023
|
this._orderTags.delete(index);
|
|
2553
3024
|
return false;
|
|
2554
3025
|
}
|
|
2555
|
-
this._setBound(which, result.value || "", { emit:
|
|
3026
|
+
this._setBound(which, result.value || "", { emit: false, user: true, format: result.status === "ok" });
|
|
2556
3027
|
return true;
|
|
2557
3028
|
}
|
|
2558
3029
|
_setBound(which, value, options = {}) {
|
|
@@ -2609,19 +3080,21 @@
|
|
|
2609
3080
|
return;
|
|
2610
3081
|
this.dispatchEvent(new CustomEvent("rangechange", { detail: { ...this._range.range }, bubbles: true }));
|
|
2611
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
|
+
}
|
|
2612
3091
|
_syncHighlight() {
|
|
2613
3092
|
if (!this._calendar || !this._range)
|
|
2614
3093
|
return;
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
}
|
|
2620
|
-
if (end && compareDates(end, start) < 0) {
|
|
2621
|
-
this._calendar.highlightedRange = { start, end: "" };
|
|
2622
|
-
} else {
|
|
2623
|
-
this._calendar.highlightedRange = { start, end };
|
|
2624
|
-
}
|
|
3094
|
+
this._previewDate = "";
|
|
3095
|
+
this._calendar.removeAttribute("data-range-preview");
|
|
3096
|
+
this._calendar.highlightedRange = this._displayRange();
|
|
3097
|
+
this._syncDragAffordance();
|
|
2625
3098
|
}
|
|
2626
3099
|
_revalidateRange(which) {
|
|
2627
3100
|
if (!this._fields || !this._range)
|
|
@@ -2711,10 +3184,14 @@
|
|
|
2711
3184
|
this._suppressFocusOpen = false;
|
|
2712
3185
|
}, 0);
|
|
2713
3186
|
}
|
|
2714
|
-
|
|
3187
|
+
_restoreFocus() {
|
|
3188
|
+
const target = this._returnFocus;
|
|
3189
|
+
this._returnFocus = null;
|
|
3190
|
+
if (!(target instanceof HTMLElement) || !target.isConnected || target.matches(":disabled"))
|
|
3191
|
+
return;
|
|
2715
3192
|
this._suppressFocusOpen = true;
|
|
2716
3193
|
setTimeout(() => {
|
|
2717
|
-
|
|
3194
|
+
target.focus();
|
|
2718
3195
|
this._suppressFocusOpen = false;
|
|
2719
3196
|
}, 0);
|
|
2720
3197
|
}
|
|
@@ -2739,7 +3216,7 @@
|
|
|
2739
3216
|
if (!fields)
|
|
2740
3217
|
return true;
|
|
2741
3218
|
for (const [index, field] of fields.entries()) {
|
|
2742
|
-
const result = await field.commit();
|
|
3219
|
+
const result = await field.commit({ moveDisplay: false });
|
|
2743
3220
|
if (result.status === "ok" || result.status === "clear") {
|
|
2744
3221
|
const which = index === 1 ? "end" : "start";
|
|
2745
3222
|
this._setBound(which, result.value || "", { format: result.status === "ok" });
|
|
@@ -2755,7 +3232,7 @@
|
|
|
2755
3232
|
if (!input.value.trim()) {
|
|
2756
3233
|
input.setCustomValidity("");
|
|
2757
3234
|
} else {
|
|
2758
|
-
await this._commitText(false, { force: true });
|
|
3235
|
+
await this._commitText(false, { force: true, moveDisplay: false });
|
|
2759
3236
|
}
|
|
2760
3237
|
this._revalidateTimeOrder("start");
|
|
2761
3238
|
this._revalidateTimeOrder("end");
|
|
@@ -2765,20 +3242,13 @@
|
|
|
2765
3242
|
show(options = {}) {
|
|
2766
3243
|
const panel = this._panel;
|
|
2767
3244
|
const calendar = this._calendar;
|
|
2768
|
-
|
|
2769
|
-
if (!panel || !calendar || !button || this._open)
|
|
3245
|
+
if (!panel || !calendar || !this._buttons.length || this._open)
|
|
2770
3246
|
return;
|
|
2771
3247
|
if (this._rangeMode()) {
|
|
2772
|
-
const endpoint = this._resolveRangeEndpoint();
|
|
3248
|
+
const endpoint = options.endpoint || this._resolveRangeEndpoint();
|
|
2773
3249
|
if (!endpoint)
|
|
2774
3250
|
return;
|
|
2775
|
-
this.
|
|
2776
|
-
this._rangeCommitId++;
|
|
2777
|
-
this._pendingIntents.clear();
|
|
2778
|
-
const target = this._boundCanonical(endpoint) || todayISO();
|
|
2779
|
-
calendar.display = monthKey(target);
|
|
2780
|
-
calendar.focusedDate = target;
|
|
2781
|
-
this._lastFocusEndpoint = endpoint;
|
|
3251
|
+
this._activateRangeEndpoint(endpoint);
|
|
2782
3252
|
} else {
|
|
2783
3253
|
const input = this._input;
|
|
2784
3254
|
if (!input || input.disabled || input.readOnly)
|
|
@@ -2786,11 +3256,19 @@
|
|
|
2786
3256
|
const target = this._value || this._adapter().parse(input.value) || todayISO();
|
|
2787
3257
|
calendar.display = monthKey(target);
|
|
2788
3258
|
calendar.focusedDate = target;
|
|
3259
|
+
this._returnFocus = options.returnFocus instanceof HTMLElement ? options.returnFocus : input;
|
|
2789
3260
|
}
|
|
2790
3261
|
panel.showPopover();
|
|
2791
3262
|
this._open = true;
|
|
2792
3263
|
this._setExpanded(true);
|
|
2793
|
-
const
|
|
3264
|
+
const coordinateSpace = this.coordinateSpace;
|
|
3265
|
+
panel.style.position = coordinateSpace === "document" ? "absolute" : "fixed";
|
|
3266
|
+
const position = () => reposition(this, panel, {
|
|
3267
|
+
placement: "bottom-start",
|
|
3268
|
+
distance: 4,
|
|
3269
|
+
shiftPadding: 8,
|
|
3270
|
+
coordinateSpace
|
|
3271
|
+
});
|
|
2794
3272
|
position();
|
|
2795
3273
|
this._stopTracking = autoUpdate(this, panel, position);
|
|
2796
3274
|
if (options.moveFocus !== false)
|
|
@@ -2800,7 +3278,8 @@
|
|
|
2800
3278
|
_setExpanded(expanded) {
|
|
2801
3279
|
const value = expanded ? "true" : "false";
|
|
2802
3280
|
this._input?.setAttribute("aria-expanded", value);
|
|
2803
|
-
this.
|
|
3281
|
+
for (const { button } of this._buttons)
|
|
3282
|
+
button.setAttribute("aria-expanded", value);
|
|
2804
3283
|
for (const field of this._fields || [])
|
|
2805
3284
|
field.input.setAttribute("aria-expanded", value);
|
|
2806
3285
|
}
|
|
@@ -2816,13 +3295,19 @@
|
|
|
2816
3295
|
this._setExpanded(false);
|
|
2817
3296
|
this._rangeCommitId++;
|
|
2818
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();
|
|
2819
3304
|
if (restoreFocus) {
|
|
2820
3305
|
if (this._rangeMode()) {
|
|
2821
3306
|
const endpoint = this._restoreFocusEndpoint();
|
|
2822
3307
|
if (endpoint)
|
|
2823
3308
|
this._focusField(endpoint);
|
|
2824
3309
|
} else {
|
|
2825
|
-
this.
|
|
3310
|
+
this._restoreFocus();
|
|
2826
3311
|
}
|
|
2827
3312
|
}
|
|
2828
3313
|
this.dispatchEvent(new Event("close", { bubbles: true }));
|