universal-datetime-picker 2.0.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.
@@ -0,0 +1,867 @@
1
+ 'use strict';
2
+
3
+ var dayjs = require('dayjs');
4
+ var customParseFormat = require('dayjs/plugin/customParseFormat');
5
+ var isSameOrAfter = require('dayjs/plugin/isSameOrAfter');
6
+ var isSameOrBefore = require('dayjs/plugin/isSameOrBefore');
7
+ var localeData = require('dayjs/plugin/localeData');
8
+ var weekday = require('dayjs/plugin/weekday');
9
+
10
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
+
12
+ var dayjs__default = /*#__PURE__*/_interopDefault(dayjs);
13
+ var customParseFormat__default = /*#__PURE__*/_interopDefault(customParseFormat);
14
+ var isSameOrAfter__default = /*#__PURE__*/_interopDefault(isSameOrAfter);
15
+ var isSameOrBefore__default = /*#__PURE__*/_interopDefault(isSameOrBefore);
16
+ var localeData__default = /*#__PURE__*/_interopDefault(localeData);
17
+ var weekday__default = /*#__PURE__*/_interopDefault(weekday);
18
+
19
+ // src/core/types.ts
20
+ var DEFAULT_LABELS = {
21
+ date: "Date",
22
+ time: "Time",
23
+ clear: "Clear",
24
+ close: "Close",
25
+ ok: "OK",
26
+ start: "Start",
27
+ end: "End",
28
+ chooseDate: "Choose date",
29
+ chooseDateRange: "Choose date range",
30
+ chooseMonth: "Choose month",
31
+ chooseYear: "Choose year",
32
+ previousMonth: "Previous month",
33
+ nextMonth: "Next month",
34
+ previousYear: "Previous year",
35
+ nextYear: "Next year",
36
+ selectEnd: "Select end date"
37
+ };
38
+ dayjs__default.default.extend(customParseFormat__default.default);
39
+ dayjs__default.default.extend(isSameOrAfter__default.default);
40
+ dayjs__default.default.extend(isSameOrBefore__default.default);
41
+ dayjs__default.default.extend(localeData__default.default);
42
+ dayjs__default.default.extend(weekday__default.default);
43
+ var DEFAULT_FORMAT = "YYYY-MM-DD HH:mm:ss";
44
+ var DATE_FORMAT = "YYYY-MM-DD";
45
+ var TIME_FORMAT = "HH:mm:ss";
46
+ function resolveFormat(options) {
47
+ if (options.format) {
48
+ return options.format;
49
+ }
50
+ const mode = options.mode ?? "datetime";
51
+ const showSeconds = options.showSeconds !== false;
52
+ const use12Hours = Boolean(options.use12Hours);
53
+ const timePart = use12Hours ? showSeconds ? "hh:mm:ss A" : "hh:mm A" : showSeconds ? "HH:mm:ss" : "HH:mm";
54
+ if (mode === "date") {
55
+ return DATE_FORMAT;
56
+ }
57
+ if (mode === "time") {
58
+ return timePart;
59
+ }
60
+ return `${DATE_FORMAT} ${timePart}`;
61
+ }
62
+ function buildTimeValue(value, format) {
63
+ const hour24 = value.hour();
64
+ const { hour, isAm } = to12Hour(hour24);
65
+ return {
66
+ hour,
67
+ hour24,
68
+ minute: value.minute(),
69
+ second: value.second(),
70
+ ampm: isAm ? "AM" : "PM",
71
+ formatted: value.format(format)
72
+ };
73
+ }
74
+ var asStringDeprecationWarned = false;
75
+ function warnAsStringDeprecation() {
76
+ if (asStringDeprecationWarned) {
77
+ return;
78
+ }
79
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
80
+ return;
81
+ }
82
+ asStringDeprecationWarned = true;
83
+ console.warn(
84
+ "[universal-datetime-picker] Omitting `asString` currently returns a formatted string. Set `asString={true}` to keep strings, or `asString={false}` to receive a Date / TimeValue. A future major release will default to Date / TimeValue."
85
+ );
86
+ }
87
+ function parseValue(value, format = DEFAULT_FORMAT) {
88
+ if (value === void 0 || value === null || value === "") {
89
+ return null;
90
+ }
91
+ if (dayjs__default.default.isDayjs(value)) {
92
+ return value.isValid() ? value : null;
93
+ }
94
+ if (value instanceof Date) {
95
+ const parsed2 = dayjs__default.default(value);
96
+ return parsed2.isValid() ? parsed2 : null;
97
+ }
98
+ if (typeof value === "string") {
99
+ const parsed2 = dayjs__default.default(value, format, true);
100
+ if (parsed2.isValid()) {
101
+ return parsed2;
102
+ }
103
+ const fallback = dayjs__default.default(value);
104
+ return fallback.isValid() ? fallback : null;
105
+ }
106
+ const parsed = dayjs__default.default(value);
107
+ return parsed.isValid() ? parsed : null;
108
+ }
109
+ function formatValue(value, format = DEFAULT_FORMAT) {
110
+ if (!value || !value.isValid()) {
111
+ return null;
112
+ }
113
+ return value.format(format);
114
+ }
115
+ function pad2(n) {
116
+ return String(n).padStart(2, "0");
117
+ }
118
+ var HOURS_24 = Array.from({ length: 24 }, (_, i) => pad2(i));
119
+ var HOURS_12 = Array.from(
120
+ { length: 12 },
121
+ (_, i) => pad2(i === 0 ? 12 : i)
122
+ );
123
+ var MINUTES = Array.from({ length: 60 }, (_, i) => pad2(i));
124
+ function to12Hour(hour24) {
125
+ const isAm = hour24 < 12;
126
+ const hour = hour24 % 12 === 0 ? 12 : hour24 % 12;
127
+ return { hour, isAm };
128
+ }
129
+ function to24Hour(hour12, isAm) {
130
+ if (hour12 === 12) {
131
+ return isAm ? 0 : 12;
132
+ }
133
+ return isAm ? hour12 : hour12 + 12;
134
+ }
135
+ function formatLocalized(date, template, locale) {
136
+ return date.locale(locale).format(template);
137
+ }
138
+ function getWeekdayLabels(locale, weekStartsOn) {
139
+ const labels = dayjs__default.default().locale(locale).localeData().weekdaysMin();
140
+ return [...labels.slice(weekStartsOn), ...labels.slice(0, weekStartsOn)];
141
+ }
142
+ function startOfWeek(date, weekStartsOn) {
143
+ const day = date.day();
144
+ const diff = (day - weekStartsOn + 7) % 7;
145
+ return date.subtract(diff, "day").startOf("day");
146
+ }
147
+ function endOfWeek(date, weekStartsOn) {
148
+ return startOfWeek(date, weekStartsOn).add(6, "day").endOf("day");
149
+ }
150
+
151
+ // src/core/logic/calendar.ts
152
+ function isDisabledDay(date, options) {
153
+ const today = dayjs__default.default().startOf("day");
154
+ const day = date.startOf("day");
155
+ if (options.disablePastDates && day.isBefore(today, "day")) {
156
+ return true;
157
+ }
158
+ if (options.disableFutureDates && day.isAfter(today, "day")) {
159
+ return true;
160
+ }
161
+ const min = parseValue(options.minDate ?? null);
162
+ const max = parseValue(options.maxDate ?? null);
163
+ if (min && day.isBefore(min.startOf("day"), "day")) {
164
+ return true;
165
+ }
166
+ if (max && day.isAfter(max.startOf("day"), "day")) {
167
+ return true;
168
+ }
169
+ return false;
170
+ }
171
+ function buildCalendarMonth(options) {
172
+ const weekStartsOn = options.weekStartsOn ?? 0;
173
+ const monthStart = options.viewMonth.startOf("month");
174
+ const monthEnd = options.viewMonth.endOf("month");
175
+ const gridStart = startOfWeek(monthStart, weekStartsOn);
176
+ const gridEnd = endOfWeek(monthEnd, weekStartsOn);
177
+ const weeks = [];
178
+ let cursor = gridStart.clone();
179
+ while (cursor.isBefore(gridEnd) || cursor.isSame(gridEnd, "day")) {
180
+ const week = [];
181
+ for (let i = 0; i < 7; i += 1) {
182
+ const date = cursor.clone();
183
+ const isCurrentMonth = date.isSame(options.viewMonth, "month");
184
+ const isSelected = Boolean(
185
+ options.selected && date.isSame(options.selected, "day")
186
+ );
187
+ const isRangeStart = Boolean(
188
+ options.rangeStart && date.isSame(options.rangeStart, "day")
189
+ );
190
+ const isRangeEnd = Boolean(
191
+ options.rangeEnd && date.isSame(options.rangeEnd, "day")
192
+ );
193
+ const effectiveEnd = options.rangeEnd ?? options.hoverEnd ?? null;
194
+ let isInRange = false;
195
+ if (options.rangeStart && effectiveEnd) {
196
+ const rangeLow = options.rangeStart.isBefore(effectiveEnd, "day") ? options.rangeStart : effectiveEnd;
197
+ const rangeHigh = options.rangeStart.isBefore(effectiveEnd, "day") ? effectiveEnd : options.rangeStart;
198
+ isInRange = date.isAfter(rangeLow, "day") && date.isBefore(rangeHigh, "day") || date.isSame(rangeLow, "day") || date.isSame(rangeHigh, "day");
199
+ }
200
+ week.push({
201
+ date,
202
+ isCurrentMonth,
203
+ isCurrentDate: date.isSame(dayjs__default.default(), "day"),
204
+ isFuture: date.isAfter(dayjs__default.default(), "day"),
205
+ isPast: date.isBefore(dayjs__default.default(), "day"),
206
+ isWeekend: date.day() === 0 || date.day() === 6,
207
+ isDisabled: isDisabledDay(date, options),
208
+ isSelected,
209
+ isInRange,
210
+ isRangeStart,
211
+ isRangeEnd
212
+ });
213
+ cursor = cursor.add(1, "day");
214
+ }
215
+ weeks.push(week);
216
+ }
217
+ return weeks;
218
+ }
219
+
220
+ // src/core/controller.ts
221
+ function padDisplay(n) {
222
+ return String(n).padStart(2, "0");
223
+ }
224
+ var PickerController = class {
225
+ constructor(options = {}) {
226
+ this.listeners = /* @__PURE__ */ new Set();
227
+ this.calPanel = "day";
228
+ this.showHours = false;
229
+ this.showMinutes = false;
230
+ this.showSecondsOpen = false;
231
+ this.showAmPm = false;
232
+ this.subscribe = (listener) => {
233
+ this.listeners.add(listener);
234
+ return () => {
235
+ this.listeners.delete(listener);
236
+ };
237
+ };
238
+ this.getSnapshot = () => this.snapshot;
239
+ /** Stable for useSyncExternalStore — returns same reference until mutate. */
240
+ this.getServerSnapshot = () => this.snapshot;
241
+ this.options = { ...options };
242
+ const mode = options.mode ?? "datetime";
243
+ const showSeconds = options.showSeconds !== false;
244
+ const use12Hours = Boolean(options.use12Hours);
245
+ const format = resolveFormat({
246
+ mode,
247
+ format: options.format,
248
+ use12Hours,
249
+ showSeconds
250
+ });
251
+ const initial = parseValue(options.value ?? options.defaultValue ?? dayjs__default.default(), format) ?? dayjs__default.default();
252
+ this.draft = initial;
253
+ this.viewMonth = initial.startOf("month");
254
+ this.focusedDay = initial;
255
+ this.tab = mode === "time" ? "time" : "date";
256
+ this.open = options.open ?? (options.inline ? true : options.defaultOpen ?? true);
257
+ this.snapshot = this.buildSnapshot();
258
+ }
259
+ setOptions(partial) {
260
+ const prev = this.options;
261
+ this.options = { ...this.options, ...partial };
262
+ if (partial.mode !== void 0 && partial.mode !== prev.mode) {
263
+ this.tab = partial.mode === "time" ? "time" : "date";
264
+ }
265
+ if (partial.open !== void 0) {
266
+ this.open = partial.open;
267
+ }
268
+ if ("value" in partial) {
269
+ if (partial.value === null) {
270
+ const fallback = dayjs__default.default();
271
+ this.draft = fallback;
272
+ this.viewMonth = fallback.startOf("month");
273
+ this.focusedDay = fallback;
274
+ } else if (partial.value !== void 0) {
275
+ const format = this.getResolvedFormat();
276
+ const parsed = parseValue(partial.value, format);
277
+ if (parsed) {
278
+ this.draft = parsed;
279
+ this.viewMonth = parsed.startOf("month");
280
+ this.focusedDay = parsed;
281
+ }
282
+ }
283
+ }
284
+ this.emit();
285
+ }
286
+ getResolvedFormat() {
287
+ return resolveFormat({
288
+ mode: this.options.mode ?? "datetime",
289
+ format: this.options.format,
290
+ use12Hours: Boolean(this.options.use12Hours),
291
+ showSeconds: this.options.showSeconds !== false
292
+ });
293
+ }
294
+ getLabels() {
295
+ return { ...DEFAULT_LABELS, ...this.options.labels };
296
+ }
297
+ emit() {
298
+ this.snapshot = this.buildSnapshot();
299
+ this.listeners.forEach((l) => l());
300
+ }
301
+ buildSnapshot() {
302
+ const mode = this.options.mode ?? "datetime";
303
+ const layout = this.options.layout ?? "combined";
304
+ const showSeconds = this.options.showSeconds !== false;
305
+ const use12Hours = Boolean(this.options.use12Hours);
306
+ const inline = Boolean(this.options.inline);
307
+ const popover = Boolean(this.options.popover);
308
+ const weekStartsOn = this.options.weekStartsOn ?? 0;
309
+ const locale = this.options.locale ?? "en";
310
+ const resolvedFormat = this.getResolvedFormat();
311
+ const labels = this.getLabels();
312
+ const weeks = buildCalendarMonth({
313
+ viewMonth: this.viewMonth,
314
+ selected: this.draft,
315
+ minDate: this.options.minDate,
316
+ maxDate: this.options.maxDate,
317
+ disablePastDates: this.options.disablePastDates,
318
+ disableFutureDates: this.options.disableFutureDates,
319
+ weekStartsOn
320
+ });
321
+ const showDate = mode !== "time";
322
+ const showTime = mode !== "date";
323
+ const useTabs = mode === "datetime" && layout === "tabs";
324
+ const showDatePanel = showDate && (!useTabs || this.tab === "date");
325
+ const showTimePanel = showTime && (!useTabs || this.tab === "time");
326
+ const hour24 = this.draft.hour();
327
+ const { hour: hour12, isAm } = to12Hour(hour24);
328
+ return {
329
+ draft: this.draft,
330
+ viewMonth: this.viewMonth,
331
+ calPanel: this.calPanel,
332
+ tab: this.tab,
333
+ showHours: this.showHours,
334
+ showMinutes: this.showMinutes,
335
+ showSecondsOpen: this.showSecondsOpen,
336
+ showAmPm: this.showAmPm,
337
+ focusedDay: this.focusedDay,
338
+ open: this.open,
339
+ mode,
340
+ layout,
341
+ showSeconds,
342
+ use12Hours,
343
+ inline,
344
+ popover,
345
+ weekStartsOn,
346
+ locale,
347
+ labels,
348
+ resolvedFormat,
349
+ asString: this.options.asString,
350
+ className: this.options.className,
351
+ theme: this.options.theme,
352
+ weeks,
353
+ weekdayLabels: getWeekdayLabels(locale, weekStartsOn),
354
+ showDate,
355
+ showTime,
356
+ useTabs,
357
+ showDatePanel,
358
+ showTimePanel,
359
+ showModeTabs: useTabs,
360
+ hour24,
361
+ hour12,
362
+ isAm,
363
+ hourOptions: use12Hours ? HOURS_12 : HOURS_24,
364
+ displayHour: use12Hours ? padDisplay(hour12) : padDisplay(hour24),
365
+ displayMinute: padDisplay(this.draft.minute()),
366
+ displaySecond: padDisplay(this.draft.second()),
367
+ minuteOptions: MINUTES
368
+ };
369
+ }
370
+ setOpen(open) {
371
+ if (this.options.inline) {
372
+ return;
373
+ }
374
+ this.open = open;
375
+ this.options.onOpenChange?.(open);
376
+ this.emit();
377
+ }
378
+ close() {
379
+ if (!this.options.inline) {
380
+ this.setOpen(false);
381
+ }
382
+ }
383
+ setTab(tab) {
384
+ this.tab = tab;
385
+ this.emit();
386
+ }
387
+ setCalPanel(panel) {
388
+ this.calPanel = panel;
389
+ this.emit();
390
+ }
391
+ setViewMonth(next) {
392
+ this.viewMonth = typeof next === "function" ? next(this.viewMonth) : next;
393
+ this.emit();
394
+ }
395
+ selectDay(day) {
396
+ this.draft = this.draft.year(day.year()).month(day.month()).date(day.date());
397
+ this.focusedDay = day;
398
+ this.emit();
399
+ }
400
+ setHour(hourValue) {
401
+ this.draft = this.draft.hour(hourValue);
402
+ this.emit();
403
+ }
404
+ setMinute(minute) {
405
+ this.draft = this.draft.minute(minute);
406
+ this.emit();
407
+ }
408
+ setSecond(second) {
409
+ this.draft = this.draft.second(second);
410
+ this.emit();
411
+ }
412
+ setAmPm(isAm) {
413
+ const { hour } = to12Hour(this.draft.hour());
414
+ this.draft = this.draft.hour(to24Hour(hour, isAm));
415
+ this.emit();
416
+ }
417
+ toggleHours() {
418
+ this.showHours = !this.showHours;
419
+ this.showMinutes = false;
420
+ this.showSecondsOpen = false;
421
+ this.showAmPm = false;
422
+ this.emit();
423
+ }
424
+ toggleMinutes() {
425
+ this.showMinutes = !this.showMinutes;
426
+ this.showHours = false;
427
+ this.showSecondsOpen = false;
428
+ this.showAmPm = false;
429
+ this.emit();
430
+ }
431
+ toggleSeconds() {
432
+ this.showSecondsOpen = !this.showSecondsOpen;
433
+ this.showHours = false;
434
+ this.showMinutes = false;
435
+ this.showAmPm = false;
436
+ this.emit();
437
+ }
438
+ toggleAmPm() {
439
+ this.showAmPm = !this.showAmPm;
440
+ this.showHours = false;
441
+ this.showMinutes = false;
442
+ this.showSecondsOpen = false;
443
+ this.emit();
444
+ }
445
+ closeTimeColumns() {
446
+ this.showHours = false;
447
+ this.showMinutes = false;
448
+ this.showSecondsOpen = false;
449
+ this.showAmPm = false;
450
+ this.emit();
451
+ }
452
+ selectHourOption(opt) {
453
+ const snap = this.snapshot;
454
+ if (snap.use12Hours) {
455
+ this.draft = this.draft.hour(to24Hour(Number(opt), snap.isAm));
456
+ } else {
457
+ this.draft = this.draft.hour(Number(opt));
458
+ }
459
+ this.showHours = false;
460
+ this.emit();
461
+ }
462
+ selectMinuteOption(opt) {
463
+ this.draft = this.draft.minute(Number(opt));
464
+ this.showMinutes = false;
465
+ this.emit();
466
+ }
467
+ selectSecondOption(opt) {
468
+ this.draft = this.draft.second(Number(opt));
469
+ this.showSecondsOpen = false;
470
+ this.emit();
471
+ }
472
+ selectAmPmOption(opt) {
473
+ const { hour } = to12Hour(this.draft.hour());
474
+ this.draft = this.draft.hour(to24Hour(hour, opt === "AM"));
475
+ this.showAmPm = false;
476
+ this.emit();
477
+ }
478
+ handleGridKeyDown(key) {
479
+ const snap = this.snapshot;
480
+ let next = this.focusedDay;
481
+ switch (key) {
482
+ case "ArrowLeft":
483
+ next = this.focusedDay.subtract(1, "day");
484
+ break;
485
+ case "ArrowRight":
486
+ next = this.focusedDay.add(1, "day");
487
+ break;
488
+ case "ArrowUp":
489
+ next = this.focusedDay.subtract(7, "day");
490
+ break;
491
+ case "ArrowDown":
492
+ next = this.focusedDay.add(7, "day");
493
+ break;
494
+ case "Home":
495
+ next = startOfWeek(this.focusedDay, snap.weekStartsOn);
496
+ break;
497
+ case "End":
498
+ next = endOfWeek(this.focusedDay, snap.weekStartsOn);
499
+ break;
500
+ case "PageUp":
501
+ next = this.focusedDay.subtract(1, "month");
502
+ this.viewMonth = next.startOf("month");
503
+ break;
504
+ case "PageDown":
505
+ next = this.focusedDay.add(1, "month");
506
+ this.viewMonth = next.startOf("month");
507
+ break;
508
+ case "Enter":
509
+ case " ": {
510
+ const cell = snap.weeks.flat().find((d) => d.date.isSame(this.focusedDay, "day"));
511
+ if (cell && !cell.isDisabled && cell.isCurrentMonth) {
512
+ this.selectDay(cell.date);
513
+ }
514
+ return true;
515
+ }
516
+ default:
517
+ return false;
518
+ }
519
+ this.focusedDay = next;
520
+ if (!next.isSame(this.viewMonth, "month")) {
521
+ this.viewMonth = next.startOf("month");
522
+ }
523
+ this.emit();
524
+ return true;
525
+ }
526
+ confirm() {
527
+ const snap = this.snapshot;
528
+ let payload;
529
+ if (snap.asString === false) {
530
+ if (snap.mode === "time") {
531
+ payload = buildTimeValue(this.draft, snap.resolvedFormat);
532
+ } else if (snap.mode === "date") {
533
+ payload = this.draft.startOf("day").toDate();
534
+ } else {
535
+ payload = this.draft.toDate();
536
+ }
537
+ } else {
538
+ if (snap.asString === void 0) {
539
+ warnAsStringDeprecation();
540
+ }
541
+ payload = formatValue(this.draft, snap.resolvedFormat);
542
+ }
543
+ this.options.onChange?.(payload);
544
+ this.close();
545
+ return payload;
546
+ }
547
+ clear() {
548
+ this.options.onChange?.(null);
549
+ this.close();
550
+ }
551
+ /** Year window helpers for month/year panels */
552
+ yearWindowStart(year) {
553
+ return Math.floor(year / 12) * 12;
554
+ }
555
+ navigatePrev() {
556
+ if (this.calPanel === "day") {
557
+ this.viewMonth = this.viewMonth.subtract(1, "month");
558
+ } else if (this.calPanel === "month") {
559
+ this.viewMonth = this.viewMonth.subtract(1, "year");
560
+ } else {
561
+ this.viewMonth = this.viewMonth.subtract(12, "year");
562
+ }
563
+ this.emit();
564
+ }
565
+ navigateNext() {
566
+ if (this.calPanel === "day") {
567
+ this.viewMonth = this.viewMonth.add(1, "month");
568
+ } else if (this.calPanel === "month") {
569
+ this.viewMonth = this.viewMonth.add(1, "year");
570
+ } else {
571
+ this.viewMonth = this.viewMonth.add(12, "year");
572
+ }
573
+ this.emit();
574
+ }
575
+ selectMonth(monthIndex) {
576
+ this.viewMonth = this.viewMonth.month(monthIndex);
577
+ this.calPanel = "day";
578
+ this.emit();
579
+ }
580
+ selectYear(year) {
581
+ this.viewMonth = this.viewMonth.year(year);
582
+ this.calPanel = "month";
583
+ this.emit();
584
+ }
585
+ };
586
+
587
+ // src/core/rangeController.ts
588
+ var RangeController = class {
589
+ constructor(options = {}) {
590
+ this.listeners = /* @__PURE__ */ new Set();
591
+ this.hoverEnd = null;
592
+ this.calPanel = "day";
593
+ this.subscribe = (listener) => {
594
+ this.listeners.add(listener);
595
+ return () => {
596
+ this.listeners.delete(listener);
597
+ };
598
+ };
599
+ this.getSnapshot = () => this.snapshot;
600
+ this.getServerSnapshot = () => this.snapshot;
601
+ this.options = { ...options };
602
+ const format = options.format ?? DATE_FORMAT;
603
+ const parsed = this.parseRange(options.value ?? options.defaultValue, format);
604
+ this.start = parsed.start;
605
+ this.end = parsed.end;
606
+ this.viewMonth = (parsed.start ?? dayjs__default.default()).startOf("month");
607
+ this.focusedDay = parsed.start ?? dayjs__default.default();
608
+ this.open = options.open ?? (options.inline ? true : options.defaultOpen ?? true);
609
+ this.snapshot = this.buildSnapshot();
610
+ }
611
+ parseRange(range, format) {
612
+ return {
613
+ start: parseValue(range?.start ?? null, format),
614
+ end: parseValue(range?.end ?? null, format)
615
+ };
616
+ }
617
+ setOptions(partial) {
618
+ this.options = { ...this.options, ...partial };
619
+ if (partial.open !== void 0) {
620
+ this.open = partial.open;
621
+ }
622
+ if ("value" in partial) {
623
+ if (partial.value === null) {
624
+ this.start = null;
625
+ this.end = null;
626
+ this.hoverEnd = null;
627
+ } else if (partial.value !== void 0) {
628
+ const format = this.options.format ?? DATE_FORMAT;
629
+ const parsed = this.parseRange(partial.value, format);
630
+ this.start = parsed.start;
631
+ this.end = parsed.end;
632
+ if (parsed.start) {
633
+ this.viewMonth = parsed.start.startOf("month");
634
+ this.focusedDay = parsed.start;
635
+ }
636
+ }
637
+ }
638
+ this.emit();
639
+ }
640
+ getLabels() {
641
+ return { ...DEFAULT_LABELS, ...this.options.labels };
642
+ }
643
+ emit() {
644
+ this.snapshot = this.buildSnapshot();
645
+ this.listeners.forEach((l) => l());
646
+ }
647
+ buildSnapshot() {
648
+ const format = this.options.format ?? DATE_FORMAT;
649
+ const weekStartsOn = this.options.weekStartsOn ?? 0;
650
+ const locale = this.options.locale ?? "en";
651
+ const weeks = buildCalendarMonth({
652
+ viewMonth: this.viewMonth,
653
+ rangeStart: this.start,
654
+ rangeEnd: this.end,
655
+ hoverEnd: this.start && !this.end ? this.hoverEnd : null,
656
+ minDate: this.options.minDate,
657
+ maxDate: this.options.maxDate,
658
+ disablePastDates: this.options.disablePastDates,
659
+ disableFutureDates: this.options.disableFutureDates,
660
+ weekStartsOn
661
+ });
662
+ return {
663
+ start: this.start,
664
+ end: this.end,
665
+ hoverEnd: this.hoverEnd,
666
+ viewMonth: this.viewMonth,
667
+ focusedDay: this.focusedDay,
668
+ calPanel: this.calPanel,
669
+ open: this.open,
670
+ inline: Boolean(this.options.inline),
671
+ format,
672
+ asString: this.options.asString,
673
+ weekStartsOn,
674
+ locale,
675
+ labels: this.getLabels(),
676
+ className: this.options.className,
677
+ weeks,
678
+ weekdayLabels: getWeekdayLabels(locale, weekStartsOn)
679
+ };
680
+ }
681
+ setOpen(open) {
682
+ if (this.options.inline) {
683
+ return;
684
+ }
685
+ this.open = open;
686
+ this.options.onOpenChange?.(open);
687
+ this.emit();
688
+ }
689
+ close() {
690
+ if (!this.options.inline) {
691
+ this.setOpen(false);
692
+ }
693
+ }
694
+ setCalPanel(panel) {
695
+ this.calPanel = panel;
696
+ this.emit();
697
+ }
698
+ setViewMonth(next) {
699
+ this.viewMonth = typeof next === "function" ? next(this.viewMonth) : next;
700
+ this.emit();
701
+ }
702
+ navigatePrev() {
703
+ if (this.calPanel === "day") {
704
+ this.viewMonth = this.viewMonth.subtract(1, "month");
705
+ } else if (this.calPanel === "month") {
706
+ this.viewMonth = this.viewMonth.subtract(1, "year");
707
+ } else {
708
+ this.viewMonth = this.viewMonth.subtract(12, "year");
709
+ }
710
+ this.emit();
711
+ }
712
+ navigateNext() {
713
+ if (this.calPanel === "day") {
714
+ this.viewMonth = this.viewMonth.add(1, "month");
715
+ } else if (this.calPanel === "month") {
716
+ this.viewMonth = this.viewMonth.add(1, "year");
717
+ } else {
718
+ this.viewMonth = this.viewMonth.add(12, "year");
719
+ }
720
+ this.emit();
721
+ }
722
+ selectMonth(monthIndex) {
723
+ this.viewMonth = this.viewMonth.month(monthIndex);
724
+ this.calPanel = "day";
725
+ this.emit();
726
+ }
727
+ selectYear(year) {
728
+ this.viewMonth = this.viewMonth.year(year);
729
+ this.calPanel = "month";
730
+ this.emit();
731
+ }
732
+ emitRange(nextStart, nextEnd) {
733
+ if (this.options.asString === false) {
734
+ this.options.onChange?.({
735
+ start: nextStart ? nextStart.toDate() : null,
736
+ end: nextEnd ? nextEnd.toDate() : null
737
+ });
738
+ } else {
739
+ if (this.options.asString === void 0) {
740
+ warnAsStringDeprecation();
741
+ }
742
+ const format = this.options.format ?? DATE_FORMAT;
743
+ this.options.onChange?.({
744
+ start: formatValue(nextStart, format),
745
+ end: formatValue(nextEnd, format)
746
+ });
747
+ }
748
+ }
749
+ pickDay(day) {
750
+ if (!this.start || this.start && this.end) {
751
+ this.start = day;
752
+ this.end = null;
753
+ this.hoverEnd = null;
754
+ this.focusedDay = day;
755
+ } else if (day.isBefore(this.start, "day")) {
756
+ this.start = day;
757
+ this.end = null;
758
+ this.hoverEnd = null;
759
+ this.focusedDay = day;
760
+ } else {
761
+ this.end = day;
762
+ this.hoverEnd = null;
763
+ this.focusedDay = day;
764
+ }
765
+ this.emit();
766
+ }
767
+ setHoverEnd(day) {
768
+ if (this.start && !this.end) {
769
+ this.hoverEnd = day;
770
+ this.emit();
771
+ }
772
+ }
773
+ handleGridKeyDown(key) {
774
+ const snap = this.snapshot;
775
+ let next = this.focusedDay;
776
+ switch (key) {
777
+ case "ArrowLeft":
778
+ next = this.focusedDay.subtract(1, "day");
779
+ break;
780
+ case "ArrowRight":
781
+ next = this.focusedDay.add(1, "day");
782
+ break;
783
+ case "ArrowUp":
784
+ next = this.focusedDay.subtract(7, "day");
785
+ break;
786
+ case "ArrowDown":
787
+ next = this.focusedDay.add(7, "day");
788
+ break;
789
+ case "Home":
790
+ next = startOfWeek(this.focusedDay, snap.weekStartsOn);
791
+ break;
792
+ case "End":
793
+ next = endOfWeek(this.focusedDay, snap.weekStartsOn);
794
+ break;
795
+ case "PageUp":
796
+ next = this.focusedDay.subtract(1, "month");
797
+ this.viewMonth = next.startOf("month");
798
+ break;
799
+ case "PageDown":
800
+ next = this.focusedDay.add(1, "month");
801
+ this.viewMonth = next.startOf("month");
802
+ break;
803
+ case "Enter":
804
+ case " ": {
805
+ const cell = snap.weeks.flat().find((d) => d.date.isSame(this.focusedDay, "day"));
806
+ if (cell && !cell.isDisabled && cell.isCurrentMonth) {
807
+ this.pickDay(cell.date);
808
+ }
809
+ return true;
810
+ }
811
+ default:
812
+ return false;
813
+ }
814
+ this.focusedDay = next;
815
+ if (!next.isSame(this.viewMonth, "month")) {
816
+ this.viewMonth = next.startOf("month");
817
+ }
818
+ this.emit();
819
+ return true;
820
+ }
821
+ confirm() {
822
+ if (!this.start || !this.end) {
823
+ return null;
824
+ }
825
+ this.emitRange(this.start, this.end);
826
+ this.close();
827
+ return {
828
+ start: this.start.toDate(),
829
+ end: this.end.toDate()
830
+ };
831
+ }
832
+ clear() {
833
+ this.start = null;
834
+ this.end = null;
835
+ this.hoverEnd = null;
836
+ this.emitRange(null, null);
837
+ this.emit();
838
+ this.close();
839
+ }
840
+ };
841
+
842
+ Object.defineProperty(exports, "dayjs", {
843
+ enumerable: true,
844
+ get: function () { return dayjs__default.default; }
845
+ });
846
+ exports.DATE_FORMAT = DATE_FORMAT;
847
+ exports.DEFAULT_FORMAT = DEFAULT_FORMAT;
848
+ exports.DEFAULT_LABELS = DEFAULT_LABELS;
849
+ exports.HOURS_12 = HOURS_12;
850
+ exports.HOURS_24 = HOURS_24;
851
+ exports.MINUTES = MINUTES;
852
+ exports.PickerController = PickerController;
853
+ exports.RangeController = RangeController;
854
+ exports.TIME_FORMAT = TIME_FORMAT;
855
+ exports.buildCalendarMonth = buildCalendarMonth;
856
+ exports.buildTimeValue = buildTimeValue;
857
+ exports.endOfWeek = endOfWeek;
858
+ exports.formatLocalized = formatLocalized;
859
+ exports.formatValue = formatValue;
860
+ exports.getWeekdayLabels = getWeekdayLabels;
861
+ exports.pad2 = pad2;
862
+ exports.parseValue = parseValue;
863
+ exports.resolveFormat = resolveFormat;
864
+ exports.startOfWeek = startOfWeek;
865
+ exports.to12Hour = to12Hour;
866
+ exports.to24Hour = to24Hour;
867
+ exports.warnAsStringDeprecation = warnAsStringDeprecation;