@lekoala/date-picker 0.4.0 → 0.5.1
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 +294 -265
- package/custom-elements.json +50 -0
- package/dist/date-picker.css +20 -15
- package/dist/date-picker.js +366 -149
- package/dist/date-picker.min.css +1 -1
- package/dist/date-picker.min.js +13 -13
- package/dist/date-picker.standalone.min.js +34 -29
- package/dist/types/control-classes.d.ts +40 -0
- package/dist/types/control-classes.d.ts.map +1 -0
- package/dist/types/date-calendar.d.ts +35 -43
- package/dist/types/date-calendar.d.ts.map +1 -1
- package/dist/types/date-picker.d.ts +44 -53
- package/dist/types/date-picker.d.ts.map +1 -1
- package/dist/types/date.d.ts +4 -2
- package/dist/types/date.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/intl.d.ts.map +1 -1
- package/dist/types/messages.d.ts +2 -0
- package/dist/types/messages.d.ts.map +1 -1
- package/dist/types/source.d.ts +1 -0
- package/dist/types/source.d.ts.map +1 -1
- package/dist/types/upgrade-properties.d.ts +8 -0
- package/dist/types/upgrade-properties.d.ts.map +1 -0
- package/docs/API.md +442 -408
- package/docs/DECISIONS.md +74 -62
- package/docs/USE_CASES.md +156 -144
- package/package.json +3 -3
- package/src/control-classes.js +80 -0
- package/src/date-calendar.js +124 -27
- package/src/date-field.js +1 -1
- package/src/date-picker.css +20 -15
- package/src/date-picker.js +133 -74
- package/src/date.js +8 -3
- package/src/index.js +1 -0
- package/src/intl.js +39 -10
- package/src/messages.js +12 -0
- package/src/source.js +14 -4
- package/src/upgrade-properties.js +14 -0
package/dist/date-picker.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*** @lekoala/date-picker v0.
|
|
1
|
+
/*** @lekoala/date-picker v0.5.1 - https://github.com/lekoala/date-picker ***/
|
|
2
2
|
(() => {
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -181,8 +181,10 @@
|
|
|
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
|
-
|
|
184
|
+
if (compareDates(week[6], end) >= 0) {
|
|
185
|
+
if (!options.fixedWeeks || weeks.length >= 6 || compareDates(week[6], addDays("9999-12-31", -7)) > 0)
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
186
188
|
cursor = addDays(cursor, 7);
|
|
187
189
|
}
|
|
188
190
|
return weeks;
|
|
@@ -296,6 +298,53 @@
|
|
|
296
298
|
}
|
|
297
299
|
}
|
|
298
300
|
|
|
301
|
+
// src/control-classes.js
|
|
302
|
+
function normalizeControlClass(value) {
|
|
303
|
+
if (typeof value !== "string")
|
|
304
|
+
return "";
|
|
305
|
+
return [
|
|
306
|
+
...new Set(value.split(/\s+/).filter((token) => token && !token.startsWith("dp-") && ![...token].some((char) => char.charCodeAt(0) < 32 || char.charCodeAt(0) === 127)))
|
|
307
|
+
].join(" ");
|
|
308
|
+
}
|
|
309
|
+
function sameControlClasses(a, b) {
|
|
310
|
+
return a.month === b.month && a.year === b.year && a.nav === b.nav;
|
|
311
|
+
}
|
|
312
|
+
var defaults = { month: "", year: "", nav: "" };
|
|
313
|
+
function getDefaultControlClasses() {
|
|
314
|
+
return { ...defaults };
|
|
315
|
+
}
|
|
316
|
+
function normalizeControlClasses(classes) {
|
|
317
|
+
if (classes == null)
|
|
318
|
+
return null;
|
|
319
|
+
const result = {};
|
|
320
|
+
for (const role of ["month", "year", "nav"]) {
|
|
321
|
+
if (Object.hasOwn(classes, role))
|
|
322
|
+
result[role] = normalizeControlClass(classes[role]);
|
|
323
|
+
}
|
|
324
|
+
return result;
|
|
325
|
+
}
|
|
326
|
+
function usesDefaultControlClasses(classes) {
|
|
327
|
+
return classes == null || ["month", "year", "nav"].some((role) => !Object.hasOwn(classes, role));
|
|
328
|
+
}
|
|
329
|
+
function resolveControlClasses(classes) {
|
|
330
|
+
return { ...getDefaultControlClasses(), ...normalizeControlClasses(classes) };
|
|
331
|
+
}
|
|
332
|
+
function setDefaultControlClasses(classes) {
|
|
333
|
+
const next = resolveControlClasses(classes);
|
|
334
|
+
if (sameControlClasses(defaults, next))
|
|
335
|
+
return;
|
|
336
|
+
defaults = next;
|
|
337
|
+
for (const listener of listeners)
|
|
338
|
+
listener();
|
|
339
|
+
}
|
|
340
|
+
var listeners = new Set;
|
|
341
|
+
function subscribeDefaultControlClasses(listener) {
|
|
342
|
+
listeners.add(listener);
|
|
343
|
+
return () => {
|
|
344
|
+
listeners.delete(listener);
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
299
348
|
// src/date-range.js
|
|
300
349
|
function normalizeRange(range) {
|
|
301
350
|
if (range == null)
|
|
@@ -480,6 +529,23 @@
|
|
|
480
529
|
|
|
481
530
|
// src/intl.js
|
|
482
531
|
var BIDI = /[\u200e\u200f\u061c\u202a-\u202e\u2066-\u2069]/g;
|
|
532
|
+
var dateFormatters = new Map;
|
|
533
|
+
var digitMaps = new Map;
|
|
534
|
+
function cached(cache, key, create) {
|
|
535
|
+
const existing = cache.get(key);
|
|
536
|
+
if (existing !== undefined)
|
|
537
|
+
return existing;
|
|
538
|
+
const value = create();
|
|
539
|
+
const oldest = cache.keys().next().value;
|
|
540
|
+
if (cache.size >= 64 && oldest !== undefined)
|
|
541
|
+
cache.delete(oldest);
|
|
542
|
+
cache.set(key, value);
|
|
543
|
+
return value;
|
|
544
|
+
}
|
|
545
|
+
function dateFormatter(locale, options) {
|
|
546
|
+
const key = JSON.stringify([locale, options]);
|
|
547
|
+
return cached(dateFormatters, key, () => new Intl.DateTimeFormat(locale, options));
|
|
548
|
+
}
|
|
483
549
|
function resolveLocale(locale = "") {
|
|
484
550
|
if (locale)
|
|
485
551
|
return locale;
|
|
@@ -490,11 +556,13 @@
|
|
|
490
556
|
return "en-US";
|
|
491
557
|
}
|
|
492
558
|
function digitMap(locale) {
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
559
|
+
return cached(digitMaps, locale, () => {
|
|
560
|
+
const formatter = new Intl.NumberFormat(locale, { useGrouping: false });
|
|
561
|
+
const map = new Map;
|
|
562
|
+
for (let i = 0;i <= 9; i++)
|
|
563
|
+
map.set(formatter.format(i), String(i));
|
|
564
|
+
return map;
|
|
565
|
+
});
|
|
498
566
|
}
|
|
499
567
|
function normalizeDigits(text, locale, options = {}) {
|
|
500
568
|
let result = String(text || "").replace(BIDI, "");
|
|
@@ -506,7 +574,7 @@
|
|
|
506
574
|
}
|
|
507
575
|
function formatLongDate(value, locale = "") {
|
|
508
576
|
const resolved = resolveLocale(locale);
|
|
509
|
-
return
|
|
577
|
+
return dateFormatter(resolved, {
|
|
510
578
|
calendar: "gregory",
|
|
511
579
|
weekday: "long",
|
|
512
580
|
year: "numeric",
|
|
@@ -517,7 +585,7 @@
|
|
|
517
585
|
}
|
|
518
586
|
function formatMonthYear(value, locale = "") {
|
|
519
587
|
const resolved = resolveLocale(locale);
|
|
520
|
-
return
|
|
588
|
+
return dateFormatter(resolved, {
|
|
521
589
|
calendar: "gregory",
|
|
522
590
|
year: "numeric",
|
|
523
591
|
month: "long",
|
|
@@ -527,7 +595,7 @@
|
|
|
527
595
|
function monthYearOrder(locale = "") {
|
|
528
596
|
const resolved = resolveLocale(locale);
|
|
529
597
|
try {
|
|
530
|
-
const parts =
|
|
598
|
+
const parts = dateFormatter(resolved, {
|
|
531
599
|
calendar: "gregory",
|
|
532
600
|
year: "numeric",
|
|
533
601
|
month: "long",
|
|
@@ -552,12 +620,12 @@
|
|
|
552
620
|
}
|
|
553
621
|
function monthNames(locale = "", style = "long") {
|
|
554
622
|
const resolved = resolveLocale(locale);
|
|
555
|
-
const formatter =
|
|
623
|
+
const formatter = dateFormatter(resolved, { calendar: "gregory", month: style, timeZone: "UTC" });
|
|
556
624
|
return Array.from({ length: 12 }, (_, index) => formatter.format(toIntlDate(`2026-${String(index + 1).padStart(2, "0")}-15`)));
|
|
557
625
|
}
|
|
558
626
|
function weekdayNames(locale = "", firstDay = 1, style = "short") {
|
|
559
627
|
const resolved = resolveLocale(locale);
|
|
560
|
-
const formatter =
|
|
628
|
+
const formatter = dateFormatter(resolved, {
|
|
561
629
|
calendar: "gregory",
|
|
562
630
|
weekday: style,
|
|
563
631
|
timeZone: "UTC"
|
|
@@ -575,7 +643,7 @@
|
|
|
575
643
|
}
|
|
576
644
|
function createDateAdapter(locale = "") {
|
|
577
645
|
const resolved = resolveLocale(locale);
|
|
578
|
-
const formatter =
|
|
646
|
+
const formatter = dateFormatter(resolved, {
|
|
579
647
|
calendar: "gregory",
|
|
580
648
|
year: "numeric",
|
|
581
649
|
month: "2-digit",
|
|
@@ -654,9 +722,21 @@
|
|
|
654
722
|
rangeOrderStart: "Start must be on or before end",
|
|
655
723
|
rangeOrderEnd: "End must be on or after start"
|
|
656
724
|
};
|
|
657
|
-
var
|
|
725
|
+
var defaults2 = { ...DEFAULT_MESSAGES };
|
|
658
726
|
function getDefaultMessages() {
|
|
659
|
-
return { ...
|
|
727
|
+
return { ...defaults2 };
|
|
728
|
+
}
|
|
729
|
+
function setDefaultMessages(messages) {
|
|
730
|
+
defaults2 = { ...defaults2, ...messages };
|
|
731
|
+
for (const listener of listeners2)
|
|
732
|
+
listener();
|
|
733
|
+
}
|
|
734
|
+
var listeners2 = new Set;
|
|
735
|
+
function subscribeDefaultMessages(listener) {
|
|
736
|
+
listeners2.add(listener);
|
|
737
|
+
return () => {
|
|
738
|
+
listeners2.delete(listener);
|
|
739
|
+
};
|
|
660
740
|
}
|
|
661
741
|
|
|
662
742
|
// src/source.js
|
|
@@ -680,6 +760,17 @@
|
|
|
680
760
|
return map;
|
|
681
761
|
}
|
|
682
762
|
|
|
763
|
+
// src/upgrade-properties.js
|
|
764
|
+
function upgradeProperties(element, properties) {
|
|
765
|
+
for (const property of properties) {
|
|
766
|
+
if (!Object.hasOwn(element, property))
|
|
767
|
+
continue;
|
|
768
|
+
const value = Reflect.get(element, property);
|
|
769
|
+
Reflect.deleteProperty(element, property);
|
|
770
|
+
Reflect.set(element, property, value);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
683
774
|
// src/date-calendar.js
|
|
684
775
|
var uid = 0;
|
|
685
776
|
function escapeHtml(value) {
|
|
@@ -738,6 +829,18 @@
|
|
|
738
829
|
"selection",
|
|
739
830
|
"month-format"
|
|
740
831
|
];
|
|
832
|
+
static setDefaultControlClasses(classes) {
|
|
833
|
+
setDefaultControlClasses(classes);
|
|
834
|
+
}
|
|
835
|
+
static getDefaultControlClasses() {
|
|
836
|
+
return getDefaultControlClasses();
|
|
837
|
+
}
|
|
838
|
+
static setDefaultMessages(messages) {
|
|
839
|
+
setDefaultMessages(messages);
|
|
840
|
+
}
|
|
841
|
+
static getDefaultMessages() {
|
|
842
|
+
return getDefaultMessages();
|
|
843
|
+
}
|
|
741
844
|
constructor() {
|
|
742
845
|
super();
|
|
743
846
|
this._id = `date-calendar-${++uid}`;
|
|
@@ -756,7 +859,11 @@
|
|
|
756
859
|
this._highlightedRange = { start: "", end: "" };
|
|
757
860
|
this._paintedRange = { start: "", end: "" };
|
|
758
861
|
this._paintedPreview = false;
|
|
759
|
-
this.
|
|
862
|
+
this._renderedStates = new Map;
|
|
863
|
+
this._messages = null;
|
|
864
|
+
this._controlClasses = null;
|
|
865
|
+
this._stopDefaultMessages = null;
|
|
866
|
+
this._stopDefaultControlClasses = null;
|
|
760
867
|
this._onClick = this._onClick.bind(this);
|
|
761
868
|
this._onChange = this._onChange.bind(this);
|
|
762
869
|
this._onKeyDown = this._onKeyDown.bind(this);
|
|
@@ -765,15 +872,47 @@
|
|
|
765
872
|
connectedCallback() {
|
|
766
873
|
if (this._connected)
|
|
767
874
|
return;
|
|
875
|
+
upgradeProperties(this, [
|
|
876
|
+
"locale",
|
|
877
|
+
"min",
|
|
878
|
+
"max",
|
|
879
|
+
"firstDay",
|
|
880
|
+
"selection",
|
|
881
|
+
"monthFormat",
|
|
882
|
+
"fixedWeeks",
|
|
883
|
+
"showWeekNumbers",
|
|
884
|
+
"controlClasses",
|
|
885
|
+
"messages",
|
|
886
|
+
"source",
|
|
887
|
+
"dateState",
|
|
888
|
+
"renderDay",
|
|
889
|
+
"isDateDisabled",
|
|
890
|
+
"highlightedRange",
|
|
891
|
+
"value",
|
|
892
|
+
"display"
|
|
893
|
+
]);
|
|
894
|
+
this._syncModel();
|
|
895
|
+
upgradeProperties(this, ["focusedDate"]);
|
|
896
|
+
this._stopDefaultControlClasses = subscribeDefaultControlClasses(() => {
|
|
897
|
+
if (usesDefaultControlClasses(this._controlClasses))
|
|
898
|
+
this.render();
|
|
899
|
+
});
|
|
900
|
+
this._stopDefaultMessages = subscribeDefaultMessages(() => {
|
|
901
|
+
if (this._messages === null)
|
|
902
|
+
this.render();
|
|
903
|
+
});
|
|
768
904
|
this._connected = true;
|
|
769
905
|
this.addEventListener("click", this._onClick);
|
|
770
906
|
this.addEventListener("change", this._onChange);
|
|
771
907
|
this.addEventListener("keydown", this._onKeyDown);
|
|
772
908
|
this.addEventListener("focusin", this._onFocusIn);
|
|
773
|
-
this._syncModel();
|
|
774
909
|
this.render();
|
|
775
910
|
}
|
|
776
911
|
disconnectedCallback() {
|
|
912
|
+
this._stopDefaultControlClasses?.();
|
|
913
|
+
this._stopDefaultControlClasses = null;
|
|
914
|
+
this._stopDefaultMessages?.();
|
|
915
|
+
this._stopDefaultMessages = null;
|
|
777
916
|
this._connected = false;
|
|
778
917
|
this._loadController?.abort();
|
|
779
918
|
this._loadController = null;
|
|
@@ -893,11 +1032,22 @@
|
|
|
893
1032
|
set showWeekNumbers(value) {
|
|
894
1033
|
this.toggleAttribute("show-week-numbers", Boolean(value));
|
|
895
1034
|
}
|
|
1035
|
+
get controlClasses() {
|
|
1036
|
+
return resolveControlClasses(this._controlClasses);
|
|
1037
|
+
}
|
|
1038
|
+
set controlClasses(value) {
|
|
1039
|
+
const previous = this.controlClasses;
|
|
1040
|
+
this._controlClasses = normalizeControlClasses(value);
|
|
1041
|
+
if (sameControlClasses(previous, this.controlClasses))
|
|
1042
|
+
return;
|
|
1043
|
+
if (this._connected)
|
|
1044
|
+
this.render();
|
|
1045
|
+
}
|
|
896
1046
|
get messages() {
|
|
897
|
-
return this._messages;
|
|
1047
|
+
return this._messages ?? getDefaultMessages();
|
|
898
1048
|
}
|
|
899
1049
|
set messages(value) {
|
|
900
|
-
this._messages = { ...getDefaultMessages(), ...value
|
|
1050
|
+
this._messages = value == null ? null : { ...getDefaultMessages(), ...value };
|
|
901
1051
|
if (this._connected)
|
|
902
1052
|
this.render();
|
|
903
1053
|
}
|
|
@@ -973,18 +1123,10 @@
|
|
|
973
1123
|
return compareDates(candidate, last) > 0 ? last : candidate;
|
|
974
1124
|
}
|
|
975
1125
|
_weeks(display = this.display) {
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
while (weeks.length < 6 && cursor) {
|
|
981
|
-
const week = [];
|
|
982
|
-
for (let i = 1;i <= 7; i++)
|
|
983
|
-
week.push(addDays(cursor, i));
|
|
984
|
-
weeks.push(week);
|
|
985
|
-
cursor = week[6];
|
|
986
|
-
}
|
|
987
|
-
return weeks;
|
|
1126
|
+
return getMonthWeeks(clampDisplayMonth(display, this.firstDay), {
|
|
1127
|
+
firstDay: this.firstDay,
|
|
1128
|
+
fixedWeeks: this.fixedWeeks
|
|
1129
|
+
});
|
|
988
1130
|
}
|
|
989
1131
|
_focusTargetKey(element) {
|
|
990
1132
|
if (element.matches(".dp-month-select, .dp-year-input") && element.id) {
|
|
@@ -1166,11 +1308,13 @@
|
|
|
1166
1308
|
return [
|
|
1167
1309
|
formatLongDate(date, this.locale),
|
|
1168
1310
|
description,
|
|
1169
|
-
rangeLabel ? this.
|
|
1170
|
-
state.disabled ? this.
|
|
1311
|
+
rangeLabel ? this.messages[rangeLabel] : "",
|
|
1312
|
+
state.disabled ? this.messages.unavailable : ""
|
|
1171
1313
|
].filter(Boolean).join(". ");
|
|
1172
1314
|
}
|
|
1173
1315
|
_updateRangeDom() {
|
|
1316
|
+
const previousRange = this._paintedRange;
|
|
1317
|
+
const previousPreview = this._paintedPreview;
|
|
1174
1318
|
this._paintedRange = { ...this._highlightedRange };
|
|
1175
1319
|
this._paintedPreview = this.hasAttribute("data-range-preview");
|
|
1176
1320
|
for (const cell of this.querySelectorAll(".dp-day[data-date]")) {
|
|
@@ -1178,13 +1322,20 @@
|
|
|
1178
1322
|
continue;
|
|
1179
1323
|
const date = cell.dataset.date || "";
|
|
1180
1324
|
const position = rangePosition(date, this._highlightedRange);
|
|
1325
|
+
if (position === rangePosition(date, previousRange) && previousPreview === this._paintedPreview)
|
|
1326
|
+
continue;
|
|
1181
1327
|
for (const [name, on] of Object.entries(rangeAttributeMap(position))) {
|
|
1182
1328
|
if (on)
|
|
1183
1329
|
cell.setAttribute(name, "true");
|
|
1184
1330
|
else
|
|
1185
1331
|
cell.removeAttribute(name);
|
|
1186
1332
|
}
|
|
1187
|
-
|
|
1333
|
+
if (!previousPreview || !this._paintedPreview) {
|
|
1334
|
+
const state = this._renderedStates.get(date) || {};
|
|
1335
|
+
const label = this._dayLabel(date, state, position);
|
|
1336
|
+
if (cell.getAttribute("aria-label") !== label)
|
|
1337
|
+
cell.setAttribute("aria-label", label);
|
|
1338
|
+
}
|
|
1188
1339
|
}
|
|
1189
1340
|
}
|
|
1190
1341
|
focusGrid() {
|
|
@@ -1339,7 +1490,7 @@
|
|
|
1339
1490
|
const minYearAttr = this.min ? ` min="${Number(this.min.slice(0, 4))}"` : "";
|
|
1340
1491
|
const maxYearAttr = this.max ? ` max="${Number(this.max.slice(0, 4))}"` : "";
|
|
1341
1492
|
const showWeeks = this.showWeekNumbers && this.firstDay === 1;
|
|
1342
|
-
const weekHeader = showWeeks ? `<th scope="col" class="dp-week-heading" abbr="${escapeHtml(this.
|
|
1493
|
+
const weekHeader = showWeeks ? `<th scope="col" class="dp-week-heading" abbr="${escapeHtml(this.messages.week)}">#</th>` : "";
|
|
1343
1494
|
const monthOptions = names.map((name, index) => {
|
|
1344
1495
|
const month = index + 1;
|
|
1345
1496
|
const key = `${String(displayYear).padStart(4, "0")}-${String(month).padStart(2, "0")}`;
|
|
@@ -1347,10 +1498,12 @@
|
|
|
1347
1498
|
return `<option value="${String(month).padStart(2, "0")}"${month === displayMonth ? " selected" : ""}${disabled ? " disabled" : ""}>${escapeHtml(name)}</option>`;
|
|
1348
1499
|
}).join("");
|
|
1349
1500
|
const dayHeaders = weekdayShort.map((name, index) => `<th scope="col" abbr="${escapeHtml(weekdayLong[index])}">${escapeHtml(name.replace(".", ""))}</th>`).join("");
|
|
1501
|
+
this._renderedStates.clear();
|
|
1350
1502
|
const rows = weeks.map((week) => {
|
|
1351
1503
|
const weekNumber = showWeeks ? `<th scope="row" class="dp-week-number">${isoWeekNumber(week[0])}</th>` : "";
|
|
1352
1504
|
const cells = week.map((date) => {
|
|
1353
1505
|
const state = this.getDateState(date);
|
|
1506
|
+
this._renderedStates.set(date, state);
|
|
1354
1507
|
const outside = monthKey(date) !== display;
|
|
1355
1508
|
const selected = this.value === date;
|
|
1356
1509
|
const focused = this.focusedDate === date;
|
|
@@ -1365,18 +1518,22 @@
|
|
|
1365
1518
|
const focusKey = focusedElement instanceof HTMLElement && this.contains(focusedElement) ? this._focusTargetKey(focusedElement) : "";
|
|
1366
1519
|
const yearFirst = monthYearOrder(locale)[0] === "year";
|
|
1367
1520
|
this.toggleAttribute("data-year-first", yearFirst);
|
|
1368
|
-
const
|
|
1369
|
-
|
|
1370
|
-
const
|
|
1371
|
-
|
|
1521
|
+
const classes = this.controlClasses;
|
|
1522
|
+
const monthClass = escapeHtml(classes.month || "dp-skin");
|
|
1523
|
+
const yearClass = escapeHtml(classes.year || "dp-skin");
|
|
1524
|
+
const navClass = escapeHtml(classes.nav || "dp-skin");
|
|
1525
|
+
const monthControl = `<label class="dp-visually-hidden" for="${this._id}-month">${escapeHtml(this.messages.month)}</label>
|
|
1526
|
+
<select id="${this._id}-month" class="dp-month-select ${monthClass}" aria-label="${escapeHtml(this.messages.month)}">${monthOptions}</select>`;
|
|
1527
|
+
const yearControl = `<label class="dp-visually-hidden" for="${this._id}-year">${escapeHtml(this.messages.year)}</label>
|
|
1528
|
+
<input id="${this._id}-year" class="dp-year-input ${yearClass}" type="number" inputmode="numeric" value="${displayYear}"${minYearAttr}${maxYearAttr} aria-label="${escapeHtml(this.messages.year)}">`;
|
|
1372
1529
|
this._rendering = true;
|
|
1373
1530
|
this.innerHTML = `
|
|
1374
1531
|
<div class="dp-calendar-shell">
|
|
1375
1532
|
<div class="dp-calendar-header">
|
|
1376
1533
|
${yearFirst ? yearControl : monthControl}
|
|
1377
1534
|
${yearFirst ? monthControl : yearControl}
|
|
1378
|
-
<button type="button" class="dp-nav dp-prev" data-calendar-action="previous" aria-label="${escapeHtml(this.
|
|
1379
|
-
<button type="button" class="dp-nav dp-next" data-calendar-action="next" aria-label="${escapeHtml(this.
|
|
1535
|
+
<button type="button" class="dp-nav dp-prev ${navClass}" 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>
|
|
1536
|
+
<button type="button" class="dp-nav dp-next ${navClass}" 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>
|
|
1380
1537
|
</div>
|
|
1381
1538
|
<h2 id="${headingId}" class="dp-calendar-heading dp-visually-hidden" aria-live="polite">${escapeHtml(formatMonthYear(`${display}-15`, locale))}</h2>
|
|
1382
1539
|
<table id="${gridId}" class="dp-grid" role="grid" aria-labelledby="${headingId}">
|
|
@@ -1406,7 +1563,7 @@
|
|
|
1406
1563
|
const extra = cell.querySelector(".dp-day-extra");
|
|
1407
1564
|
if (!(extra instanceof HTMLElement))
|
|
1408
1565
|
continue;
|
|
1409
|
-
const content = this._renderDay(date, this.
|
|
1566
|
+
const content = this._renderDay(date, this._renderedStates.get(date) || {});
|
|
1410
1567
|
if (content instanceof Node)
|
|
1411
1568
|
extra.append(content);
|
|
1412
1569
|
else if (content !== undefined && content !== null)
|
|
@@ -1422,13 +1579,15 @@
|
|
|
1422
1579
|
function crossAxisFor(side) {
|
|
1423
1580
|
return side === "top" || side === "bottom" ? "x" : "y";
|
|
1424
1581
|
}
|
|
1582
|
+
var OPPOSITE = { top: "bottom", bottom: "top", left: "right", right: "left" };
|
|
1583
|
+
var PLACEMENTS = new Set(Object.keys(OPPOSITE).flatMap((side) => [side, `${side}-start`, `${side}-end`]));
|
|
1584
|
+
var COORDINATE_SPACES = new Set(["viewport", "document"]);
|
|
1425
1585
|
function parsePlacement(placement) {
|
|
1586
|
+
if (!PLACEMENTS.has(placement))
|
|
1587
|
+
throw new TypeError(`Unknown placement: ${placement}`);
|
|
1426
1588
|
const [side, align = null] = placement.split("-");
|
|
1427
1589
|
return { side, align, crossAxis: crossAxisFor(side) };
|
|
1428
1590
|
}
|
|
1429
|
-
function flipSide(side) {
|
|
1430
|
-
return { top: "bottom", bottom: "top", left: "right", right: "left" }[side] || side;
|
|
1431
|
-
}
|
|
1432
1591
|
function computeCoords(reference, floating, side, align, rtl, distance) {
|
|
1433
1592
|
const crossAxis = crossAxisFor(side);
|
|
1434
1593
|
const commonX = reference.x + reference.width / 2 - floating.width / 2;
|
|
@@ -1460,17 +1619,12 @@
|
|
|
1460
1619
|
function overflowOn(position, size, start, end) {
|
|
1461
1620
|
return Math.max(start - position, 0) + Math.max(position + size - end, 0);
|
|
1462
1621
|
}
|
|
1463
|
-
function isRTL(
|
|
1464
|
-
const
|
|
1465
|
-
if (
|
|
1466
|
-
return
|
|
1467
|
-
if (direction === "ltr")
|
|
1468
|
-
return false;
|
|
1469
|
-
const win = element.ownerDocument?.defaultView;
|
|
1470
|
-
if (win?.CSS?.supports?.("selector(:dir(rtl))") && typeof element.matches === "function") {
|
|
1471
|
-
return element.matches(":dir(rtl)");
|
|
1622
|
+
function isRTL(reference) {
|
|
1623
|
+
const win = reference.ownerDocument?.defaultView;
|
|
1624
|
+
if (win && reference instanceof win.Element) {
|
|
1625
|
+
return win.getComputedStyle(reference).direction === "rtl";
|
|
1472
1626
|
}
|
|
1473
|
-
return
|
|
1627
|
+
return "dir" in reference && reference.dir === "rtl";
|
|
1474
1628
|
}
|
|
1475
1629
|
var STABLE_SCROLLBAR_MAX_WIDTH = 25;
|
|
1476
1630
|
function getViewportBoundary(doc) {
|
|
@@ -1508,8 +1662,14 @@
|
|
|
1508
1662
|
const percent = (referenceCenter - boxStart) / size * 100;
|
|
1509
1663
|
return Math.round(Math.min(100, Math.max(0, percent)) * 1000) / 1000;
|
|
1510
1664
|
}
|
|
1511
|
-
function isOutsideBoundary(
|
|
1512
|
-
|
|
1665
|
+
function isOutsideBoundary(rects, boundary) {
|
|
1666
|
+
for (let i = 0;i < rects.length; i++) {
|
|
1667
|
+
const rect = rects[i];
|
|
1668
|
+
if (rect.right >= boundary.x && rect.left <= boundary.right && rect.bottom >= boundary.y && rect.top <= boundary.bottom) {
|
|
1669
|
+
return false;
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
return true;
|
|
1513
1673
|
}
|
|
1514
1674
|
function getAvailableHeight(referenceRect, side, boundary, distance, padding) {
|
|
1515
1675
|
if (side === "top") {
|
|
@@ -1564,10 +1724,22 @@
|
|
|
1564
1724
|
for (const [subscription, type] of notifications) {
|
|
1565
1725
|
if (!subscriptions.has(subscription) || !subscription.floating.isConnected)
|
|
1566
1726
|
continue;
|
|
1567
|
-
|
|
1727
|
+
try {
|
|
1728
|
+
subscription.callback({ type });
|
|
1729
|
+
} catch (error) {
|
|
1730
|
+
reportError(error);
|
|
1731
|
+
}
|
|
1568
1732
|
}
|
|
1569
1733
|
});
|
|
1570
1734
|
}
|
|
1735
|
+
function reportError(error) {
|
|
1736
|
+
if (typeof win.reportError === "function")
|
|
1737
|
+
win.reportError(error);
|
|
1738
|
+
else
|
|
1739
|
+
win.setTimeout(() => {
|
|
1740
|
+
throw error;
|
|
1741
|
+
});
|
|
1742
|
+
}
|
|
1571
1743
|
function notifyAll(type) {
|
|
1572
1744
|
for (const subscription of subscriptions)
|
|
1573
1745
|
queue(subscription, type);
|
|
@@ -1658,28 +1830,32 @@
|
|
|
1658
1830
|
return trackerFor(floating).add(reference, floating, callback);
|
|
1659
1831
|
}
|
|
1660
1832
|
function positionOnce(reference, floating, options) {
|
|
1833
|
+
const placement = options.placement === undefined ? "bottom-start" : options.placement;
|
|
1834
|
+
let { side, align, crossAxis } = parsePlacement(placement);
|
|
1835
|
+
const coordinateSpace = options.coordinateSpace === undefined ? "viewport" : options.coordinateSpace;
|
|
1836
|
+
if (!COORDINATE_SPACES.has(coordinateSpace)) {
|
|
1837
|
+
throw new TypeError(`Unknown coordinateSpace: ${coordinateSpace}`);
|
|
1838
|
+
}
|
|
1661
1839
|
if (!isVisible(floating))
|
|
1662
1840
|
return null;
|
|
1663
|
-
const placement = options.placement || "bottom-start";
|
|
1664
1841
|
const distance = options.distance || 0;
|
|
1665
1842
|
const flip = options.flip !== false;
|
|
1666
1843
|
const shift = options.shift !== false;
|
|
1667
1844
|
const shiftPadding = options.shiftPadding ?? 4;
|
|
1668
|
-
let { side, align, crossAxis } = parsePlacement(placement);
|
|
1669
1845
|
const rtl = align ? isRTL(reference) : false;
|
|
1670
1846
|
const rects = reference.getClientRects();
|
|
1671
|
-
|
|
1672
|
-
if (!referenceRect)
|
|
1847
|
+
if (!rects.length)
|
|
1673
1848
|
return null;
|
|
1849
|
+
const rectFor = (s) => s === "bottom" ? rects[rects.length - 1] : rects[0];
|
|
1674
1850
|
const boundary = getBoundary(reference, options);
|
|
1675
|
-
if (!boundary || isOutsideBoundary(
|
|
1851
|
+
if (!boundary || isOutsideBoundary(rects, boundary))
|
|
1676
1852
|
return null;
|
|
1677
1853
|
const floatingRect = getFloatingSize(floating);
|
|
1678
1854
|
const limits = {
|
|
1679
1855
|
x: { size: floatingRect.width, start: boundary.x, end: boundary.right },
|
|
1680
1856
|
y: { size: floatingRect.height, start: boundary.y, end: boundary.bottom }
|
|
1681
1857
|
};
|
|
1682
|
-
const place = (nextSide, nextAlign) => computeCoords(
|
|
1858
|
+
const place = (nextSide, nextAlign) => computeCoords(rectFor(nextSide), floatingRect, nextSide, nextAlign, rtl, distance);
|
|
1683
1859
|
const overflowAt = (position, axis) => {
|
|
1684
1860
|
const { size, start, end } = limits[axis];
|
|
1685
1861
|
return overflowOn(position, size, start + shiftPadding, end - shiftPadding);
|
|
@@ -1689,31 +1865,30 @@
|
|
|
1689
1865
|
return overflowAt(shift ? clampToBoundary(position, size, start, end, shiftPadding) : position, axis);
|
|
1690
1866
|
};
|
|
1691
1867
|
let coords = place(side, align);
|
|
1868
|
+
const overflowFor = (nextSide, at) => {
|
|
1869
|
+
const cross = crossAxisFor(nextSide);
|
|
1870
|
+
const main = cross === "x" ? "y" : "x";
|
|
1871
|
+
const mainOverflow = overflowAt(at[main], main);
|
|
1872
|
+
return { main: mainOverflow, total: mainOverflow + shiftedOverflowAt(at[cross], cross) };
|
|
1873
|
+
};
|
|
1692
1874
|
if (flip) {
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
const
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
coords = flipped;
|
|
1702
|
-
overflow = flippedOverflow;
|
|
1703
|
-
}
|
|
1704
|
-
}
|
|
1705
|
-
if (mainAxis === "x" && overflow > 0) {
|
|
1706
|
-
const above = place("top", align);
|
|
1707
|
-
const below = place("bottom", align);
|
|
1708
|
-
const useBottom = overflowAt(below.y, "y") < overflowAt(above.y, "y");
|
|
1709
|
-
const candidate = useBottom ? below : above;
|
|
1710
|
-
const swapped = overflowAt(candidate.y, "y") + shiftedOverflowAt(candidate.x, "x");
|
|
1711
|
-
if (swapped < overflow + shiftedOverflowAt(coords.y, "y")) {
|
|
1712
|
-
side = useBottom ? "bottom" : "top";
|
|
1713
|
-
crossAxis = "x";
|
|
1714
|
-
coords = candidate;
|
|
1875
|
+
let best = overflowFor(side, coords);
|
|
1876
|
+
const consider = (nextSide) => {
|
|
1877
|
+
const next = place(nextSide, align);
|
|
1878
|
+
const overflow = overflowFor(nextSide, next);
|
|
1879
|
+
if (overflow.total < best.total) {
|
|
1880
|
+
side = nextSide;
|
|
1881
|
+
coords = next;
|
|
1882
|
+
best = overflow;
|
|
1715
1883
|
}
|
|
1884
|
+
};
|
|
1885
|
+
if (best.main > 0)
|
|
1886
|
+
consider(OPPOSITE[side]);
|
|
1887
|
+
if (crossAxis === "y" && best.main > 0) {
|
|
1888
|
+
consider("top");
|
|
1889
|
+
consider("bottom");
|
|
1716
1890
|
}
|
|
1891
|
+
crossAxis = crossAxisFor(side);
|
|
1717
1892
|
}
|
|
1718
1893
|
if (crossAxis === "x" && shift && align) {
|
|
1719
1894
|
const overflow = overflowAt(coords.x, "x");
|
|
@@ -1730,12 +1905,13 @@
|
|
|
1730
1905
|
const { size, start, end } = limits[crossAxis];
|
|
1731
1906
|
coords[crossAxis] = clampToBoundary(coords[crossAxis], size, start, end, shiftPadding);
|
|
1732
1907
|
}
|
|
1733
|
-
const
|
|
1734
|
-
const
|
|
1735
|
-
const
|
|
1908
|
+
const resolvedRect = rectFor(side);
|
|
1909
|
+
const arrowX = arrowPercent(resolvedRect.x + resolvedRect.width / 2, coords.x, floatingRect.width);
|
|
1910
|
+
const arrowY = arrowPercent(resolvedRect.y + resolvedRect.height / 2, coords.y, floatingRect.height);
|
|
1911
|
+
const availableHeight = `${getAvailableHeight(resolvedRect, side, boundary, distance, shiftPadding)}px`;
|
|
1736
1912
|
const { style } = floating;
|
|
1737
1913
|
const roomChanged = style.getPropertyValue("--available-height") !== availableHeight;
|
|
1738
|
-
const win =
|
|
1914
|
+
const win = coordinateSpace === "document" ? reference.ownerDocument.defaultView : null;
|
|
1739
1915
|
const originX = win ? win.scrollX : 0;
|
|
1740
1916
|
const originY = win ? win.scrollY : 0;
|
|
1741
1917
|
style.left = `${coords.x + originX}px`;
|
|
@@ -1863,7 +2039,7 @@
|
|
|
1863
2039
|
input.setCustomValidity("");
|
|
1864
2040
|
return;
|
|
1865
2041
|
}
|
|
1866
|
-
input.setCustomValidity(
|
|
2042
|
+
input.setCustomValidity(this.messages.invalidDate);
|
|
1867
2043
|
}
|
|
1868
2044
|
async commit(options = {}) {
|
|
1869
2045
|
const input = this.input;
|
|
@@ -1961,6 +2137,18 @@
|
|
|
1961
2137
|
|
|
1962
2138
|
class DatePickerElement extends HTMLElement {
|
|
1963
2139
|
static observedAttributes = ["value", "locale", "min", "max", "open-on-focus", "month-format"];
|
|
2140
|
+
static setDefaultControlClasses(classes) {
|
|
2141
|
+
setDefaultControlClasses(classes);
|
|
2142
|
+
}
|
|
2143
|
+
static getDefaultControlClasses() {
|
|
2144
|
+
return getDefaultControlClasses();
|
|
2145
|
+
}
|
|
2146
|
+
static setDefaultMessages(messages) {
|
|
2147
|
+
setDefaultMessages(messages);
|
|
2148
|
+
}
|
|
2149
|
+
static getDefaultMessages() {
|
|
2150
|
+
return getDefaultMessages();
|
|
2151
|
+
}
|
|
1964
2152
|
constructor() {
|
|
1965
2153
|
super();
|
|
1966
2154
|
this._id = `date-picker-${++uid2}`;
|
|
@@ -1992,7 +2180,9 @@
|
|
|
1992
2180
|
this._stopTracking = null;
|
|
1993
2181
|
this._open = false;
|
|
1994
2182
|
this._suppressFocusOpen = false;
|
|
1995
|
-
this._messages =
|
|
2183
|
+
this._messages = null;
|
|
2184
|
+
this._controlClasses = null;
|
|
2185
|
+
this._stopDefaultMessages = null;
|
|
1996
2186
|
this._source = null;
|
|
1997
2187
|
this._dateState = null;
|
|
1998
2188
|
this._renderDay = null;
|
|
@@ -2005,11 +2195,31 @@
|
|
|
2005
2195
|
connectedCallback() {
|
|
2006
2196
|
if (this._connected)
|
|
2007
2197
|
return;
|
|
2008
|
-
|
|
2198
|
+
upgradeProperties(this, [
|
|
2199
|
+
"locale",
|
|
2200
|
+
"min",
|
|
2201
|
+
"max",
|
|
2202
|
+
"monthFormat",
|
|
2203
|
+
"openOnFocus",
|
|
2204
|
+
"coordinateSpace",
|
|
2205
|
+
"controlClasses",
|
|
2206
|
+
"messages",
|
|
2207
|
+
"source",
|
|
2208
|
+
"dateState",
|
|
2209
|
+
"renderDay",
|
|
2210
|
+
"isDateDisabled"
|
|
2211
|
+
]);
|
|
2212
|
+
if (this.hasAttribute("range"))
|
|
2009
2213
|
this._connectRange();
|
|
2010
|
-
|
|
2214
|
+
else
|
|
2215
|
+
this._connectSingle();
|
|
2216
|
+
if (this._connected) {
|
|
2217
|
+
upgradeProperties(this, ["value", "range"]);
|
|
2218
|
+
this._stopDefaultMessages = subscribeDefaultMessages(() => {
|
|
2219
|
+
if (this._messages === null)
|
|
2220
|
+
this._refreshMessages();
|
|
2221
|
+
});
|
|
2011
2222
|
}
|
|
2012
|
-
this._connectSingle();
|
|
2013
2223
|
}
|
|
2014
2224
|
_connectSingle() {
|
|
2015
2225
|
const input = this.querySelector(":scope > input:not([type=hidden]):not([type=time]):not([data-time-start]):not([data-time-end])");
|
|
@@ -2020,7 +2230,7 @@
|
|
|
2020
2230
|
this._connected = true;
|
|
2021
2231
|
this._input = input;
|
|
2022
2232
|
this._discoverTimeFields();
|
|
2023
|
-
this._field = new DateFieldController(input, { messages: this.
|
|
2233
|
+
this._field = new DateFieldController(input, { messages: this.messages, locale: this.locale });
|
|
2024
2234
|
this._field.onAttributesChanged = () => this._syncInputState();
|
|
2025
2235
|
this._field.confirm = (date, options) => this._confirmDate(date, options);
|
|
2026
2236
|
this._setupFormValue();
|
|
@@ -2035,7 +2245,7 @@
|
|
|
2035
2245
|
else if (!input.value)
|
|
2036
2246
|
this._setValue("", { emit: false, format: false });
|
|
2037
2247
|
else
|
|
2038
|
-
input.setCustomValidity(this.
|
|
2248
|
+
input.setCustomValidity(this.messages.invalidDate);
|
|
2039
2249
|
if (this._field.hidden)
|
|
2040
2250
|
this._field.hidden.defaultValue = this._value;
|
|
2041
2251
|
if (input.getAttribute("value") == null && input.defaultValue === "") {
|
|
@@ -2076,8 +2286,8 @@
|
|
|
2076
2286
|
this._connected = true;
|
|
2077
2287
|
this._input = null;
|
|
2078
2288
|
this._fields = [
|
|
2079
|
-
new DateFieldController(startInput, { messages: this.
|
|
2080
|
-
new DateFieldController(endInput, { messages: this.
|
|
2289
|
+
new DateFieldController(startInput, { messages: this.messages, locale: this.locale }),
|
|
2290
|
+
new DateFieldController(endInput, { messages: this.messages, locale: this.locale })
|
|
2081
2291
|
];
|
|
2082
2292
|
this._range = new DateRangeController;
|
|
2083
2293
|
this._rangeOriginalDescribedBy = [
|
|
@@ -2099,9 +2309,9 @@
|
|
|
2099
2309
|
const initialEnd = isDate(endInput.value) ? endInput.value : adapter.parse(endInput.value);
|
|
2100
2310
|
this._setRange(initialStart || "", initialEnd || "", { emit: false });
|
|
2101
2311
|
if (startInput.value.trim() && !isDate(initialStart))
|
|
2102
|
-
startInput.setCustomValidity(this.
|
|
2312
|
+
startInput.setCustomValidity(this.messages.invalidDate);
|
|
2103
2313
|
if (endInput.value.trim() && !isDate(initialEnd))
|
|
2104
|
-
endInput.setCustomValidity(this.
|
|
2314
|
+
endInput.setCustomValidity(this.messages.invalidDate);
|
|
2105
2315
|
if (this._fields[0].hidden)
|
|
2106
2316
|
this._fields[0].hidden.defaultValue = this._range.start;
|
|
2107
2317
|
if (this._fields[1].hidden)
|
|
@@ -2114,6 +2324,8 @@
|
|
|
2114
2324
|
}
|
|
2115
2325
|
}
|
|
2116
2326
|
disconnectedCallback() {
|
|
2327
|
+
this._stopDefaultMessages?.();
|
|
2328
|
+
this._stopDefaultMessages = null;
|
|
2117
2329
|
this._connected = false;
|
|
2118
2330
|
this.hide(false);
|
|
2119
2331
|
this._controller?.abort();
|
|
@@ -2247,18 +2459,35 @@
|
|
|
2247
2459
|
get open() {
|
|
2248
2460
|
return this._open;
|
|
2249
2461
|
}
|
|
2462
|
+
get controlClasses() {
|
|
2463
|
+
return resolveControlClasses(this._controlClasses);
|
|
2464
|
+
}
|
|
2465
|
+
set controlClasses(value) {
|
|
2466
|
+
this._controlClasses = normalizeControlClasses(value);
|
|
2467
|
+
if (this._calendar)
|
|
2468
|
+
this._calendar.controlClasses = this._controlClasses;
|
|
2469
|
+
}
|
|
2250
2470
|
get messages() {
|
|
2251
|
-
return this._messages;
|
|
2471
|
+
return this._messages ?? getDefaultMessages();
|
|
2252
2472
|
}
|
|
2253
2473
|
set messages(value) {
|
|
2254
|
-
this._messages = { ...getDefaultMessages(), ...value
|
|
2474
|
+
this._messages = value == null ? null : { ...getDefaultMessages(), ...value };
|
|
2255
2475
|
if (this._calendar)
|
|
2256
2476
|
this._calendar.messages = this._messages;
|
|
2477
|
+
this._refreshMessages();
|
|
2478
|
+
}
|
|
2479
|
+
_refreshMessages() {
|
|
2480
|
+
const messages = this.messages;
|
|
2257
2481
|
for (const field of this._fields || [])
|
|
2258
|
-
field.setMessages(
|
|
2259
|
-
this._field?.setMessages(
|
|
2482
|
+
field.setMessages(messages);
|
|
2483
|
+
this._field?.setMessages(messages);
|
|
2484
|
+
this._panel?.setAttribute("aria-label", messages.calendar);
|
|
2485
|
+
const field = this._field ?? this._fields?.[0];
|
|
2486
|
+
if (this._formatHint && field)
|
|
2487
|
+
this._formatHint.textContent = `${messages.formatHint}: ${field.placeholder}`;
|
|
2260
2488
|
this._refreshButtonLabel();
|
|
2261
|
-
this.
|
|
2489
|
+
if (this._connected)
|
|
2490
|
+
this.validate();
|
|
2262
2491
|
}
|
|
2263
2492
|
get source() {
|
|
2264
2493
|
return this._source;
|
|
@@ -2386,7 +2615,7 @@
|
|
|
2386
2615
|
panel.className = "dp-picker-panel";
|
|
2387
2616
|
panel.setAttribute("popover", "manual");
|
|
2388
2617
|
panel.setAttribute("role", "dialog");
|
|
2389
|
-
panel.setAttribute("aria-label", this.
|
|
2618
|
+
panel.setAttribute("aria-label", this.messages.calendar);
|
|
2390
2619
|
const calendar = new DateCalendarElement;
|
|
2391
2620
|
calendar.selection = "none";
|
|
2392
2621
|
calendar.fixedWeeks = true;
|
|
@@ -2410,6 +2639,23 @@
|
|
|
2410
2639
|
this._refreshLocale();
|
|
2411
2640
|
this._refreshButtonLabel();
|
|
2412
2641
|
}
|
|
2642
|
+
_bindPopup(signal, input, restore) {
|
|
2643
|
+
this.ownerDocument.addEventListener("pointerdown", (event) => {
|
|
2644
|
+
if (!this._open || event.composedPath().includes(this))
|
|
2645
|
+
return;
|
|
2646
|
+
this.hide(false);
|
|
2647
|
+
}, { capture: true, signal });
|
|
2648
|
+
this.ownerDocument.addEventListener("reset", (event) => {
|
|
2649
|
+
if (!(event.target instanceof HTMLFormElement) || !input || event.target !== input.form)
|
|
2650
|
+
return;
|
|
2651
|
+
this.hide(false);
|
|
2652
|
+
queueMicrotask(() => {
|
|
2653
|
+
if (!event.defaultPrevented)
|
|
2654
|
+
restore();
|
|
2655
|
+
});
|
|
2656
|
+
}, { capture: true, signal });
|
|
2657
|
+
this.addEventListener("keydown", (event) => this._onEscape(event), { signal });
|
|
2658
|
+
}
|
|
2413
2659
|
_bind() {
|
|
2414
2660
|
const input = this._input;
|
|
2415
2661
|
const button = this._buttons[0]?.button;
|
|
@@ -2472,22 +2718,7 @@
|
|
|
2472
2718
|
});
|
|
2473
2719
|
}, { signal });
|
|
2474
2720
|
calendar.addEventListener("dateloadend", () => void this.validate(), { signal });
|
|
2475
|
-
this.
|
|
2476
|
-
if (!this._open || event.composedPath().includes(this))
|
|
2477
|
-
return;
|
|
2478
|
-
this.hide(false);
|
|
2479
|
-
}, { capture: true, signal });
|
|
2480
|
-
this.ownerDocument.addEventListener("reset", (event) => {
|
|
2481
|
-
const form = event.target;
|
|
2482
|
-
if (form instanceof HTMLFormElement && this._input && form === this._input.form) {
|
|
2483
|
-
this.hide(false);
|
|
2484
|
-
queueMicrotask(() => {
|
|
2485
|
-
if (!event.defaultPrevented)
|
|
2486
|
-
this._restoreDefault();
|
|
2487
|
-
});
|
|
2488
|
-
}
|
|
2489
|
-
}, { capture: true, signal });
|
|
2490
|
-
this.addEventListener("keydown", (event) => this._onEscape(event), { signal });
|
|
2721
|
+
this._bindPopup(signal, this._input, () => this._restoreDefault());
|
|
2491
2722
|
}
|
|
2492
2723
|
_bindRange() {
|
|
2493
2724
|
const calendar = this._calendar;
|
|
@@ -2567,22 +2798,7 @@
|
|
|
2567
2798
|
calendar.addEventListener("pointercancel", (event) => this._onGridPointerCancel(event), { signal });
|
|
2568
2799
|
calendar.addEventListener("lostpointercapture", (event) => this._onGridPointerCancel(event), { signal });
|
|
2569
2800
|
calendar.addEventListener("dateloadend", () => void this.validate(), { signal });
|
|
2570
|
-
this.
|
|
2571
|
-
if (!this._open || event.composedPath().includes(this))
|
|
2572
|
-
return;
|
|
2573
|
-
this.hide(false);
|
|
2574
|
-
}, { capture: true, signal });
|
|
2575
|
-
this.ownerDocument.addEventListener("reset", (event) => {
|
|
2576
|
-
const form = event.target;
|
|
2577
|
-
if (form instanceof HTMLFormElement && this._fields && form === this._fields[0].input.form) {
|
|
2578
|
-
this.hide(false);
|
|
2579
|
-
queueMicrotask(() => {
|
|
2580
|
-
if (!event.defaultPrevented)
|
|
2581
|
-
this._restoreRangeDefault();
|
|
2582
|
-
});
|
|
2583
|
-
}
|
|
2584
|
-
}, { capture: true, signal });
|
|
2585
|
-
this.addEventListener("keydown", (event) => this._onEscape(event), { signal });
|
|
2801
|
+
this._bindPopup(signal, this._fields?.[0]?.input, () => this._restoreRangeDefault());
|
|
2586
2802
|
}
|
|
2587
2803
|
_activateRangeEndpoint(endpoint) {
|
|
2588
2804
|
const calendar = this._calendar;
|
|
@@ -2879,6 +3095,7 @@
|
|
|
2879
3095
|
calendar.min = this.min;
|
|
2880
3096
|
calendar.max = this.max;
|
|
2881
3097
|
calendar.monthFormat = this.monthFormat;
|
|
3098
|
+
calendar.controlClasses = this._controlClasses;
|
|
2882
3099
|
calendar.messages = this._messages;
|
|
2883
3100
|
calendar.source = this._source;
|
|
2884
3101
|
calendar.dateState = this._dateState;
|
|
@@ -2887,7 +3104,7 @@
|
|
|
2887
3104
|
if (!this._rangeMode() && this._value)
|
|
2888
3105
|
calendar.value = this._value;
|
|
2889
3106
|
if (panel)
|
|
2890
|
-
panel.setAttribute("aria-label", this.
|
|
3107
|
+
panel.setAttribute("aria-label", this.messages.calendar);
|
|
2891
3108
|
}
|
|
2892
3109
|
_refreshLocale() {
|
|
2893
3110
|
const hint = this._formatHint;
|
|
@@ -2896,7 +3113,7 @@
|
|
|
2896
3113
|
if (this._rangeMode() && this._fields) {
|
|
2897
3114
|
this._fields[0].setLocale(this.locale);
|
|
2898
3115
|
this._fields[1].setLocale(this.locale);
|
|
2899
|
-
hint.textContent = `${this.
|
|
3116
|
+
hint.textContent = `${this.messages.formatHint}: ${this._fields[0].placeholder}`;
|
|
2900
3117
|
for (const [index, field] of this._fields.entries()) {
|
|
2901
3118
|
if (!field.input.hasAttribute("placeholder") || this._generatedPlaceholder) {
|
|
2902
3119
|
field.input.placeholder = field.placeholder;
|
|
@@ -2913,7 +3130,7 @@
|
|
|
2913
3130
|
if (!field)
|
|
2914
3131
|
return;
|
|
2915
3132
|
field.setLocale(this.locale);
|
|
2916
|
-
hint.textContent = `${this.
|
|
3133
|
+
hint.textContent = `${this.messages.formatHint}: ${field.placeholder}`;
|
|
2917
3134
|
if (!field.input.hasAttribute("placeholder") || this._generatedPlaceholder) {
|
|
2918
3135
|
field.input.placeholder = field.placeholder;
|
|
2919
3136
|
this._generatedPlaceholder = true;
|
|
@@ -2930,7 +3147,7 @@
|
|
|
2930
3147
|
this._refreshRangeButtonLabel();
|
|
2931
3148
|
return;
|
|
2932
3149
|
}
|
|
2933
|
-
const prefix = this._value ? this.
|
|
3150
|
+
const prefix = this._value ? this.messages.changeDate : this.messages.chooseDate;
|
|
2934
3151
|
const suffix = this._value ? `, ${formatLongDate(this._value, this.locale)}` : "";
|
|
2935
3152
|
single.setAttribute("aria-label", `${prefix}${suffix}`);
|
|
2936
3153
|
}
|
|
@@ -2940,9 +3157,9 @@
|
|
|
2940
3157
|
const { start, end } = this._range;
|
|
2941
3158
|
for (const { button, endpoint } of this._buttons) {
|
|
2942
3159
|
const bound = endpoint === "end" ? end : start;
|
|
2943
|
-
const prefix = bound ? this.
|
|
3160
|
+
const prefix = bound ? this.messages.changeDate : this.messages.chooseDate;
|
|
2944
3161
|
const suffix = bound ? `, ${formatLongDate(bound, this.locale)}` : "";
|
|
2945
|
-
const boundLabel = endpoint === "end" ? this.
|
|
3162
|
+
const boundLabel = endpoint === "end" ? this.messages.rangeEnd : this.messages.rangeStart;
|
|
2946
3163
|
button.setAttribute("aria-label", `${prefix}${suffix}, ${boundLabel}`);
|
|
2947
3164
|
}
|
|
2948
3165
|
}
|
|
@@ -2989,7 +3206,7 @@
|
|
|
2989
3206
|
const confirmed = await calendar.ensureDate(date);
|
|
2990
3207
|
const state = calendar.getDateState(date);
|
|
2991
3208
|
if (!confirmed || state.disabled)
|
|
2992
|
-
return { ok: false, message: this.
|
|
3209
|
+
return { ok: false, message: this.messages.unavailableDate };
|
|
2993
3210
|
return { ok: true };
|
|
2994
3211
|
}
|
|
2995
3212
|
async _commitText(emit, options = {}) {
|
|
@@ -3105,7 +3322,7 @@
|
|
|
3105
3322
|
for (const bound of bounds) {
|
|
3106
3323
|
const index = bound === "end" ? 1 : 0;
|
|
3107
3324
|
const input = this._fields[index].input;
|
|
3108
|
-
const message = bound === "end" ? this.
|
|
3325
|
+
const message = bound === "end" ? this.messages.rangeOrderEnd : this.messages.rangeOrderStart;
|
|
3109
3326
|
const shouldHaveOrder = inverted && bound === which;
|
|
3110
3327
|
if (shouldHaveOrder) {
|
|
3111
3328
|
input.setCustomValidity(message);
|
|
@@ -3127,7 +3344,7 @@
|
|
|
3127
3344
|
const input = inputs[index];
|
|
3128
3345
|
if (!input)
|
|
3129
3346
|
continue;
|
|
3130
|
-
const message = bound === "end" ? this.
|
|
3347
|
+
const message = bound === "end" ? this.messages.rangeOrderEnd : this.messages.rangeOrderStart;
|
|
3131
3348
|
const shouldHaveOrder = inverted && bound === which;
|
|
3132
3349
|
if (shouldHaveOrder) {
|
|
3133
3350
|
input.setCustomValidity(message);
|