@lilydesignsystem/angular-date-time-picker 0.2.0 → 0.2.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 CHANGED
@@ -10,7 +10,7 @@ order, 12- vs 24-hour clock and AM/PM names all come from `Intl`.
10
10
 
11
11
  Canonical contract: [spec/index.md](./spec/index.md). This package is the
12
12
  Angular port of the Svelte-canonical
13
- [`@lilydesignsystem/svelte-date-time-picker`](../../lily-design-system-svelte-helpers/lily-design-system-svelte-date-time-picker/).
13
+ [`@lilydesignsystem/svelte-date-time-picker`](../lily-design-system-svelte-date-time-picker/).
14
14
 
15
15
  ## Install
16
16
 
@@ -62,11 +62,11 @@ export class BookingComponent {
62
62
 
63
63
  ## The value is always ISO
64
64
 
65
- | `mode` | `value` |
66
- | ------ | ------- |
67
- | `"date"` (default) | `"2026-03-15"` |
68
- | `"time"` | `"09:30"` |
69
- | `"datetime"` | `"2026-03-15T09:30"` |
65
+ | `mode` | `value` |
66
+ | ------------------ | -------------------- |
67
+ | `"date"` (default) | `"2026-03-15"` |
68
+ | `"time"` | `"09:30"` |
69
+ | `"datetime"` | `"2026-03-15T09:30"` |
70
70
 
71
71
  Sortable as a string, unambiguous in every locale, and identical to what
72
72
  `<input type="date">` posts — so you can swap the native control in or out
@@ -193,10 +193,16 @@ once on open — hide it visually with your own CSS if you prefer.
193
193
  ### Replace the glyph
194
194
 
195
195
  ```html
196
- <lily-date-time-picker [label]="label" [labels]="labels">
197
- <ng-template lilyDateTimePickerIcon let-args>
196
+ <lily-date-time-picker
197
+ [label]="label"
198
+ [labels]="labels"
199
+ >
200
+ <ng-template
201
+ lilyDateTimePickerIcon
202
+ let-args
203
+ >
198
204
  <my-calendar-icon [expanded]="args.open" />
199
- <span class="visually-hidden">{{ args.display }}</span>
205
+ <span class="screen-reader-span">{{ args.display }}</span>
200
206
  </ng-template>
201
207
  </lily-date-time-picker>
202
208
  ```
@@ -269,13 +275,18 @@ nobody wants to page a calendar back forty years.
269
275
  - [`@lilydesignsystem/angular-locale-picker`](../lily-design-system-angular-locale-picker/)
270
276
  - [`@lilydesignsystem/angular-text-size-picker`](../lily-design-system-angular-text-size-picker/)
271
277
  - [`@lilydesignsystem/angular-share-picker`](../lily-design-system-angular-share-picker/)
272
- - [`@lilydesignsystem/svelte-date-time-picker`](../../lily-design-system-svelte-helpers/lily-design-system-svelte-date-time-picker/) — the canonical Svelte original.
278
+ - [`@lilydesignsystem/svelte-date-time-picker`](../lily-design-system-svelte-date-time-picker/) — the canonical Svelte original.
273
279
 
274
280
  ## License
275
281
 
276
282
  MIT or Apache-2.0 or GPL-2.0 or GPL-3.0 or BSD-3-Clause. Contact
277
283
  joel@joelparkerhenderson.com for other terms.
278
284
 
285
+ ## Known limitations
286
+
287
+ - **Week numbers are ISO 8601 only.** `showWeekNumbers` numbers weeks the ISO 8601 way: weeks start on Monday and week 1 is the week containing the year's first Thursday. Other systems are not available yet: the US, Canada and Japan number from a Sunday-first week containing 1 January, and some countries use a Saturday-first week. This is a documented gap against the worldwide target, not a decision; it is planned as `weekNumbering: "iso" | "us" | "locale"` (tasks.md P17-T4, worldwide audit (`spec/internationalization/worldwide-audit.md` in the monorepo) finding 4). Until then, leave week numbers off for an audience that does not use ISO weeks, or compute them yourself and show them in your own markup.
288
+ - **The column header is yours.** The visible header (`labels.week`) and any accessible name for a week number are supplied by the app, never English defaults, so you can label the column "Wk", "KW" or "Week (ISO)" and make it clear which system is shown.
289
+
279
290
  ---
280
291
 
281
292
  Lily™ and Lily Design System™ are trademarks.
@@ -1,7 +1,76 @@
1
1
  import { NgTemplateOutlet } from "@angular/common";
2
2
  import * as i0 from "@angular/core";
3
- import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Directive, TemplateRef, computed, contentChild, effect, inject, input, model, output, signal, viewChild } from "@angular/core";
3
+ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, Directive, TemplateRef, afterNextRender, computed, contentChild, effect, inject, input, model, output, signal, viewChild } from "@angular/core";
4
4
  import { IconButton } from "@lilydesignsystem/angular-headless";
5
+ const DAY_MS = 864e5;
6
+ const toMs = (iso) => Date.parse(`${iso}T00:00:00Z`);
7
+ const toIso = (ms) => new Date(ms).toISOString().slice(0, 10);
8
+ const shift = (iso, days) => toIso(toMs(iso) + days * DAY_MS);
9
+ const formatters = /* @__PURE__ */ new Map();
10
+ function dayFormatter(calendar) {
11
+ let formatter = formatters.get(calendar);
12
+ if (!formatter) {
13
+ formatter = new Intl.DateTimeFormat(`en-u-ca-${calendar}-nu-latn`, {
14
+ day: "numeric",
15
+ timeZone: "UTC"
16
+ });
17
+ formatters.set(calendar, formatter);
18
+ }
19
+ return formatter;
20
+ }
21
+ function calendarDay(iso, calendar = "gregory") {
22
+ const part = dayFormatter(calendar).formatToParts(new Date(toMs(iso))).find((p) => p.type === "day");
23
+ return Number(part?.value);
24
+ }
25
+ function calendarMonthStart(iso, calendar = "gregory") {
26
+ return shift(iso, 1 - calendarDay(iso, calendar));
27
+ }
28
+ function calendarMonthLength(start, calendar = "gregory") {
29
+ for (let length = 1; length < 40; length++) if (calendarDay(shift(start, length), calendar) === 1) return length;
30
+ throw new RangeError(`calendar-system: no month end after ${start} in ${calendar}`);
31
+ }
32
+ function calendarAddMonths(start, delta, calendar = "gregory") {
33
+ let month = start;
34
+ for (let i = 0; i < delta; i++) month = shift(month, calendarMonthLength(month, calendar));
35
+ for (let i = 0; i > delta; i--) month = calendarMonthStart(shift(month, -1), calendar);
36
+ return month;
37
+ }
38
+ function calendarMonthMatrix(start, firstDayOfWeek, calendar = "gregory") {
39
+ const weekday = new Date(toMs(start)).getUTCDay();
40
+ let date = shift(start, -((weekday - firstDayOfWeek + 7) % 7));
41
+ const rows = [];
42
+ for (let row = 0; row < 6; row++) {
43
+ const days = [];
44
+ for (let column = 0; column < 7; column++) {
45
+ days.push(date);
46
+ date = shift(date, 1);
47
+ }
48
+ rows.push(days);
49
+ }
50
+ return rows;
51
+ }
52
+ function calendarLocale(locale, calendar = "gregory") {
53
+ if (!locale) return locale;
54
+ try {
55
+ return new Intl.Locale(locale, { calendar }).toString();
56
+ } catch {
57
+ return locale;
58
+ }
59
+ }
60
+ function isRtl(element) {
61
+ if (!element) return false;
62
+ const attr = element.closest("[dir]")?.getAttribute("dir")?.toLowerCase();
63
+ if (attr === "rtl") return true;
64
+ if (attr === "ltr") return false;
65
+ if (typeof getComputedStyle === "function") return getComputedStyle(element).direction === "rtl";
66
+ return false;
67
+ }
68
+ function logicalKey(key, rtl) {
69
+ if (!rtl) return key;
70
+ if (key === "ArrowLeft") return "ArrowRight";
71
+ if (key === "ArrowRight") return "ArrowLeft";
72
+ return key;
73
+ }
5
74
  const CALENDAR = "📅︎";
6
75
  function pad(n, width = 2) {
7
76
  return String(Math.abs(n)).padStart(width, "0");
@@ -187,7 +256,7 @@ function monthMatrix(year, month, firstDayOfWeek) {
187
256
  function monthNames(locale) {
188
257
  const build = (month) => {
189
258
  try {
190
- const fmt = new Intl.DateTimeFormat(locale, {
259
+ const fmt = new Intl.DateTimeFormat(gregorian(locale), {
191
260
  month,
192
261
  timeZone: "UTC"
193
262
  });
@@ -217,7 +286,7 @@ function matchMonthName(token, names) {
217
286
  }
218
287
  function numericFieldOrder(locale) {
219
288
  try {
220
- const order = new Intl.DateTimeFormat(locale, {
289
+ const order = new Intl.DateTimeFormat(gregorian(locale), {
221
290
  day: "2-digit",
222
291
  month: "2-digit",
223
292
  year: "numeric",
@@ -232,7 +301,7 @@ function numericFieldOrder(locale) {
232
301
  ];
233
302
  }
234
303
  function parseDateInput(text, locale) {
235
- const trimmed = text.trim();
304
+ const trimmed = normalizeDigits(text).trim();
236
305
  if (!trimmed) return null;
237
306
  const iso = parseIsoDate(trimmed);
238
307
  if (iso) return formatIsoDate(iso);
@@ -272,8 +341,123 @@ function parseDateInput(text, locale) {
272
341
  day
273
342
  });
274
343
  }
275
- function parseTimeInput(text) {
276
- const m = /^(\d{1,2})[:.]?(\d{2})\s*([ap])\.?m\.?$|^(\d{1,2})[:.]?(\d{2})$/.exec(text.trim().toLowerCase());
344
+ function gregorian(locale) {
345
+ if (!locale) return locale;
346
+ try {
347
+ return new Intl.Locale(locale, { calendar: "gregory" }).toString();
348
+ } catch {
349
+ return locale;
350
+ }
351
+ }
352
+ const NATIVE_DIGITS = /* @__PURE__ */ new Map();
353
+ function nativeDigits() {
354
+ if (NATIVE_DIGITS.size > 0) return NATIVE_DIGITS;
355
+ for (const system of [
356
+ "adlm",
357
+ "ahom",
358
+ "arab",
359
+ "arabext",
360
+ "bali",
361
+ "beng",
362
+ "bhks",
363
+ "brah",
364
+ "cakm",
365
+ "cham",
366
+ "deva",
367
+ "fullwide",
368
+ "gong",
369
+ "gonm",
370
+ "gujr",
371
+ "guru",
372
+ "hanidec",
373
+ "hmng",
374
+ "hmnp",
375
+ "java",
376
+ "kali",
377
+ "kawi",
378
+ "khmr",
379
+ "knda",
380
+ "lana",
381
+ "lanatham",
382
+ "laoo",
383
+ "lepc",
384
+ "limb",
385
+ "mathbold",
386
+ "mathdbl",
387
+ "mathmono",
388
+ "mathsanb",
389
+ "mathsans",
390
+ "mlym",
391
+ "modi",
392
+ "mong",
393
+ "mroo",
394
+ "mtei",
395
+ "mymr",
396
+ "mymrshan",
397
+ "mymrtlng",
398
+ "nagm",
399
+ "newa",
400
+ "nkoo",
401
+ "olck",
402
+ "orya",
403
+ "osma",
404
+ "rohg",
405
+ "saur",
406
+ "segment",
407
+ "shrd",
408
+ "sind",
409
+ "sinh",
410
+ "sora",
411
+ "sund",
412
+ "takr",
413
+ "talu",
414
+ "tamldec",
415
+ "telu",
416
+ "thai",
417
+ "tibt",
418
+ "tirh",
419
+ "tnsa",
420
+ "vaii",
421
+ "wara",
422
+ "wcho"
423
+ ]) try {
424
+ const format = new Intl.NumberFormat(`en-u-nu-${system}`, { useGrouping: false });
425
+ for (let digit = 0; digit < 10; digit++) NATIVE_DIGITS.set(format.format(digit), String(digit));
426
+ } catch {}
427
+ return NATIVE_DIGITS;
428
+ }
429
+ function normalizeDigits(text) {
430
+ const map = nativeDigits();
431
+ return text.replace(/\p{Nd}/gu, (d) => map.get(d) ?? d);
432
+ }
433
+ function dayPeriodWords(locale) {
434
+ try {
435
+ const word = (hour) => new Intl.DateTimeFormat(locale, {
436
+ hour: "numeric",
437
+ hourCycle: "h12",
438
+ timeZone: "UTC"
439
+ }).formatToParts(new Date(Date.UTC(2021, 4, 6, hour))).find((p) => p.type === "dayPeriod")?.value.toLowerCase().replace(/[.\s\u00a0\u202f]/g, "") ?? "";
440
+ const am = word(9);
441
+ const pm = word(15);
442
+ return am && pm && am !== pm ? {
443
+ am,
444
+ pm
445
+ } : null;
446
+ } catch {
447
+ return null;
448
+ }
449
+ }
450
+ function parseTimeInput(text, locale) {
451
+ let typed = normalizeDigits(text).trim().toLowerCase();
452
+ const words = dayPeriodWords(locale);
453
+ if (words) {
454
+ const compact = typed.replace(/[.\s\u00a0\u202f]/g, "");
455
+ if (compact.endsWith(words.pm)) typed = `${compact.slice(0, -words.pm.length)} pm`;
456
+ else if (compact.endsWith(words.am)) typed = `${compact.slice(0, -words.am.length)} am`;
457
+ else if (compact.startsWith(words.pm)) typed = `${compact.slice(words.pm.length)} pm`;
458
+ else if (compact.startsWith(words.am)) typed = `${compact.slice(words.am.length)} am`;
459
+ }
460
+ const m = /^(\d{1,2})[:.]?(\d{2})\s*([ap])\.?m\.?$|^(\d{1,2})[:.]?(\d{2})$/.exec(typed);
277
461
  if (!m) return null;
278
462
  let hour = Number(m[1] ?? m[4]);
279
463
  const minute = Number(m[2] ?? m[5]);
@@ -316,7 +500,7 @@ var DateTimePickerIcon = class DateTimePickerIcon {
316
500
  static {
317
501
  this.ɵfac = i0.ɵɵngDeclareFactory({
318
502
  minVersion: "12.0.0",
319
- version: "22.2.1",
503
+ version: "22.2.4",
320
504
  ngImport: i0,
321
505
  type: DateTimePickerIcon,
322
506
  deps: [],
@@ -326,7 +510,7 @@ var DateTimePickerIcon = class DateTimePickerIcon {
326
510
  static {
327
511
  this.ɵdir = i0.ɵɵngDeclareDirective({
328
512
  minVersion: "14.0.0",
329
- version: "22.2.1",
513
+ version: "22.2.4",
330
514
  type: DateTimePickerIcon,
331
515
  isStandalone: true,
332
516
  selector: "ng-template[lilyDateTimePickerIcon]",
@@ -336,7 +520,7 @@ var DateTimePickerIcon = class DateTimePickerIcon {
336
520
  };
337
521
  i0.ɵɵngDeclareClassMetadata({
338
522
  minVersion: "12.0.0",
339
- version: "22.2.1",
523
+ version: "22.2.4",
340
524
  ngImport: i0,
341
525
  type: DateTimePickerIcon,
342
526
  decorators: [{
@@ -372,6 +556,7 @@ var DateTimePicker = class DateTimePicker {
372
556
  this.mode = input("date", ...ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []);
373
557
  this.value = model("", ...ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []);
374
558
  this.locale = input("", ...ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []);
559
+ this.calendar = input("gregory", ...ngDevMode ? [{ debugName: "calendar" }] : /* istanbul ignore next */ []);
375
560
  this.min = input("", ...ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []);
376
561
  this.max = input("", ...ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []);
377
562
  this.isDateDisabled = input(void 0, ...ngDevMode ? [{ debugName: "isDateDisabled" }] : /* istanbul ignore next */ []);
@@ -433,8 +618,7 @@ var DateTimePicker = class DateTimePicker {
433
618
  this.typed = signal(null, ...ngDevMode ? [{ debugName: "typed" }] : /* istanbul ignore next */ []);
434
619
  this.pendingDate = signal("", ...ngDevMode ? [{ debugName: "pendingDate" }] : /* istanbul ignore next */ []);
435
620
  this.pendingTime = signal("", ...ngDevMode ? [{ debugName: "pendingTime" }] : /* istanbul ignore next */ []);
436
- this.viewYear = signal(1970, ...ngDevMode ? [{ debugName: "viewYear" }] : /* istanbul ignore next */ []);
437
- this.viewMonth = signal(1, ...ngDevMode ? [{ debugName: "viewMonth" }] : /* istanbul ignore next */ []);
621
+ this.viewStart = signal("1970-01-01", ...ngDevMode ? [{ debugName: "viewStart" }] : /* istanbul ignore next */ []);
438
622
  this.cursor = signal("", ...ngDevMode ? [{ debugName: "cursor" }] : /* istanbul ignore next */ []);
439
623
  this.today = signal("", ...ngDevMode ? [{ debugName: "today" }] : /* istanbul ignore next */ []);
440
624
  this.fieldId = computed(() => this.inputId() || `${this.baseId}-input`, ...ngDevMode ? [{ debugName: "fieldId" }] : /* istanbul ignore next */ []);
@@ -455,16 +639,15 @@ var DateTimePicker = class DateTimePicker {
455
639
  return typeof Intl.supportedValuesOf === "function" ? Intl.supportedValuesOf("timeZone") : [];
456
640
  }, ...ngDevMode ? [{ debugName: "zoneOptions" }] : /* istanbul ignore next */ []);
457
641
  this.periodText = computed(() => {
458
- const viewYear = this.viewYear();
459
- const viewMonth = this.viewMonth();
642
+ const viewStart = this.viewStart();
460
643
  try {
461
- return new Intl.DateTimeFormat(this.locale() || void 0, {
644
+ return new Intl.DateTimeFormat(calendarLocale(this.locale() || void 0, this.calendar()), {
462
645
  month: "long",
463
646
  year: "numeric",
464
647
  timeZone: "UTC"
465
- }).format(new Date(Date.UTC(viewYear, viewMonth - 1, 1)));
648
+ }).format(/* @__PURE__ */ new Date(`${viewStart}T00:00:00Z`));
466
649
  } catch {
467
- return `${viewYear}-${pad(viewMonth)}`;
650
+ return viewStart.slice(0, 7);
468
651
  }
469
652
  }, ...ngDevMode ? [{ debugName: "periodText" }] : /* istanbul ignore next */ []);
470
653
  this.weekdays = computed(() => {
@@ -475,11 +658,11 @@ var DateTimePicker = class DateTimePicker {
475
658
  const d = new Date(Date.UTC(2021, 7, 1 + (weekStart + i) % 7));
476
659
  try {
477
660
  out.push({
478
- short: new Intl.DateTimeFormat(locale, {
661
+ short: new Intl.DateTimeFormat(gregorian(locale), {
479
662
  weekday: "short",
480
663
  timeZone: "UTC"
481
664
  }).format(d),
482
- long: new Intl.DateTimeFormat(locale, {
665
+ long: new Intl.DateTimeFormat(gregorian(locale), {
483
666
  weekday: "long",
484
667
  timeZone: "UTC"
485
668
  }).format(d)
@@ -493,7 +676,7 @@ var DateTimePicker = class DateTimePicker {
493
676
  }
494
677
  return out;
495
678
  }, ...ngDevMode ? [{ debugName: "weekdays" }] : /* istanbul ignore next */ []);
496
- this.weeks = computed(() => monthMatrix(this.viewYear(), this.viewMonth(), this.weekStart()), ...ngDevMode ? [{ debugName: "weeks" }] : /* istanbul ignore next */ []);
679
+ this.weeks = computed(() => calendarMonthMatrix(this.viewStart(), this.weekStart(), this.calendar()), ...ngDevMode ? [{ debugName: "weeks" }] : /* istanbul ignore next */ []);
497
680
  this.pendingHour = computed(() => parseIsoTime(this.pendingTime())?.hour ?? 0, ...ngDevMode ? [{ debugName: "pendingHour" }] : /* istanbul ignore next */ []);
498
681
  this.pendingMinute = computed(() => parseIsoTime(this.pendingTime())?.minute ?? 0, ...ngDevMode ? [{ debugName: "pendingMinute" }] : /* istanbul ignore next */ []);
499
682
  this.hourOptions = computed(() => {
@@ -535,11 +718,39 @@ var DateTimePicker = class DateTimePicker {
535
718
  this.today.set(today);
536
719
  const anchor = parseIsoDate(committed.date) ?? parseIsoDate(today);
537
720
  if (anchor) {
538
- this.viewYear.set(anchor.year);
539
- this.viewMonth.set(anchor.month);
721
+ this.viewStart.set(calendarMonthStart(formatIsoDate(anchor), this.calendar()));
540
722
  this.cursor.set(formatIsoDate(anchor));
541
723
  }
542
724
  });
725
+ const destroyRef = inject(DestroyRef);
726
+ afterNextRender(() => {
727
+ const root = this.rootRef().nativeElement;
728
+ const form = root.closest("form");
729
+ if (!form) return;
730
+ const initialValue = this.value();
731
+ const initialZone = this.timeZone();
732
+ let timer;
733
+ const onReset = (event) => {
734
+ clearTimeout(timer);
735
+ timer = setTimeout(() => {
736
+ if (event.defaultPrevented) return;
737
+ this.closeDialog(false);
738
+ this.typed.set(null);
739
+ this.invalid.set(false);
740
+ this.value.set(initialValue);
741
+ this.timeZone.set(initialZone);
742
+ const field = root.querySelector(".date-time-picker-input");
743
+ const formatter = this.formatValue() ?? ((v) => this.defaultFormat(v));
744
+ if (field) field.value = formatter(initialValue ?? "");
745
+ this.cdr.markForCheck();
746
+ }, 0);
747
+ };
748
+ form.addEventListener("reset", onReset);
749
+ destroyRef.onDestroy(() => {
750
+ clearTimeout(timer);
751
+ form.removeEventListener("reset", onReset);
752
+ });
753
+ });
543
754
  }
544
755
  pad2(n) {
545
756
  return pad(n);
@@ -548,17 +759,16 @@ var DateTimePicker = class DateTimePicker {
548
759
  return isoWeek(isoDate);
549
760
  }
550
761
  parseCell(isoDate) {
551
- const parsed = parseIsoDate(isoDate);
552
762
  return {
553
- day: parsed ? String(parsed.day) : "",
554
- outside: parsed ? parsed.month !== this.viewMonth() : false
763
+ day: parseIsoDate(isoDate) ? String(calendarDay(isoDate, this.calendar())) : "",
764
+ outside: isoDate < this.viewStart() || isoDate >= calendarAddMonths(this.viewStart(), 1, this.calendar())
555
765
  };
556
766
  }
557
767
  dayLabel(isoDate) {
558
768
  const parsed = parseIsoDate(isoDate);
559
769
  if (!parsed) return isoDate;
560
770
  try {
561
- return new Intl.DateTimeFormat(this.locale() || void 0, {
771
+ return new Intl.DateTimeFormat(calendarLocale(this.locale() || void 0, this.calendar()), {
562
772
  weekday: "long",
563
773
  day: "numeric",
564
774
  month: "long",
@@ -571,7 +781,7 @@ var DateTimePicker = class DateTimePicker {
571
781
  }
572
782
  dayPeriodName(pm) {
573
783
  try {
574
- const found = new Intl.DateTimeFormat(this.locale() || void 0, {
784
+ const found = new Intl.DateTimeFormat(gregorian(this.locale() || void 0), {
575
785
  hour: "numeric",
576
786
  hour12: true,
577
787
  timeZone: "UTC"
@@ -584,7 +794,7 @@ var DateTimePicker = class DateTimePicker {
584
794
  const parsed = parseIsoTime(isoTime);
585
795
  if (!parsed) return isoTime;
586
796
  try {
587
- return new Intl.DateTimeFormat(this.locale() || void 0, {
797
+ return new Intl.DateTimeFormat(gregorian(this.locale() || void 0), {
588
798
  hour: "2-digit",
589
799
  minute: "2-digit",
590
800
  hour12: this.clock12(),
@@ -600,7 +810,7 @@ var DateTimePicker = class DateTimePicker {
600
810
  const chunks = [];
601
811
  const parsed = date ? parseIsoDate(date) : null;
602
812
  if (parsed) try {
603
- chunks.push(new Intl.DateTimeFormat(this.locale() || void 0, {
813
+ chunks.push(new Intl.DateTimeFormat(gregorian(this.locale() || void 0), {
604
814
  day: "2-digit",
605
815
  month: "short",
606
816
  year: "numeric",
@@ -637,10 +847,7 @@ var DateTimePicker = class DateTimePicker {
637
847
  this.pendingTime.set(this.committed().time || this.defaultTime());
638
848
  this.cursor.set(pendingDate);
639
849
  const anchor = parseIsoDate(pendingDate) ?? parseIsoDate(today);
640
- if (anchor) {
641
- this.viewYear.set(anchor.year);
642
- this.viewMonth.set(anchor.month);
643
- }
850
+ if (anchor) this.viewStart.set(calendarMonthStart(formatIsoDate(anchor), this.calendar()));
644
851
  this.open.set(true);
645
852
  this.cdr.detectChanges();
646
853
  this.focusInitial();
@@ -693,10 +900,7 @@ var DateTimePicker = class DateTimePicker {
693
900
  if (!withinRange(nextIso, this.min() || void 0, this.max() || void 0)) return;
694
901
  this.cursor.set(nextIso);
695
902
  const parsed = parseIsoDate(nextIso);
696
- if (parsed && (parsed.year !== this.viewYear() || parsed.month !== this.viewMonth())) {
697
- this.viewYear.set(parsed.year);
698
- this.viewMonth.set(parsed.month);
699
- }
903
+ if (parsed) this.viewStart.set(calendarMonthStart(formatIsoDate(parsed), this.calendar()));
700
904
  this.cdr.detectChanges();
701
905
  this.focusCursor();
702
906
  }
@@ -715,22 +919,12 @@ var DateTimePicker = class DateTimePicker {
715
919
  if (this.commitOnDay()) this.commit();
716
920
  }
717
921
  shiftMonth(delta) {
718
- const next = parseIsoDate(addMonths(formatIsoDate({
719
- year: this.viewYear(),
720
- month: this.viewMonth(),
721
- day: 1
722
- }), delta));
723
- if (!next) return;
922
+ const next = calendarAddMonths(this.viewStart(), delta, this.calendar());
724
923
  const hadGridFocus = this.gridRef()?.nativeElement.contains(document.activeElement) === true;
725
- this.viewYear.set(next.year);
726
- this.viewMonth.set(next.month);
924
+ this.viewStart.set(next);
727
925
  const c = parseIsoDate(this.cursor());
728
926
  if (c) {
729
- this.cursor.set(formatIsoDate({
730
- year: next.year,
731
- month: next.month,
732
- day: Math.min(c.day, daysInMonth(next.year, next.month))
733
- }));
927
+ this.cursor.set(addDays(next, Math.min(calendarDay(formatIsoDate(c), this.calendar()), calendarMonthLength(next, this.calendar())) - 1));
734
928
  if (hadGridFocus) {
735
929
  this.cdr.detectChanges();
736
930
  this.focusCursor();
@@ -747,10 +941,7 @@ var DateTimePicker = class DateTimePicker {
747
941
  if (!withinRange(next, this.min() || void 0, this.max() || void 0)) return;
748
942
  const hadGridFocus = this.gridRef()?.nativeElement.contains(document.activeElement) === true;
749
943
  const parsed = parseIsoDate(next);
750
- if (parsed && (parsed.year !== this.viewYear() || parsed.month !== this.viewMonth())) {
751
- this.viewYear.set(parsed.year);
752
- this.viewMonth.set(parsed.month);
753
- }
944
+ if (parsed) this.viewStart.set(calendarMonthStart(formatIsoDate(parsed), this.calendar()));
754
945
  this.cursor.set(next);
755
946
  if (!this.dayDisabled(next)) this.pendingDate.set(next);
756
947
  if (hadGridFocus) {
@@ -765,7 +956,7 @@ var DateTimePicker = class DateTimePicker {
765
956
  return this.timeZoneLabels()[zone] ?? zone;
766
957
  }
767
958
  onGridKeydown(event) {
768
- switch (event.key) {
959
+ switch (logicalKey(event.key, isRtl(this.gridRef()?.nativeElement))) {
769
960
  case "ArrowLeft":
770
961
  event.preventDefault();
771
962
  this.moveCursor(addDays(this.cursor(), -1));
@@ -837,12 +1028,12 @@ var DateTimePicker = class DateTimePicker {
837
1028
  }
838
1029
  }
839
1030
  parseTypedForMode(text) {
840
- if (this.mode() === "time") return parseTimeInput(text);
1031
+ if (this.mode() === "time") return parseTimeInput(text, this.locale() || void 0);
841
1032
  if (this.mode() === "date") return parseDateInput(text, this.locale() || void 0);
842
1033
  const m = /^(.*?)[T\s]+([^\sT]+)$/.exec(text.trim());
843
1034
  if (!m) return null;
844
1035
  const date = parseDateInput(m[1], this.locale() || void 0);
845
- const time = parseTimeInput(m[2]);
1036
+ const time = parseTimeInput(m[2], this.locale() || void 0);
846
1037
  return date && time ? `${date}T${time}` : null;
847
1038
  }
848
1039
  resolveTyped() {
@@ -915,10 +1106,7 @@ var DateTimePicker = class DateTimePicker {
915
1106
  this.pendingDate.set(target);
916
1107
  this.cursor.set(target);
917
1108
  const parsed = parseIsoDate(target);
918
- if (parsed) {
919
- this.viewYear.set(parsed.year);
920
- this.viewMonth.set(parsed.month);
921
- }
1109
+ if (parsed) this.viewStart.set(calendarMonthStart(formatIsoDate(parsed), this.calendar()));
922
1110
  this.shortcut.emit({
923
1111
  id: shortcut.id,
924
1112
  isoDate: target
@@ -939,7 +1127,7 @@ var DateTimePicker = class DateTimePicker {
939
1127
  static {
940
1128
  this.ɵfac = i0.ɵɵngDeclareFactory({
941
1129
  minVersion: "12.0.0",
942
- version: "22.2.1",
1130
+ version: "22.2.4",
943
1131
  ngImport: i0,
944
1132
  type: DateTimePicker,
945
1133
  deps: [],
@@ -949,7 +1137,7 @@ var DateTimePicker = class DateTimePicker {
949
1137
  static {
950
1138
  this.ɵcmp = i0.ɵɵngDeclareComponent({
951
1139
  minVersion: "17.0.0",
952
- version: "22.2.1",
1140
+ version: "22.2.4",
953
1141
  type: DateTimePicker,
954
1142
  isStandalone: true,
955
1143
  selector: "lily-date-time-picker",
@@ -989,6 +1177,13 @@ var DateTimePicker = class DateTimePicker {
989
1177
  isRequired: false,
990
1178
  transformFunction: null
991
1179
  },
1180
+ calendar: {
1181
+ classPropertyName: "calendar",
1182
+ publicName: "calendar",
1183
+ isSignal: true,
1184
+ isRequired: false,
1185
+ transformFunction: null
1186
+ },
992
1187
  min: {
993
1188
  classPropertyName: "min",
994
1189
  publicName: "min",
@@ -1612,7 +1807,7 @@ var DateTimePicker = class DateTimePicker {
1612
1807
  };
1613
1808
  i0.ɵɵngDeclareClassMetadata({
1614
1809
  minVersion: "12.0.0",
1615
- version: "22.2.1",
1810
+ version: "22.2.4",
1616
1811
  ngImport: i0,
1617
1812
  type: DateTimePicker,
1618
1813
  decorators: [{
@@ -2061,6 +2256,14 @@ i0.ɵɵngDeclareClassMetadata({
2061
2256
  required: false
2062
2257
  }]
2063
2258
  }],
2259
+ calendar: [{
2260
+ type: i0.Input,
2261
+ args: [{
2262
+ isSignal: true,
2263
+ alias: "calendar",
2264
+ required: false
2265
+ }]
2266
+ }],
2064
2267
  min: [{
2065
2268
  type: i0.Input,
2066
2269
  args: [{
@@ -2274,6 +2477,6 @@ i0.ɵɵngDeclareClassMetadata({
2274
2477
  }]
2275
2478
  }
2276
2479
  });
2277
- export { CALENDAR, DateTimePicker, DateTimePickerIcon, addDays, addMonths, daysInMonth, firstDayOfWeekFor, formatIsoDate, formatIsoTime, fromEpochDay, isoWeek, joinValue, monthMatrix, monthNames, nextDateTimePickerId, numericFieldOrder, pad, parseDateInput, parseIsoDate, parseIsoTime, parseTimeInput, splitValue, toEpochDay, weekdayOf, withinRange };
2480
+ export { CALENDAR, DateTimePicker, DateTimePickerIcon, addDays, addMonths, daysInMonth, firstDayOfWeekFor, formatIsoDate, formatIsoTime, fromEpochDay, gregorian, isoWeek, joinValue, monthMatrix, monthNames, nextDateTimePickerId, normalizeDigits, numericFieldOrder, pad, parseDateInput, parseIsoDate, parseIsoTime, parseTimeInput, splitValue, toEpochDay, weekdayOf, withinRange };
2278
2481
 
2279
2482
  //# sourceMappingURL=lilydesignsystem-angular-date-time-picker.mjs.map