@nepdatejs/datepicker 0.0.0-bootstrap → 0.1.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/dist/index.cjs ADDED
@@ -0,0 +1,1325 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let _nepdatejs_core = require("@nepdatejs/core");
3
+ let _nepdatejs_calendar = require("@nepdatejs/calendar");
4
+ //#region src/mask.ts
5
+ const DIGIT = "[0-9०-९]";
6
+ const DIGITS_ONLY = new RegExp(`^${DIGIT}{1,8}$`);
7
+ const YEAR_MONTH = new RegExp(`^(${DIGIT}{4}-${DIGIT}{2})(${DIGIT}?)$`);
8
+ /**
9
+ * Add the dashes of YYYY-MM-DD while the user types digits: "2083" becomes
10
+ * "2083-", "208306" becomes "2083-06-" and a pasted "20830624" becomes
11
+ * "2083-06-24". ASCII and Devanagari digits keep their script, and a
12
+ * separator typed straight after a dash is dropped, so typing the dashes
13
+ * yourself works too. Only text that grew at the end (typing, or a paste into
14
+ * an empty field) is touched: deleting, editing in the middle and other
15
+ * separators ("2083/6/4") are left as the user wrote them. Pure.
16
+ */
17
+ function maskDateText(next, previous = "") {
18
+ if (next.length <= previous.length || !next.startsWith(previous)) return next;
19
+ if (previous.endsWith("-") && /^[-./]$/.test(next.slice(previous.length))) return previous;
20
+ if (DIGITS_ONLY.test(next)) {
21
+ let out = next.slice(0, 4);
22
+ if (next.length >= 4) out += "-";
23
+ out += next.slice(4, 6);
24
+ if (next.length >= 6) out += "-";
25
+ return out + next.slice(6);
26
+ }
27
+ const yearMonth = YEAR_MONTH.exec(next);
28
+ if (yearMonth) return `${yearMonth[1] ?? ""}-${yearMonth[2] ?? ""}`;
29
+ return next;
30
+ }
31
+ //#endregion
32
+ //#region src/input.ts
33
+ /**
34
+ * Read what the user typed: year first, ASCII or Devanagari digits, in the
35
+ * calendar on screen. All date work is done by core (docs/plan D-005).
36
+ */
37
+ function parseInput(text, calendar, limits, locale, format = "iso") {
38
+ if (text.trim() === "") return { kind: "empty" };
39
+ const messages = (0, _nepdatejs_core.getLocale)(locale).messages;
40
+ const date = (0, _nepdatejs_core.parseDate)(text, calendar);
41
+ if (!date) return {
42
+ kind: "error",
43
+ error: {
44
+ code: "format",
45
+ message: messages.invalidFormat[calendar]
46
+ }
47
+ };
48
+ const error = checkDate(date, calendar, limits, locale, format);
49
+ return error ? {
50
+ kind: "error",
51
+ error
52
+ } : {
53
+ kind: "date",
54
+ date: (0, _nepdatejs_core.toCalendar)(date, "AD")
55
+ };
56
+ }
57
+ /** Null when the day is allowed; otherwise a translated error. */
58
+ function checkDate(date, calendar, limits, locale, format = "iso") {
59
+ const messages = (0, _nepdatejs_core.getLocale)(locale).messages;
60
+ if (!(0, _nepdatejs_core.isWithin)(date, limits.min, limits.max)) {
61
+ const values = {
62
+ min: formatInput(limits.min, calendar, format, locale),
63
+ max: formatInput(limits.max, calendar, format, locale)
64
+ };
65
+ const template = limits.hasMin === limits.hasMax ? messages.outOfRange : limits.hasMin ? messages.onOrAfter : messages.onOrBefore;
66
+ return {
67
+ code: "range",
68
+ message: (0, _nepdatejs_core.formatMessage)(template, values)
69
+ };
70
+ }
71
+ if (limits.isDateDisabled?.(date)) return {
72
+ code: "disabled",
73
+ message: messages.unavailable
74
+ };
75
+ return null;
76
+ }
77
+ /** How the input shows a date: in the calendar on screen, with the locale's digits. */
78
+ function formatInput(date, calendar, format, locale) {
79
+ return date ? (0, _nepdatejs_core.formatDate)((0, _nepdatejs_core.toCalendar)(date, calendar), format, locale) : "";
80
+ }
81
+ /** "10 October 2026 AD": the same day in the other calendar. */
82
+ function equivalentText(date, calendar, locale) {
83
+ if (!date) return null;
84
+ const other = calendar === "BS" ? "AD" : "BS";
85
+ return `${(0, _nepdatejs_core.formatDate)((0, _nepdatejs_core.toCalendar)(date, other), "long", locale)} ${(0, _nepdatejs_core.getLocale)(locale).calendarNames[other]}`;
86
+ }
87
+ function placeholderText(calendar, locale) {
88
+ return `YYYY-MM-DD (${(0, _nepdatejs_core.getLocale)(locale).calendarNames[calendar]})`;
89
+ }
90
+ /** An AD "YYYY-MM-DD" string as a date; anything else is null. */
91
+ function readIso(value) {
92
+ return value ? (0, _nepdatejs_core.fromIsoDate)(value) : null;
93
+ }
94
+ function detailOf(date) {
95
+ return date ? Object.freeze({
96
+ ad: (0, _nepdatejs_core.toCalendar)(date, "AD"),
97
+ bs: (0, _nepdatejs_core.toCalendar)(date, "BS")
98
+ }) : null;
99
+ }
100
+ //#endregion
101
+ //#region src/base.ts
102
+ /** The panel calendar's options that come straight from the picker's options. */
103
+ function panelOptions(options, calendar) {
104
+ return {
105
+ calendar,
106
+ locale: options.locale,
107
+ min: readIso(options.min),
108
+ max: readIso(options.max),
109
+ isDateDisabled: options.isDateDisabled,
110
+ holidays: options.holidays,
111
+ events: options.events,
112
+ showOtherCalendar: options.showOtherCalendar,
113
+ weekStartsOn: options.weekStartsOn,
114
+ weekendDays: options.weekendDays,
115
+ today: options.today
116
+ };
117
+ }
118
+ /** What may be typed: the panel's effective range, so typing and clicking agree. */
119
+ function inputLimits(options, panel) {
120
+ const { minDate, maxDate } = panel.getState();
121
+ return {
122
+ min: minDate,
123
+ max: maxDate,
124
+ hasMin: readIso(options.min) !== null,
125
+ hasMax: readIso(options.max) !== null,
126
+ isDateDisabled: options.isDateDisabled
127
+ };
128
+ }
129
+ function localeOf(options) {
130
+ return options.locale ?? (0, _nepdatejs_core.getConfig)().defaultLocale;
131
+ }
132
+ function formatOf(options) {
133
+ return options.displayFormat ?? "iso";
134
+ }
135
+ function todayOf(options) {
136
+ return options.today ?? (0, _nepdatejs_core.today)("AD");
137
+ }
138
+ function isRange(selection) {
139
+ return !(0, _nepdatejs_calendar.isDayList)(selection) && !("calendar" in selection);
140
+ }
141
+ function isSingleDay(selection) {
142
+ return !(0, _nepdatejs_calendar.isDayList)(selection) && "calendar" in selection;
143
+ }
144
+ /**
145
+ * Listener set plus batching: changes made inside `act` notify once at the end,
146
+ * and callbacks queued with `after` run after listeners have seen the new state.
147
+ */
148
+ function createEmitter(rebuild) {
149
+ const listeners = /* @__PURE__ */ new Set();
150
+ const queued = [];
151
+ let depth = 0;
152
+ function notify() {
153
+ rebuild();
154
+ for (const listener of [...listeners]) listener();
155
+ }
156
+ return {
157
+ subscribe(listener) {
158
+ listeners.add(listener);
159
+ return () => {
160
+ listeners.delete(listener);
161
+ };
162
+ },
163
+ act(change) {
164
+ depth++;
165
+ try {
166
+ change();
167
+ } finally {
168
+ depth--;
169
+ }
170
+ if (depth === 0) {
171
+ notify();
172
+ for (const callback of queued.splice(0)) callback();
173
+ }
174
+ },
175
+ after(callback) {
176
+ queued.push(callback);
177
+ },
178
+ notify() {
179
+ if (depth === 0) notify();
180
+ },
181
+ clear() {
182
+ listeners.clear();
183
+ }
184
+ };
185
+ }
186
+ //#endregion
187
+ //#region src/presets.ts
188
+ /** The date a built-in single preset stands for. */
189
+ function resolveSinglePreset(id, context) {
190
+ const today = (0, _nepdatejs_core.toCalendar)(context.today, context.calendar);
191
+ switch (id) {
192
+ case "today": return today;
193
+ case "yesterday": return (0, _nepdatejs_core.addDays)(today, -1);
194
+ case "tomorrow": return (0, _nepdatejs_core.addDays)(today, 1);
195
+ }
196
+ }
197
+ /** The range a built-in range preset stands for, in the calendar on screen. */
198
+ function resolveRangePreset(id, context) {
199
+ const today = (0, _nepdatejs_core.toCalendar)(context.today, context.calendar);
200
+ const week = context.weekStartsOn;
201
+ switch (id) {
202
+ case "today": return {
203
+ start: today,
204
+ end: today
205
+ };
206
+ case "yesterday": {
207
+ const day = (0, _nepdatejs_core.addDays)(today, -1);
208
+ return {
209
+ start: day,
210
+ end: day
211
+ };
212
+ }
213
+ case "thisWeek": return {
214
+ start: (0, _nepdatejs_core.startOfWeek)(today, week),
215
+ end: (0, _nepdatejs_core.endOfWeek)(today, week)
216
+ };
217
+ case "lastWeek": {
218
+ const day = (0, _nepdatejs_core.addDays)(today, -7);
219
+ return {
220
+ start: (0, _nepdatejs_core.startOfWeek)(day, week),
221
+ end: (0, _nepdatejs_core.endOfWeek)(day, week)
222
+ };
223
+ }
224
+ case "last7Days": return {
225
+ start: (0, _nepdatejs_core.addDays)(today, -6),
226
+ end: today
227
+ };
228
+ case "last30Days": return {
229
+ start: (0, _nepdatejs_core.addDays)(today, -29),
230
+ end: today
231
+ };
232
+ case "thisMonth": return {
233
+ start: (0, _nepdatejs_core.startOfMonth)(today),
234
+ end: (0, _nepdatejs_core.endOfMonth)(today)
235
+ };
236
+ case "lastMonth": {
237
+ const month = (0, _nepdatejs_core.addMonths)((0, _nepdatejs_core.startOfMonth)(today), -1);
238
+ return {
239
+ start: month,
240
+ end: (0, _nepdatejs_core.endOfMonth)(month)
241
+ };
242
+ }
243
+ case "thisYear": return {
244
+ start: (0, _nepdatejs_core.startOfYear)(today),
245
+ end: (0, _nepdatejs_core.endOfYear)(today)
246
+ };
247
+ case "thisFiscalYear": {
248
+ const fy = (0, _nepdatejs_core.fiscalYear)(today);
249
+ return {
250
+ start: fy.firstDay,
251
+ end: fy.lastDay
252
+ };
253
+ }
254
+ case "lastFiscalYear": {
255
+ const fy = (0, _nepdatejs_core.fiscalYearRange)((0, _nepdatejs_core.fiscalYear)(today).startYear - 1);
256
+ return {
257
+ start: fy.firstDay,
258
+ end: fy.lastDay
259
+ };
260
+ }
261
+ }
262
+ }
263
+ /** Shared by both pickers: label + resolver for a preset entry. */
264
+ function describePreset(preset, locale, resolveBuiltIn) {
265
+ if (typeof preset === "string") return {
266
+ id: preset,
267
+ label: (0, _nepdatejs_core.getLocale)(locale).presets[preset] ?? preset,
268
+ resolve: (context) => resolveBuiltIn(preset, context)
269
+ };
270
+ return preset;
271
+ }
272
+ //#endregion
273
+ //#region src/picker.ts
274
+ /**
275
+ * A BS/AD date picker without UI: typed text ⇄ value, validation, the BS/AD
276
+ * switch and open/close, plus the panel's calendar store. The value is always
277
+ * an AD "YYYY-MM-DD" string (docs/plan D-003); all date work goes through core.
278
+ *
279
+ * Like the calendar, the picker keeps its own value; passing `value` through
280
+ * setOptions replaces it (controlled use). Passing back the value the user just
281
+ * typed leaves their text alone, so the cursor does not jump.
282
+ */
283
+ function createDatePicker(initial = {}) {
284
+ let options = { ...initial };
285
+ let calendar = options.calendar ?? options.defaultCalendar ?? "BS";
286
+ let date = readIso(options.value ?? options.defaultValue);
287
+ let value = date ? (0, _nepdatejs_core.toIsoDate)(date) : "";
288
+ let text = formatInput(date, calendar, formatOf(options), localeOf(options));
289
+ let error = null;
290
+ let open = false;
291
+ let destroyed = false;
292
+ const panel = (0, _nepdatejs_calendar.createCalendar)({
293
+ ...panelOptions(options, calendar),
294
+ selectionMode: "single",
295
+ selected: date,
296
+ onSelect: (selection) => {
297
+ if (isSingleDay(selection)) pick(selection);
298
+ }
299
+ });
300
+ let snapshot = build();
301
+ const emitter = createEmitter(() => {
302
+ snapshot = build();
303
+ });
304
+ panel.subscribe(() => {
305
+ emitter.notify();
306
+ });
307
+ function build() {
308
+ const locale = localeOf(options);
309
+ return Object.freeze({
310
+ value,
311
+ date: detailOf(date),
312
+ text,
313
+ calendar,
314
+ canSwitchCalendar: options.calendar === void 0,
315
+ open: open || options.inline === true,
316
+ inline: options.inline === true,
317
+ error,
318
+ equivalentText: error ? null : equivalentText(date, calendar, locale),
319
+ placeholder: placeholderText(calendar, locale),
320
+ presets: presetStates(),
321
+ calendarState: panel.getState()
322
+ });
323
+ }
324
+ function presetContext() {
325
+ return {
326
+ today: (0, _nepdatejs_core.toCalendar)(todayOf(options), "AD"),
327
+ calendar,
328
+ weekStartsOn: options.weekStartsOn ?? (0, _nepdatejs_core.getConfig)().weekStartsOn
329
+ };
330
+ }
331
+ /** Each shortcut's date, or null when it cannot be used now. */
332
+ function resolvedPresets() {
333
+ const context = presetContext();
334
+ const limits = inputLimits(options, panel);
335
+ return (options.presets ?? []).map((preset) => {
336
+ const entry = describePreset(preset, options.locale, resolveSinglePreset);
337
+ const date = (() => {
338
+ try {
339
+ const candidate = entry.resolve(context);
340
+ return checkDate(candidate, calendar, limits, localeOf(options)) ? null : candidate;
341
+ } catch {
342
+ return null;
343
+ }
344
+ })();
345
+ return {
346
+ id: entry.id,
347
+ label: entry.label,
348
+ date
349
+ };
350
+ });
351
+ }
352
+ function presetStates() {
353
+ return resolvedPresets().map(({ id, label, date }) => Object.freeze({
354
+ id,
355
+ label,
356
+ isActive: date !== null && (0, _nepdatejs_core.toIsoDate)(date) === value,
357
+ isDisabled: date === null
358
+ }));
359
+ }
360
+ function syncPanel(showDate) {
361
+ panel.setOptions({
362
+ ...panelOptions(options, calendar),
363
+ selected: date,
364
+ ...showDate && date ? { visibleMonth: date } : {}
365
+ });
366
+ }
367
+ /** Change the value; queue onChange when it differs and the user caused it. */
368
+ function setDate(next, byUser) {
369
+ const nextValue = next ? (0, _nepdatejs_core.toIsoDate)(next) : "";
370
+ const changed = nextValue !== value;
371
+ date = next;
372
+ value = nextValue;
373
+ syncPanel(next !== null);
374
+ if (changed && byUser) {
375
+ const detail = detailOf(next);
376
+ emitter.after(() => options.onChange?.(nextValue, detail));
377
+ }
378
+ }
379
+ function format(next) {
380
+ return formatInput(next, calendar, formatOf(options), localeOf(options));
381
+ }
382
+ function pick(selection) {
383
+ emitter.act(() => {
384
+ const next = (0, _nepdatejs_core.toCalendar)(selection, "AD");
385
+ error = null;
386
+ text = format(next);
387
+ setDate(next, true);
388
+ if (options.closeOnSelect ?? true) open = false;
389
+ });
390
+ }
391
+ const actions = {
392
+ type(next) {
393
+ if (destroyed) return;
394
+ emitter.act(() => {
395
+ text = options.mask === false ? next : maskDateText(next, text);
396
+ const result = parseInput(text, calendar, inputLimits(options, panel), localeOf(options), formatOf(options));
397
+ error = result.kind === "error" ? result.error : null;
398
+ setDate(result.kind === "date" ? result.date : null, true);
399
+ });
400
+ },
401
+ blur() {
402
+ emitter.act(() => {
403
+ if (!error) text = format(date);
404
+ });
405
+ },
406
+ clear() {
407
+ emitter.act(() => {
408
+ text = "";
409
+ error = null;
410
+ setDate(null, true);
411
+ });
412
+ },
413
+ setValue(next) {
414
+ emitter.act(() => {
415
+ applyValue(next);
416
+ });
417
+ },
418
+ open() {
419
+ emitter.act(() => {
420
+ open = true;
421
+ panel.actions.goTo(date ?? todayOf(options));
422
+ });
423
+ },
424
+ close() {
425
+ emitter.act(() => {
426
+ open = false;
427
+ });
428
+ },
429
+ toggle() {
430
+ if (open) actions.close();
431
+ else actions.open();
432
+ },
433
+ switchCalendar(next) {
434
+ if (options.calendar !== void 0 || next === calendar || destroyed) return;
435
+ emitter.act(() => {
436
+ calendar = next;
437
+ if (!error) text = format(date);
438
+ syncPanel(date !== null);
439
+ emitter.after(() => options.onCalendarChange?.(next));
440
+ });
441
+ },
442
+ select(day) {
443
+ let picked = false;
444
+ if (!destroyed) emitter.act(() => {
445
+ picked = panel.actions.select(day);
446
+ });
447
+ return picked;
448
+ },
449
+ selectToday() {
450
+ return actions.select(todayOf(options));
451
+ },
452
+ reset() {
453
+ emitter.act(() => {
454
+ const next = readIso(options.defaultValue);
455
+ error = null;
456
+ text = format(next);
457
+ setDate(next, true);
458
+ });
459
+ },
460
+ applyPreset(id) {
461
+ const preset = resolvedPresets().find((entry) => entry.id === id);
462
+ if (destroyed || !preset?.date) return false;
463
+ pick(preset.date);
464
+ return true;
465
+ }
466
+ };
467
+ /** An outside value: replaces the text only when it is a different value (echo guard). */
468
+ function applyValue(next) {
469
+ const nextDate = readIso(next);
470
+ if ((nextDate ? (0, _nepdatejs_core.toIsoDate)(nextDate) : "") === value) return;
471
+ error = null;
472
+ text = format(nextDate);
473
+ setDate(nextDate, false);
474
+ }
475
+ return {
476
+ getState: () => snapshot,
477
+ subscribe: (listener) => emitter.subscribe(listener),
478
+ setOptions(changes) {
479
+ if (destroyed) return;
480
+ emitter.act(() => {
481
+ const before = {
482
+ calendar,
483
+ locale: localeOf(options),
484
+ format: formatOf(options)
485
+ };
486
+ options = {
487
+ ...options,
488
+ ...changes
489
+ };
490
+ if (options.calendar !== void 0) calendar = options.calendar;
491
+ if ("value" in changes) applyValue(changes.value);
492
+ if ((before.calendar !== calendar || before.locale !== localeOf(options) || before.format !== formatOf(options)) && !error) text = format(date);
493
+ syncPanel(false);
494
+ });
495
+ },
496
+ actions,
497
+ calendar: panel,
498
+ destroy() {
499
+ destroyed = true;
500
+ panel.destroy();
501
+ emitter.clear();
502
+ }
503
+ };
504
+ }
505
+ //#endregion
506
+ //#region src/range.ts
507
+ /**
508
+ * A BS/AD date range picker without UI: two typed fields (start, end), a panel
509
+ * calendar in range mode, minDays/maxDays checks and the BS/AD switch. Values
510
+ * are AD "YYYY-MM-DD" strings; an unfinished or invalid end is "".
511
+ */
512
+ function createDateRangePicker(initial = {}) {
513
+ let options = { ...initial };
514
+ let calendar = options.calendar ?? options.defaultCalendar ?? "BS";
515
+ let start = readIso(options.value?.start ?? options.defaultValue?.start);
516
+ let end = readIso(options.value?.end ?? options.defaultValue?.end);
517
+ [start, end] = ordered(start, end);
518
+ let value = valueOf(start, end);
519
+ let startText = format(start);
520
+ let endText = format(end);
521
+ let error = null;
522
+ let open = false;
523
+ let destroyed = false;
524
+ const panel = (0, _nepdatejs_calendar.createCalendar)({
525
+ ...panelOptions(options, calendar),
526
+ selectionMode: "range",
527
+ selected: {
528
+ start,
529
+ end
530
+ },
531
+ onSelect: (selection) => {
532
+ if (isRange(selection)) pick(selection.start, selection.end);
533
+ }
534
+ });
535
+ let snapshot = build();
536
+ const emitter = createEmitter(() => {
537
+ snapshot = build();
538
+ });
539
+ panel.subscribe(() => {
540
+ emitter.notify();
541
+ });
542
+ function format(date) {
543
+ return formatInput(date, calendar, formatOf(options), localeOf(options));
544
+ }
545
+ function build() {
546
+ const locale = localeOf(options);
547
+ return Object.freeze({
548
+ value,
549
+ date: Object.freeze({
550
+ start: detailOf(start),
551
+ end: detailOf(end)
552
+ }),
553
+ startText,
554
+ endText,
555
+ calendar,
556
+ canSwitchCalendar: options.calendar === void 0,
557
+ open: open || options.inline === true,
558
+ inline: options.inline === true,
559
+ error,
560
+ equivalentText: Object.freeze({
561
+ start: error?.field === "start" ? null : equivalentText(start, calendar, locale),
562
+ end: error?.field === "end" ? null : equivalentText(end, calendar, locale)
563
+ }),
564
+ placeholder: placeholderText(calendar, locale),
565
+ presets: presetStates(),
566
+ calendarState: panel.getState()
567
+ });
568
+ }
569
+ function presetContext() {
570
+ return {
571
+ today: (0, _nepdatejs_core.toCalendar)(todayOf(options), "AD"),
572
+ calendar,
573
+ weekStartsOn: options.weekStartsOn ?? (0, _nepdatejs_core.getConfig)().weekStartsOn
574
+ };
575
+ }
576
+ /** Each shortcut's range, or null when it cannot be used now. */
577
+ function resolvedPresets() {
578
+ const context = presetContext();
579
+ const limits = inputLimits(options, panel);
580
+ const locale = localeOf(options);
581
+ return (options.presets ?? []).map((preset) => {
582
+ const entry = describePreset(preset, options.locale, resolveRangePreset);
583
+ const range = (() => {
584
+ try {
585
+ const candidate = entry.resolve(context);
586
+ const from = (0, _nepdatejs_core.toCalendar)(candidate.start, "AD");
587
+ const to = (0, _nepdatejs_core.toCalendar)(candidate.end, "AD");
588
+ return (0, _nepdatejs_core.compareDates)(from, to) <= 0 && !checkDate(from, calendar, limits, locale) && !checkDate(to, calendar, limits, locale) && lengthError(from, to) === null ? candidate : null;
589
+ } catch {
590
+ return null;
591
+ }
592
+ })();
593
+ return {
594
+ id: entry.id,
595
+ label: entry.label,
596
+ range
597
+ };
598
+ });
599
+ }
600
+ function presetStates() {
601
+ return resolvedPresets().map(({ id, label, range }) => Object.freeze({
602
+ id,
603
+ label,
604
+ isActive: range !== null && (0, _nepdatejs_core.toIsoDate)(range.start) === value.start && (0, _nepdatejs_core.toIsoDate)(range.end) === value.end,
605
+ isDisabled: range === null
606
+ }));
607
+ }
608
+ function syncPanel() {
609
+ panel.setOptions({
610
+ ...panelOptions(options, calendar),
611
+ selected: {
612
+ start,
613
+ end
614
+ },
615
+ ...start ? { visibleMonth: start } : {}
616
+ });
617
+ }
618
+ /** Too short or too long, or null. Counts both ends. */
619
+ function lengthError(from, to) {
620
+ const days = (0, _nepdatejs_core.differenceInDays)(to, from) + 1;
621
+ const messages = (0, _nepdatejs_core.getLocale)(localeOf(options)).messages;
622
+ if (options.minDays !== void 0 && days < options.minDays) return {
623
+ field: "range",
624
+ code: "tooShort",
625
+ message: (0, _nepdatejs_core.formatMessage)(messages.rangeTooShort, { min: String(options.minDays) })
626
+ };
627
+ if (options.maxDays !== void 0 && days > options.maxDays) return {
628
+ field: "range",
629
+ code: "tooLong",
630
+ message: (0, _nepdatejs_core.formatMessage)(messages.rangeTooLong, { max: String(options.maxDays) })
631
+ };
632
+ return null;
633
+ }
634
+ /** Store the dates, keep the panel in step, and queue onChange when the value moved. */
635
+ function commit(nextStart, nextEnd, byUser) {
636
+ start = nextStart;
637
+ end = nextEnd;
638
+ const next = valueOf(start, end);
639
+ const changed = next.start !== value.start || next.end !== value.end;
640
+ value = next;
641
+ syncPanel();
642
+ if (changed && byUser) {
643
+ const detail = Object.freeze({
644
+ start: detailOf(start),
645
+ end: detailOf(end)
646
+ });
647
+ emitter.after(() => options.onChange?.(next, detail));
648
+ }
649
+ }
650
+ /** Put the ends in order, check the length, then commit. False when the length is not allowed. */
651
+ function settle(nextStart, nextEnd) {
652
+ const [a, b] = ordered(nextStart, nextEnd);
653
+ if (a !== nextStart) [startText, endText] = [endText, startText];
654
+ const tooFar = a && b ? lengthError(a, b) : null;
655
+ error = tooFar ?? error;
656
+ commit(a, tooFar ? null : b, true);
657
+ return tooFar === null;
658
+ }
659
+ function pick(from, to) {
660
+ emitter.act(() => {
661
+ const a = from ? (0, _nepdatejs_core.toCalendar)(from, "AD") : null;
662
+ const b = to ? (0, _nepdatejs_core.toCalendar)(to, "AD") : null;
663
+ error = null;
664
+ startText = format(a);
665
+ endText = format(b);
666
+ const allowed = settle(a, b);
667
+ if (b && allowed && (options.closeOnSelect ?? true)) open = false;
668
+ });
669
+ }
670
+ const actions = {
671
+ type(field, text) {
672
+ if (destroyed) return;
673
+ emitter.act(() => {
674
+ if (options.mask !== false) text = maskDateText(text, field === "start" ? startText : endText);
675
+ if (field === "start") startText = text;
676
+ else endText = text;
677
+ const result = parseInput(text, calendar, inputLimits(options, panel), localeOf(options), formatOf(options));
678
+ const date = result.kind === "date" ? result.date : null;
679
+ error = result.kind === "error" ? {
680
+ ...result.error,
681
+ field
682
+ } : null;
683
+ const other = field === "start" ? end : start;
684
+ const otherError = other ? checkDate(other, calendar, inputLimits(options, panel), localeOf(options)) : null;
685
+ if (!error && otherError) error = {
686
+ ...otherError,
687
+ field: field === "start" ? "end" : "start"
688
+ };
689
+ if (field === "start") settle(date, end);
690
+ else settle(start, date);
691
+ });
692
+ },
693
+ blur(field) {
694
+ emitter.act(() => {
695
+ if (error?.field === field) return;
696
+ if (field === "start") startText = format(start);
697
+ else if (end || error?.field !== "range") endText = format(end);
698
+ });
699
+ },
700
+ clear() {
701
+ emitter.act(() => {
702
+ startText = "";
703
+ endText = "";
704
+ error = null;
705
+ commit(null, null, true);
706
+ });
707
+ },
708
+ setValue(next) {
709
+ emitter.act(() => {
710
+ applyValue(next);
711
+ });
712
+ },
713
+ open() {
714
+ emitter.act(() => {
715
+ open = true;
716
+ panel.actions.goTo(start ?? todayOf(options));
717
+ });
718
+ },
719
+ close() {
720
+ emitter.act(() => {
721
+ open = false;
722
+ });
723
+ },
724
+ toggle() {
725
+ if (open) actions.close();
726
+ else actions.open();
727
+ },
728
+ switchCalendar(next) {
729
+ if (options.calendar !== void 0 || next === calendar || destroyed) return;
730
+ emitter.act(() => {
731
+ calendar = next;
732
+ if (!error) {
733
+ startText = format(start);
734
+ endText = format(end);
735
+ }
736
+ syncPanel();
737
+ emitter.after(() => options.onCalendarChange?.(next));
738
+ });
739
+ },
740
+ select(day) {
741
+ let picked = false;
742
+ if (!destroyed) emitter.act(() => {
743
+ picked = panel.actions.select(day);
744
+ });
745
+ return picked;
746
+ },
747
+ applyPreset(id) {
748
+ const preset = resolvedPresets().find((entry) => entry.id === id);
749
+ if (destroyed || !preset?.range) return false;
750
+ pick(preset.range.start, preset.range.end);
751
+ return true;
752
+ },
753
+ reset() {
754
+ emitter.act(() => {
755
+ const [a, b] = ordered(readIso(options.defaultValue?.start), readIso(options.defaultValue?.end));
756
+ error = null;
757
+ startText = format(a);
758
+ endText = format(b);
759
+ commit(a, b, true);
760
+ });
761
+ }
762
+ };
763
+ /** An outside value: replaces the texts only when the value differs (echo guard). */
764
+ function applyValue(next) {
765
+ const [a, b] = ordered(readIso(next?.start), readIso(next?.end));
766
+ const incoming = valueOf(a, b);
767
+ if (incoming.start === value.start && incoming.end === value.end) return;
768
+ error = null;
769
+ startText = format(a);
770
+ endText = format(b);
771
+ commit(a, b, false);
772
+ }
773
+ return {
774
+ getState: () => snapshot,
775
+ subscribe: (listener) => emitter.subscribe(listener),
776
+ setOptions(changes) {
777
+ if (destroyed) return;
778
+ emitter.act(() => {
779
+ const before = {
780
+ calendar,
781
+ locale: localeOf(options),
782
+ format: formatOf(options)
783
+ };
784
+ options = {
785
+ ...options,
786
+ ...changes
787
+ };
788
+ if (options.calendar !== void 0) calendar = options.calendar;
789
+ if ("value" in changes) applyValue(changes.value);
790
+ if ((before.calendar !== calendar || before.locale !== localeOf(options) || before.format !== formatOf(options)) && !error) {
791
+ startText = format(start);
792
+ endText = format(end);
793
+ }
794
+ syncPanel();
795
+ });
796
+ },
797
+ actions,
798
+ calendar: panel,
799
+ destroy() {
800
+ destroyed = true;
801
+ panel.destroy();
802
+ emitter.clear();
803
+ }
804
+ };
805
+ }
806
+ function ordered(a, b) {
807
+ return a && b && (0, _nepdatejs_core.compareDates)(b, a) < 0 ? [b, a] : [a, b];
808
+ }
809
+ function valueOf(start, end) {
810
+ return Object.freeze({
811
+ start: start ? (0, _nepdatejs_core.toIsoDate)(start) : "",
812
+ end: end ? (0, _nepdatejs_core.toIsoDate)(end) : ""
813
+ });
814
+ }
815
+ //#endregion
816
+ //#region src/multi.ts
817
+ const SEPARATOR = /[,\s\u060c]+/;
818
+ /**
819
+ * A picker for several separate days (PICK-001). The value is a sorted list of
820
+ * AD "YYYY-MM-DD" strings; the input lists the days in the calendar on screen,
821
+ * separated by ", ", and clicking a day in the panel adds or removes it. The
822
+ * list is always written as YYYY-MM-DD so it can be typed back.
823
+ */
824
+ function createMultiDatePicker(initial = {}) {
825
+ let options = { ...initial };
826
+ let calendar = options.calendar ?? options.defaultCalendar ?? "BS";
827
+ let dates = readAll(options.value ?? options.defaultValue);
828
+ let value = valuesOf(dates);
829
+ let text = format(dates);
830
+ let error = null;
831
+ /** False while the typed text has a problem: then it is left as typed. */
832
+ let textOk = true;
833
+ let open = false;
834
+ let destroyed = false;
835
+ const panel = (0, _nepdatejs_calendar.createCalendar)({
836
+ ...panelOptions(options, calendar),
837
+ selectionMode: "multiple",
838
+ selected: dates,
839
+ onSelect: (selection) => {
840
+ if ((0, _nepdatejs_calendar.isDayList)(selection)) pick(selection.map((day) => (0, _nepdatejs_core.toCalendar)(day, "AD")));
841
+ }
842
+ });
843
+ let snapshot = build();
844
+ const emitter = createEmitter(() => {
845
+ snapshot = build();
846
+ });
847
+ panel.subscribe(() => {
848
+ emitter.notify();
849
+ });
850
+ function build() {
851
+ return Object.freeze({
852
+ value,
853
+ dates: detailsOf(dates),
854
+ text,
855
+ calendar,
856
+ canSwitchCalendar: options.calendar === void 0,
857
+ open: open || options.inline === true,
858
+ inline: options.inline === true,
859
+ error,
860
+ placeholder: placeholderText(calendar, localeOf(options)),
861
+ calendarState: panel.getState()
862
+ });
863
+ }
864
+ function format(list) {
865
+ return list.map((day) => formatInput(day, calendar, "iso", localeOf(options))).join(", ");
866
+ }
867
+ function tooMany(count) {
868
+ const max = options.maxDates;
869
+ return max !== void 0 && count > max ? {
870
+ code: "tooMany",
871
+ message: (0, _nepdatejs_core.formatMessage)((0, _nepdatejs_core.getLocale)(localeOf(options)).messages.tooManyDates, { max: String(max) })
872
+ } : null;
873
+ }
874
+ function syncPanel() {
875
+ panel.setOptions({
876
+ ...panelOptions(options, calendar),
877
+ selected: dates
878
+ });
879
+ }
880
+ /** Change the value; queue onChange when it differs and the user caused it. */
881
+ function setDates(next, byUser) {
882
+ const sorted = unique(next);
883
+ const nextValue = valuesOf(sorted);
884
+ const changed = nextValue.join() !== value.join();
885
+ dates = sorted;
886
+ value = nextValue;
887
+ syncPanel();
888
+ if (changed && byUser) {
889
+ const details = detailsOf(sorted);
890
+ emitter.after(() => options.onChange?.(nextValue, details));
891
+ }
892
+ }
893
+ function pick(next) {
894
+ emitter.act(() => {
895
+ error = tooMany(next.length);
896
+ if (error) {
897
+ syncPanel();
898
+ return;
899
+ }
900
+ text = format(unique(next));
901
+ textOk = true;
902
+ setDates(next, true);
903
+ if (options.closeOnSelect === true) open = false;
904
+ });
905
+ }
906
+ const actions = {
907
+ type(next) {
908
+ if (destroyed) return;
909
+ emitter.act(() => {
910
+ text = options.mask === false ? next : maskLast(next, text);
911
+ const limits = inputLimits(options, panel);
912
+ const parsed = [];
913
+ let firstError = null;
914
+ for (const token of text.split(SEPARATOR)) {
915
+ const result = parseInput(token, calendar, limits, localeOf(options));
916
+ if (result.kind === "date") parsed.push(result.date);
917
+ else if (result.kind === "error") firstError ?? (firstError = result.error);
918
+ }
919
+ error = firstError ?? tooMany(unique(parsed).length);
920
+ textOk = error === null;
921
+ setDates(parsed, true);
922
+ });
923
+ },
924
+ blur() {
925
+ emitter.act(() => {
926
+ if (textOk) text = format(dates);
927
+ });
928
+ },
929
+ clear() {
930
+ emitter.act(() => {
931
+ text = "";
932
+ error = null;
933
+ textOk = true;
934
+ setDates([], true);
935
+ });
936
+ },
937
+ setValue(next) {
938
+ emitter.act(() => {
939
+ applyValue(next);
940
+ });
941
+ },
942
+ open() {
943
+ emitter.act(() => {
944
+ open = true;
945
+ const first = dates[0];
946
+ if (first) panel.actions.goTo(first);
947
+ });
948
+ },
949
+ close() {
950
+ emitter.act(() => {
951
+ open = false;
952
+ });
953
+ },
954
+ toggle() {
955
+ if (open) actions.close();
956
+ else actions.open();
957
+ },
958
+ switchCalendar(next) {
959
+ if (options.calendar !== void 0 || next === calendar || destroyed) return;
960
+ emitter.act(() => {
961
+ calendar = next;
962
+ if (textOk) text = format(dates);
963
+ syncPanel();
964
+ emitter.after(() => options.onCalendarChange?.(next));
965
+ });
966
+ },
967
+ select(day) {
968
+ if (destroyed) return false;
969
+ const before = value;
970
+ emitter.act(() => {
971
+ panel.actions.select(day);
972
+ });
973
+ return value !== before;
974
+ },
975
+ remove(iso) {
976
+ emitter.act(() => {
977
+ error = null;
978
+ const next = dates.filter((day) => (0, _nepdatejs_core.toIsoDate)(day) !== iso);
979
+ text = format(next);
980
+ textOk = true;
981
+ setDates(next, true);
982
+ });
983
+ },
984
+ reset() {
985
+ emitter.act(() => {
986
+ const next = readAll(options.defaultValue);
987
+ error = null;
988
+ text = format(next);
989
+ textOk = true;
990
+ setDates(next, true);
991
+ });
992
+ }
993
+ };
994
+ /** An outside value: replaces the text only when it is a different value (echo guard). */
995
+ function applyValue(next) {
996
+ const nextDates = readAll(next);
997
+ if (valuesOf(nextDates).join() === value.join()) return;
998
+ error = null;
999
+ text = format(nextDates);
1000
+ textOk = true;
1001
+ setDates(nextDates, false);
1002
+ }
1003
+ return {
1004
+ getState: () => snapshot,
1005
+ subscribe: (listener) => emitter.subscribe(listener),
1006
+ setOptions(changes) {
1007
+ if (destroyed) return;
1008
+ emitter.act(() => {
1009
+ const before = {
1010
+ calendar,
1011
+ locale: localeOf(options)
1012
+ };
1013
+ options = {
1014
+ ...options,
1015
+ ...changes
1016
+ };
1017
+ if (options.calendar !== void 0) calendar = options.calendar;
1018
+ if ("value" in changes) applyValue(changes.value);
1019
+ if ((before.calendar !== calendar || before.locale !== localeOf(options)) && textOk) text = format(dates);
1020
+ syncPanel();
1021
+ });
1022
+ },
1023
+ actions,
1024
+ calendar: panel,
1025
+ destroy() {
1026
+ destroyed = true;
1027
+ panel.destroy();
1028
+ emitter.clear();
1029
+ }
1030
+ };
1031
+ }
1032
+ function readAll(values) {
1033
+ return unique((values ?? []).map(readIso).filter((day) => day !== null));
1034
+ }
1035
+ function unique(list) {
1036
+ return [...new Map(list.map((day) => [(0, _nepdatejs_core.toIsoDate)(day), day])).entries()].sort(([a], [b]) => a < b ? -1 : 1).map(([, day]) => day);
1037
+ }
1038
+ function valuesOf(list) {
1039
+ return Object.freeze(list.map((day) => (0, _nepdatejs_core.toIsoDate)(day)));
1040
+ }
1041
+ function detailsOf(list) {
1042
+ return Object.freeze(list.map((day) => Object.freeze({
1043
+ ad: day,
1044
+ bs: (0, _nepdatejs_core.toCalendar)(day, "BS")
1045
+ })));
1046
+ }
1047
+ /** Mask only the day being typed: the text after the last separator. */
1048
+ function maskLast(next, previous) {
1049
+ if (!next.startsWith(previous)) return next;
1050
+ const match = /^(.*[,\s\u060c])?([^,\s\u060c]*)$/.exec(next);
1051
+ const head = match?.[1] ?? "";
1052
+ return head + maskDateText(match?.[2] ?? next, previous.length > head.length ? previous.slice(head.length) : "");
1053
+ }
1054
+ //#endregion
1055
+ //#region src/datetime.ts
1056
+ /**
1057
+ * A BS/AD date and time picker without UI. The date half is a regular date
1058
+ * picker; the value is the instant as an ISO timestamp carrying the zone's
1059
+ * offset, so servers store one unambiguous moment.
1060
+ */
1061
+ function createDateTimePicker(initial = {}) {
1062
+ let options = { ...initial };
1063
+ const start = (0, _nepdatejs_core.fromIsoDateTime)(options.value ?? options.defaultValue, zone());
1064
+ let time = start?.time ?? null;
1065
+ let timeText = time ? fmt(time) : "";
1066
+ let timeError = null;
1067
+ let value = "";
1068
+ let destroyed = false;
1069
+ const datePicker = createDatePicker({
1070
+ ...dateOptions(),
1071
+ defaultValue: start ? toIsoDay(start.date) : "",
1072
+ closeOnSelect: false,
1073
+ onChange: () => {
1074
+ emitter.act(() => {
1075
+ if (datePicker.getState().date && !time) {
1076
+ time = (0, _nepdatejs_core.parseTime)(options.defaultTime) ?? Object.freeze({
1077
+ hour: 0,
1078
+ minute: 0
1079
+ });
1080
+ timeText = fmt(time);
1081
+ timeError = null;
1082
+ }
1083
+ commit(true);
1084
+ });
1085
+ }
1086
+ });
1087
+ value = compose();
1088
+ let snapshot = build();
1089
+ const emitter = createEmitter(() => {
1090
+ snapshot = build();
1091
+ });
1092
+ datePicker.subscribe(() => {
1093
+ emitter.notify();
1094
+ });
1095
+ function zone() {
1096
+ return options.timeZone ?? (0, _nepdatejs_core.getConfig)().timeZone;
1097
+ }
1098
+ function fmt(t) {
1099
+ return (0, _nepdatejs_core.formatTime)(t, {
1100
+ hour12: options.hour12 ?? false,
1101
+ locale: localeOf(options)
1102
+ });
1103
+ }
1104
+ function dateOptions() {
1105
+ const { value: _value, defaultValue: _default, onChange: _onChange, timeZone: _zone, hour12: _hour12, minuteStep: _step, defaultTime: _defaultTime, ...rest } = options;
1106
+ return rest;
1107
+ }
1108
+ function compose() {
1109
+ const day = datePicker.getState().date;
1110
+ return day && time ? (0, _nepdatejs_core.toIsoDateTime)(day.ad, time, zone()) : "";
1111
+ }
1112
+ function detail() {
1113
+ const day = datePicker.getState().date;
1114
+ return day && time && value ? Object.freeze({
1115
+ ad: day.ad,
1116
+ bs: day.bs,
1117
+ time,
1118
+ iso: value
1119
+ }) : null;
1120
+ }
1121
+ /** Recompute the value; queue onChange when it changed and the user caused it. */
1122
+ function commit(byUser) {
1123
+ const next = compose();
1124
+ if (next === value) return;
1125
+ value = next;
1126
+ if (byUser) {
1127
+ const info = detail();
1128
+ emitter.after(() => options.onChange?.(next, info));
1129
+ }
1130
+ }
1131
+ function build() {
1132
+ const inner = datePicker.getState();
1133
+ const locale = localeOf(options);
1134
+ const step = Math.min(30, Math.max(1, Math.floor(options.minuteStep ?? 5)));
1135
+ const { am, pm } = (0, _nepdatejs_core.getLocale)(locale).time;
1136
+ const hour12 = options.hour12 ?? false;
1137
+ return Object.freeze({
1138
+ value,
1139
+ detail: detail(),
1140
+ dateText: inner.text,
1141
+ timeText,
1142
+ time,
1143
+ calendar: inner.calendar,
1144
+ canSwitchCalendar: inner.canSwitchCalendar,
1145
+ open: inner.open,
1146
+ inline: inner.inline,
1147
+ error: inner.error ? {
1148
+ ...inner.error,
1149
+ field: "date"
1150
+ } : timeError ? {
1151
+ ...timeError,
1152
+ field: "time"
1153
+ } : null,
1154
+ equivalentText: inner.equivalentText,
1155
+ placeholder: inner.placeholder,
1156
+ timePlaceholder: hour12 ? `h:mm ${am}` : "HH:MM",
1157
+ hours: Array.from({ length: 24 }, (_, hour) => Object.freeze({
1158
+ value: hour,
1159
+ label: hour12 ? `${(0, _nepdatejs_core.formatNumber)(hour % 12 === 0 ? 12 : hour % 12, locale)} ${hour < 12 ? am : pm}` : (0, _nepdatejs_core.formatNumber)(String(hour).padStart(2, "0"), locale),
1160
+ isSelected: time?.hour === hour
1161
+ })),
1162
+ minutes: Array.from({ length: Math.ceil(60 / step) }, (_, index) => Object.freeze({
1163
+ value: index * step,
1164
+ label: (0, _nepdatejs_core.formatNumber)(String(index * step).padStart(2, "0"), locale),
1165
+ isSelected: time?.minute === index * step
1166
+ })),
1167
+ presets: inner.presets,
1168
+ calendarState: inner.calendarState
1169
+ });
1170
+ }
1171
+ function setTime(next, text, byUser) {
1172
+ time = next;
1173
+ timeText = text;
1174
+ timeError = null;
1175
+ commit(byUser);
1176
+ }
1177
+ const actions = {
1178
+ typeDate(text) {
1179
+ datePicker.actions.type(text);
1180
+ },
1181
+ blurDate() {
1182
+ datePicker.actions.blur();
1183
+ },
1184
+ typeTime(text) {
1185
+ if (destroyed) return;
1186
+ emitter.act(() => {
1187
+ const parsed = (0, _nepdatejs_core.parseTime)(text);
1188
+ if (text.trim() === "" || parsed) setTime(parsed, text, true);
1189
+ else {
1190
+ time = null;
1191
+ timeText = text;
1192
+ timeError = {
1193
+ code: "format",
1194
+ message: (0, _nepdatejs_core.getLocale)(localeOf(options)).messages.invalidTime
1195
+ };
1196
+ commit(true);
1197
+ }
1198
+ });
1199
+ },
1200
+ blurTime() {
1201
+ emitter.act(() => {
1202
+ if (!timeError && time) timeText = fmt(time);
1203
+ });
1204
+ },
1205
+ selectDate(date) {
1206
+ return !destroyed && datePicker.actions.select(date);
1207
+ },
1208
+ selectHour(hour) {
1209
+ emitter.act(() => {
1210
+ const next = Object.freeze({
1211
+ hour,
1212
+ minute: time?.minute ?? 0
1213
+ });
1214
+ setTime(next, fmt(next), true);
1215
+ });
1216
+ },
1217
+ selectMinute(minute) {
1218
+ emitter.act(() => {
1219
+ const next = Object.freeze({
1220
+ hour: time?.hour ?? 0,
1221
+ minute
1222
+ });
1223
+ setTime(next, fmt(next), true);
1224
+ });
1225
+ },
1226
+ selectNow() {
1227
+ if (destroyed) return false;
1228
+ const current = (0, _nepdatejs_core.now)(zone());
1229
+ let picked = false;
1230
+ emitter.act(() => {
1231
+ time = current.time;
1232
+ timeText = fmt(current.time);
1233
+ timeError = null;
1234
+ picked = datePicker.actions.select(current.date);
1235
+ commit(true);
1236
+ });
1237
+ return picked;
1238
+ },
1239
+ applyPreset(id) {
1240
+ return !destroyed && datePicker.actions.applyPreset(id);
1241
+ },
1242
+ open() {
1243
+ datePicker.actions.open();
1244
+ },
1245
+ close() {
1246
+ datePicker.actions.close();
1247
+ },
1248
+ toggle() {
1249
+ datePicker.actions.toggle();
1250
+ },
1251
+ clear() {
1252
+ emitter.act(() => {
1253
+ datePicker.actions.setValue("");
1254
+ setTime(null, "", true);
1255
+ });
1256
+ },
1257
+ setValue(next) {
1258
+ emitter.act(() => {
1259
+ applyValue(next);
1260
+ });
1261
+ },
1262
+ switchCalendar(calendar) {
1263
+ datePicker.actions.switchCalendar(calendar);
1264
+ },
1265
+ reset() {
1266
+ emitter.act(() => {
1267
+ const start = (0, _nepdatejs_core.fromIsoDateTime)(options.defaultValue, zone());
1268
+ datePicker.actions.setValue(start ? toIsoDay(start.date) : "");
1269
+ setTime(start?.time ?? null, start ? fmt(start.time) : "", true);
1270
+ });
1271
+ }
1272
+ };
1273
+ /** An outside value; ignored when it is the instant already shown (echo guard). */
1274
+ function applyValue(next) {
1275
+ const parsed = (0, _nepdatejs_core.fromIsoDateTime)(next, zone());
1276
+ if ((parsed ? (0, _nepdatejs_core.toIsoDateTime)(parsed.date, parsed.time, zone()) : "") === value) return;
1277
+ datePicker.actions.setValue(parsed ? toIsoDay(parsed.date) : "");
1278
+ time = parsed?.time ?? null;
1279
+ timeText = time ? fmt(time) : "";
1280
+ timeError = null;
1281
+ commit(false);
1282
+ }
1283
+ return {
1284
+ getState: () => snapshot,
1285
+ subscribe: (listener) => emitter.subscribe(listener),
1286
+ setOptions(changes) {
1287
+ if (destroyed) return;
1288
+ emitter.act(() => {
1289
+ options = {
1290
+ ...options,
1291
+ ...changes
1292
+ };
1293
+ datePicker.setOptions(dateOptions());
1294
+ if ("value" in changes) applyValue(changes.value);
1295
+ if (time && !timeError) timeText = fmt(time);
1296
+ commit(false);
1297
+ });
1298
+ },
1299
+ actions,
1300
+ calendar: datePicker.calendar,
1301
+ destroy() {
1302
+ destroyed = true;
1303
+ datePicker.destroy();
1304
+ emitter.clear();
1305
+ }
1306
+ };
1307
+ }
1308
+ function toIsoDay(date) {
1309
+ return (0, _nepdatejs_core.toIsoDate)(date);
1310
+ }
1311
+ //#endregion
1312
+ exports.checkDate = checkDate;
1313
+ exports.createDatePicker = createDatePicker;
1314
+ exports.createDateRangePicker = createDateRangePicker;
1315
+ exports.createDateTimePicker = createDateTimePicker;
1316
+ exports.createMultiDatePicker = createMultiDatePicker;
1317
+ exports.equivalentText = equivalentText;
1318
+ exports.formatInput = formatInput;
1319
+ exports.maskDateText = maskDateText;
1320
+ exports.parseInput = parseInput;
1321
+ exports.placeholderText = placeholderText;
1322
+ exports.resolveRangePreset = resolveRangePreset;
1323
+ exports.resolveSinglePreset = resolveSinglePreset;
1324
+
1325
+ //# sourceMappingURL=index.cjs.map