@nanahoshi/mona-ui 0.24.4 → 0.24.6

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.
Files changed (80) hide show
  1. package/README.md +3 -0
  2. package/fesm2022/nanahoshi-mona-ui-auto-complete.mjs +95 -70
  3. package/fesm2022/nanahoshi-mona-ui-calendar.mjs +196 -137
  4. package/fesm2022/nanahoshi-mona-ui-combo-box.mjs +136 -89
  5. package/fesm2022/nanahoshi-mona-ui-date-input.mjs +164 -3
  6. package/fesm2022/nanahoshi-mona-ui-date-picker.mjs +124 -140
  7. package/fesm2022/nanahoshi-mona-ui-datetime-picker.mjs +205 -202
  8. package/fesm2022/nanahoshi-mona-ui-dropdown-list.mjs +108 -56
  9. package/fesm2022/nanahoshi-mona-ui-dropdowns.mjs +68 -59
  10. package/fesm2022/nanahoshi-mona-ui-editor.mjs +3 -3
  11. package/fesm2022/nanahoshi-mona-ui-filter.mjs +1 -1
  12. package/fesm2022/{nanahoshi-mona-ui-grid-grid-footer-row.component-DLOPRuFv.mjs → nanahoshi-mona-ui-grid-grid-footer-row.component-CD_ODHpU.mjs} +2 -2
  13. package/fesm2022/{nanahoshi-mona-ui-grid-grid-list.component-Dw5U9H0a.mjs → nanahoshi-mona-ui-grid-grid-list.component-0jN7I1jo.mjs} +4 -4
  14. package/fesm2022/{nanahoshi-mona-ui-grid-grid-row.component-D1kyAzD8.mjs → nanahoshi-mona-ui-grid-grid-row.component-BI_iE7pl.mjs} +3 -3
  15. package/fesm2022/{nanahoshi-mona-ui-grid-grid-virtual-list.component-ECK1_smx.mjs → nanahoshi-mona-ui-grid-grid-virtual-list.component-Sa1aAtJ-.mjs} +4 -4
  16. package/fesm2022/{nanahoshi-mona-ui-grid-nanahoshi-mona-ui-grid-D4lUDbfx.mjs → nanahoshi-mona-ui-grid-nanahoshi-mona-ui-grid-BvUM9nPt.mjs} +8 -8
  17. package/fesm2022/nanahoshi-mona-ui-grid.mjs +1 -1
  18. package/fesm2022/nanahoshi-mona-ui-i18n-icu.mjs +2 -1
  19. package/fesm2022/nanahoshi-mona-ui-internal-indicator-icon.mjs +2 -2
  20. package/fesm2022/nanahoshi-mona-ui-internal.mjs +4 -2
  21. package/fesm2022/nanahoshi-mona-ui-locales-ar-sa.mjs +2 -1
  22. package/fesm2022/nanahoshi-mona-ui-locales-de-de.mjs +4 -1
  23. package/fesm2022/nanahoshi-mona-ui-locales-es-es.mjs +4 -1
  24. package/fesm2022/nanahoshi-mona-ui-locales-fr-fr.mjs +4 -1
  25. package/fesm2022/nanahoshi-mona-ui-locales-id-id.mjs +2 -1
  26. package/fesm2022/nanahoshi-mona-ui-locales-it-it.mjs +2 -1
  27. package/fesm2022/nanahoshi-mona-ui-locales-ja-jp.mjs +2 -1
  28. package/fesm2022/nanahoshi-mona-ui-locales-ko-kr.mjs +2 -1
  29. package/fesm2022/nanahoshi-mona-ui-locales-pt-br.mjs +2 -1
  30. package/fesm2022/nanahoshi-mona-ui-locales-ru-ru.mjs +2 -1
  31. package/fesm2022/nanahoshi-mona-ui-locales-tr-tr.mjs +2 -1
  32. package/fesm2022/nanahoshi-mona-ui-locales-zh-cn.mjs +2 -1
  33. package/fesm2022/nanahoshi-mona-ui-locales-zh-tw.mjs +2 -1
  34. package/fesm2022/nanahoshi-mona-ui-multi-select.mjs +118 -66
  35. package/fesm2022/nanahoshi-mona-ui-numeric-text-box.mjs +195 -122
  36. package/fesm2022/nanahoshi-mona-ui-pager.mjs +1 -1
  37. package/fesm2022/nanahoshi-mona-ui-time-picker.mjs +149 -167
  38. package/fesm2022/nanahoshi-mona-ui-time-selector.mjs +182 -137
  39. package/i18n/catalogs/en-US.messages.json +2 -1
  40. package/locales/ar-sa/ar-sa.messages.json +2 -1
  41. package/locales/de-de/de-de.messages.json +2 -1
  42. package/locales/es-es/es-es.messages.json +2 -1
  43. package/locales/fr-fr/fr-fr.messages.json +2 -1
  44. package/locales/id-id/id-id.messages.json +2 -1
  45. package/locales/it-it/it-it.messages.json +2 -1
  46. package/locales/ja-jp/ja-jp.messages.json +2 -1
  47. package/locales/ko-kr/ko-kr.messages.json +2 -1
  48. package/locales/pt-br/pt-br.messages.json +2 -1
  49. package/locales/ru-ru/ru-ru.messages.json +2 -1
  50. package/locales/tr-tr/tr-tr.messages.json +2 -1
  51. package/locales/zh-cn/zh-cn.messages.json +2 -1
  52. package/locales/zh-tw/zh-tw.messages.json +2 -1
  53. package/package.json +2 -2
  54. package/types/nanahoshi-mona-ui-auto-complete.d.ts +34 -20
  55. package/types/nanahoshi-mona-ui-calendar.d.ts +30 -11
  56. package/types/nanahoshi-mona-ui-combo-box.d.ts +42 -23
  57. package/types/nanahoshi-mona-ui-date-input.d.ts +74 -3
  58. package/types/nanahoshi-mona-ui-date-picker.d.ts +61 -33
  59. package/types/nanahoshi-mona-ui-datetime-picker.d.ts +79 -38
  60. package/types/nanahoshi-mona-ui-dropdown-list.d.ts +29 -15
  61. package/types/nanahoshi-mona-ui-dropdowns.d.ts +30 -19
  62. package/types/nanahoshi-mona-ui-i18n.d.ts +1 -0
  63. package/types/nanahoshi-mona-ui-internal.d.ts +3 -1
  64. package/types/nanahoshi-mona-ui-locales-ar-sa.d.ts +1 -0
  65. package/types/nanahoshi-mona-ui-locales-de-de.d.ts +1 -0
  66. package/types/nanahoshi-mona-ui-locales-es-es.d.ts +1 -0
  67. package/types/nanahoshi-mona-ui-locales-fr-fr.d.ts +1 -0
  68. package/types/nanahoshi-mona-ui-locales-id-id.d.ts +1 -0
  69. package/types/nanahoshi-mona-ui-locales-it-it.d.ts +1 -0
  70. package/types/nanahoshi-mona-ui-locales-ja-jp.d.ts +1 -0
  71. package/types/nanahoshi-mona-ui-locales-ko-kr.d.ts +1 -0
  72. package/types/nanahoshi-mona-ui-locales-pt-br.d.ts +1 -0
  73. package/types/nanahoshi-mona-ui-locales-ru-ru.d.ts +1 -0
  74. package/types/nanahoshi-mona-ui-locales-tr-tr.d.ts +1 -0
  75. package/types/nanahoshi-mona-ui-locales-zh-cn.d.ts +1 -0
  76. package/types/nanahoshi-mona-ui-locales-zh-tw.d.ts +1 -0
  77. package/types/nanahoshi-mona-ui-multi-select.d.ts +45 -21
  78. package/types/nanahoshi-mona-ui-numeric-text-box.d.ts +57 -16
  79. package/types/nanahoshi-mona-ui-time-picker.d.ts +72 -42
  80. package/types/nanahoshi-mona-ui-time-selector.d.ts +78 -46
@@ -1,9 +1,9 @@
1
1
  import { NgTemplateOutlet } from '@angular/common';
2
2
  import * as i0 from '@angular/core';
3
- import { inject, TemplateRef, Directive, computed, input, output, DestroyRef, ElementRef, signal, contentChild, linkedSignal, model, afterNextRender, effect, untracked, Component } from '@angular/core';
3
+ import { inject, TemplateRef, Directive, computed, input, output, DestroyRef, ElementRef, signal, contentChild, linkedSignal, booleanAttribute, model, afterNextRender, effect, untracked, Component } from '@angular/core';
4
4
  import { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
5
5
  import { LucideChevronLeft, LucideChevronRight } from '@lucide/angular';
6
- import { any, exactly, Dictionary, lastOrDefault, range, index, select } from '@mirei/ts-collections';
6
+ import { Dictionary, lastOrDefault, range, index, select } from '@mirei/ts-collections';
7
7
  import { ButtonDirective } from '@nanahoshi/mona-ui/button';
8
8
  import { PreventableEvent, TakeFirstPipe } from '@nanahoshi/mona-ui/common';
9
9
  import { CalendarService } from '@nanahoshi/mona-ui/date-input';
@@ -11,7 +11,7 @@ import { themeRaisedBackdropClasses, createElementControlId, rxTimeout } from '@
11
11
  import { DateTime } from 'luxon';
12
12
  import { skip, fromEvent } from 'rxjs';
13
13
  import { twMerge } from 'tailwind-merge';
14
- import { formatNumber, MonaI18nService, injectComponentDirection, gregorianDateTime, formatGregorianDateToLocaleString, getLocaleFirstDayOfWeek, gregorianDateTimeFromObject } from '@nanahoshi/mona-ui/i18n';
14
+ import { formatNumber, MonaI18nService, formatGregorianDateToLocaleString, injectComponentDirection, gregorianDateTime, getLocaleFirstDayOfWeek, gregorianDateTimeFromObject } from '@nanahoshi/mona-ui/i18n';
15
15
  import { cva } from 'class-variance-authority';
16
16
 
17
17
  // Generated from i18n/catalogs/en-US.messages.json by scripts/generate-locale-catalogs.ts. Do not edit.
@@ -212,10 +212,10 @@ const calendarDecadeViewCellThemeVariants = cva(`
212
212
  }
213
213
  });
214
214
 
215
+ /** One year of the decade view: a grid cell. */
215
216
  class DecadeYearDirective {
216
217
  constructor() {
217
218
  this.#i18n = inject(MonaI18nService);
218
- this.messages = this.#i18n.componentMessages("calendar", CALENDAR_DEFAULT_MESSAGES);
219
219
  this.ariaLabel = computed(() => this.messages().yearCellLabel(this.year()), /* @ts-ignore */
220
220
  ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
221
221
  this.baseClass = computed(() => {
@@ -233,6 +233,7 @@ class DecadeYearDirective {
233
233
  return this.year() === DateTime.now().year;
234
234
  }, /* @ts-ignore */
235
235
  ...(ngDevMode ? [{ debugName: "isCurrent" }] : /* istanbul ignore next */ []));
236
+ this.messages = this.#i18n.componentMessages("calendar", CALENDAR_DEFAULT_MESSAGES);
236
237
  this.selected = computed(() => {
237
238
  const selectedDate = this.selectedDate();
238
239
  if (!selectedDate) {
@@ -241,6 +242,9 @@ class DecadeYearDirective {
241
242
  return this.year() === DateTime.fromJSDate(selectedDate).year;
242
243
  }, /* @ts-ignore */
243
244
  ...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
245
+ /** Whether the whole calendar is disabled. */
246
+ this.disabled = input(false, /* @ts-ignore */
247
+ ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
244
248
  this.navigatedDate = input.required(/* @ts-ignore */
245
249
  ...(ngDevMode ? [{ debugName: "navigatedDate" }] : /* istanbul ignore next */ []));
246
250
  this.rounded = input.required(/* @ts-ignore */
@@ -252,22 +256,23 @@ class DecadeYearDirective {
252
256
  }
253
257
  #i18n;
254
258
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: DecadeYearDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
255
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.6", type: DecadeYearDirective, isStandalone: true, selector: "[monaDecadeYear]", inputs: { navigatedDate: { classPropertyName: "navigatedDate", publicName: "navigatedDate", isSignal: true, isRequired: true, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: true, transformFunction: null }, selectedDate: { classPropertyName: "selectedDate", publicName: "selectedDate", isSignal: true, isRequired: false, transformFunction: null }, year: { classPropertyName: "year", publicName: "year", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "role": "gridcell" }, properties: { "attr.tabindex": "focused() ? 0 : -1", "attr.aria-current": "isCurrent() ? 'true' : null", "attr.aria-label": "ariaLabel()", "attr.aria-selected": "selected() ? 'true' : null", "class": "baseClass()" } }, ngImport: i0 }); }
259
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.6", type: DecadeYearDirective, isStandalone: true, selector: "[monaDecadeYear]", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, navigatedDate: { classPropertyName: "navigatedDate", publicName: "navigatedDate", isSignal: true, isRequired: true, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: true, transformFunction: null }, selectedDate: { classPropertyName: "selectedDate", publicName: "selectedDate", isSignal: true, isRequired: false, transformFunction: null }, year: { classPropertyName: "year", publicName: "year", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "role": "gridcell" }, properties: { "attr.tabindex": "focused() && !disabled() ? 0 : -1", "attr.aria-current": "isCurrent() ? 'true' : null", "attr.aria-disabled": "disabled() ? 'true' : null", "attr.aria-label": "ariaLabel()", "attr.aria-selected": "selected() ? 'true' : null", "class": "baseClass()" } }, ngImport: i0 }); }
256
260
  }
257
261
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: DecadeYearDirective, decorators: [{
258
262
  type: Directive,
259
263
  args: [{
260
264
  selector: "[monaDecadeYear]",
261
265
  host: {
262
- "[attr.tabindex]": "focused() ? 0 : -1",
266
+ "[attr.tabindex]": "focused() && !disabled() ? 0 : -1",
263
267
  "[attr.aria-current]": "isCurrent() ? 'true' : null",
268
+ "[attr.aria-disabled]": "disabled() ? 'true' : null",
264
269
  "[attr.aria-label]": "ariaLabel()",
265
270
  "[attr.aria-selected]": "selected() ? 'true' : null",
266
271
  "[class]": "baseClass()",
267
272
  role: "gridcell"
268
273
  }
269
274
  }]
270
- }], propDecorators: { navigatedDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "navigatedDate", required: true }] }], rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: true }] }], selectedDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedDate", required: false }] }], year: [{ type: i0.Input, args: [{ isSignal: true, alias: "year", required: true }] }] } });
275
+ }], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], navigatedDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "navigatedDate", required: true }] }], rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: true }] }], selectedDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedDate", required: false }] }], year: [{ type: i0.Input, args: [{ isSignal: true, alias: "year", required: true }] }] } });
271
276
 
272
277
  const compareDates = (date1, date2, operator) => {
273
278
  if (!date1 || !date2) {
@@ -309,9 +314,25 @@ const compareDates = (date1, date2, operator) => {
309
314
  }
310
315
  return operator === "==";
311
316
  };
317
+ /** A key that is equal for two dates on the same local calendar day, whatever their time. */
318
+ const toDayKey = (date) => `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
312
319
 
320
+ /**
321
+ * One day of the month view: a grid cell named by its full date ("Tuesday, November 4, 2026"). The calendar passes
322
+ * the selection and the range preview as sets of day keys, so each cell answers in constant time.
323
+ */
313
324
  class MonthDayDirective {
314
325
  constructor() {
326
+ this.#i18n = inject(MonaI18nService);
327
+ this.#key = computed(() => toDayKey(this.entry().key), /* @ts-ignore */
328
+ ...(ngDevMode ? [{ debugName: "#key" }] : /* istanbul ignore next */ []));
329
+ this.ariaLabel = computed(() => formatGregorianDateToLocaleString(this.entry().key, this.#i18n.localeId(), {
330
+ weekday: "long",
331
+ year: "numeric",
332
+ month: "long",
333
+ day: "numeric"
334
+ }), /* @ts-ignore */
335
+ ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
315
336
  this.baseClass = computed(() => {
316
337
  const disabled = this.dayDisabled();
317
338
  const focused = this.focused();
@@ -331,33 +352,11 @@ class MonthDayDirective {
331
352
  });
332
353
  }, /* @ts-ignore */
333
354
  ...(ngDevMode ? [{ debugName: "baseClass" }] : /* istanbul ignore next */ []));
334
- this.dayDisabled = computed(() => {
335
- const disabled = this.disabled();
336
- const entry = this.entry();
337
- const disabledDates = this.disabledDates();
338
- const max = this.max();
339
- const min = this.min();
340
- let isDisabledByInput = false;
341
- if (typeof disabledDates === "function") {
342
- isDisabledByInput = disabledDates(entry.key);
343
- }
344
- else if (disabledDates) {
345
- isDisabledByInput = any(disabledDates, d => compareDates(entry.key, d, "=="));
346
- }
347
- return disabled || isDisabledByInput || compareDates(entry.key, max, ">") || compareDates(entry.key, min, "<");
348
- }, /* @ts-ignore */
355
+ this.dayDisabled = computed(() => this.disabled() || this.isDayUnavailable()(this.entry().key), /* @ts-ignore */
349
356
  ...(ngDevMode ? [{ debugName: "dayDisabled" }] : /* istanbul ignore next */ []));
350
- this.focused = computed(() => {
351
- const entry = this.entry();
352
- const navigatedDate = this.navigatedDate();
353
- return compareDates(entry.key, navigatedDate, "==");
354
- }, /* @ts-ignore */
357
+ this.focused = computed(() => compareDates(this.entry().key, this.navigatedDate(), "=="), /* @ts-ignore */
355
358
  ...(ngDevMode ? [{ debugName: "focused" }] : /* istanbul ignore next */ []));
356
- this.isToday = computed(() => {
357
- const entry = this.entry();
358
- const today = new Date();
359
- return compareDates(entry.key, today, "==");
360
- }, /* @ts-ignore */
359
+ this.isToday = computed(() => compareDates(this.entry().key, this.today(), "=="), /* @ts-ignore */
361
360
  ...(ngDevMode ? [{ debugName: "isToday" }] : /* istanbul ignore next */ []));
362
361
  this.outside = computed(() => {
363
362
  const entry = this.entry();
@@ -366,43 +365,35 @@ class MonthDayDirective {
366
365
  return compareDates(entry.key, monthStart, "<") || compareDates(entry.key, monthEnd, ">");
367
366
  }, /* @ts-ignore */
368
367
  ...(ngDevMode ? [{ debugName: "outside" }] : /* istanbul ignore next */ []));
369
- this.rangePreviewed = computed(() => {
370
- const entry = this.entry();
371
- return !this.selected() && exactly(this.rangePreview(), 1, d => compareDates(entry.key, d, "=="));
372
- }, /* @ts-ignore */
368
+ this.rangePreviewed = computed(() => !this.selected() && this.rangePreviewKeys().has(this.#key()), /* @ts-ignore */
373
369
  ...(ngDevMode ? [{ debugName: "rangePreviewed" }] : /* istanbul ignore next */ []));
374
- this.selected = computed(() => {
375
- const entry = this.entry();
376
- const value = this.value();
377
- if (Array.isArray(value)) {
378
- return exactly(value, 1, d => compareDates(entry.key, d, "=="));
379
- }
380
- return compareDates(entry.key, value, "==");
381
- }, /* @ts-ignore */
370
+ this.selected = computed(() => this.selectedKeys().has(this.#key()), /* @ts-ignore */
382
371
  ...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
383
372
  this.dayPointerEnter = output();
384
373
  this.daySelect = output();
374
+ /** Whether the whole calendar is disabled. */
385
375
  this.disabled = input.required(/* @ts-ignore */
386
376
  ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
387
- this.disabledDates = input.required(/* @ts-ignore */
388
- ...(ngDevMode ? [{ debugName: "disabledDates" }] : /* istanbul ignore next */ []));
389
377
  this.entry = input.required(/* @ts-ignore */
390
378
  ...(ngDevMode ? [{ debugName: "entry" }] : /* istanbul ignore next */ []));
391
- this.max = input.required(/* @ts-ignore */
392
- ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
393
- this.min = input.required(/* @ts-ignore */
394
- ...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
379
+ /** Whether a day can't be picked: out of range or in `disabledDates`. */
380
+ this.isDayUnavailable = input.required(/* @ts-ignore */
381
+ ...(ngDevMode ? [{ debugName: "isDayUnavailable" }] : /* istanbul ignore next */ []));
395
382
  this.monthBounds = input.required(/* @ts-ignore */
396
383
  ...(ngDevMode ? [{ debugName: "monthBounds" }] : /* istanbul ignore next */ []));
397
384
  this.navigatedDate = input.required(/* @ts-ignore */
398
385
  ...(ngDevMode ? [{ debugName: "navigatedDate" }] : /* istanbul ignore next */ []));
399
- this.rangePreview = input.required(/* @ts-ignore */
400
- ...(ngDevMode ? [{ debugName: "rangePreview" }] : /* istanbul ignore next */ []));
386
+ this.rangePreviewKeys = input.required(/* @ts-ignore */
387
+ ...(ngDevMode ? [{ debugName: "rangePreviewKeys" }] : /* istanbul ignore next */ []));
401
388
  this.rounded = input.required(/* @ts-ignore */
402
389
  ...(ngDevMode ? [{ debugName: "rounded" }] : /* istanbul ignore next */ []));
403
- this.value = input.required(/* @ts-ignore */
404
- ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
390
+ this.selectedKeys = input.required(/* @ts-ignore */
391
+ ...(ngDevMode ? [{ debugName: "selectedKeys" }] : /* istanbul ignore next */ []));
392
+ this.today = input.required(/* @ts-ignore */
393
+ ...(ngDevMode ? [{ debugName: "today" }] : /* istanbul ignore next */ []));
405
394
  }
395
+ #i18n;
396
+ #key;
406
397
  onClick(event) {
407
398
  if (this.dayDisabled()) {
408
399
  return;
@@ -417,31 +408,34 @@ class MonthDayDirective {
417
408
  this.dayPointerEnter.emit(this.entry().key);
418
409
  }
419
410
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: MonthDayDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
420
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.6", type: MonthDayDirective, isStandalone: true, selector: "[monaMonthDay]", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: true, transformFunction: null }, disabledDates: { classPropertyName: "disabledDates", publicName: "disabledDates", isSignal: true, isRequired: true, transformFunction: null }, entry: { classPropertyName: "entry", publicName: "entry", isSignal: true, isRequired: true, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: true, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: true, transformFunction: null }, monthBounds: { classPropertyName: "monthBounds", publicName: "monthBounds", isSignal: true, isRequired: true, transformFunction: null }, navigatedDate: { classPropertyName: "navigatedDate", publicName: "navigatedDate", isSignal: true, isRequired: true, transformFunction: null }, rangePreview: { classPropertyName: "rangePreview", publicName: "rangePreview", isSignal: true, isRequired: true, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { dayPointerEnter: "dayPointerEnter", daySelect: "daySelect" }, host: { attributes: { "role": "button" }, listeners: { "click": "onClick($event)", "pointerenter": "onPointerEnter()" }, properties: { "attr.tabindex": "focused() ? 0 : -1", "attr.aria-pressed": "selected() ? 'true' : 'false'", "attr.aria-current": "isToday() ? 'date' : null", "attr.aria-disabled": "dayDisabled() ? 'true' : null", "attr.data-range-preview": "rangePreviewed() ? 'true' : null", "class": "baseClass()" } }, ngImport: i0 }); }
411
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.6", type: MonthDayDirective, isStandalone: true, selector: "[monaMonthDay]", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: true, transformFunction: null }, entry: { classPropertyName: "entry", publicName: "entry", isSignal: true, isRequired: true, transformFunction: null }, isDayUnavailable: { classPropertyName: "isDayUnavailable", publicName: "isDayUnavailable", isSignal: true, isRequired: true, transformFunction: null }, monthBounds: { classPropertyName: "monthBounds", publicName: "monthBounds", isSignal: true, isRequired: true, transformFunction: null }, navigatedDate: { classPropertyName: "navigatedDate", publicName: "navigatedDate", isSignal: true, isRequired: true, transformFunction: null }, rangePreviewKeys: { classPropertyName: "rangePreviewKeys", publicName: "rangePreviewKeys", isSignal: true, isRequired: true, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: true, transformFunction: null }, selectedKeys: { classPropertyName: "selectedKeys", publicName: "selectedKeys", isSignal: true, isRequired: true, transformFunction: null }, today: { classPropertyName: "today", publicName: "today", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { dayPointerEnter: "dayPointerEnter", daySelect: "daySelect" }, host: { attributes: { "role": "gridcell" }, listeners: { "click": "onClick($event)", "pointerenter": "onPointerEnter()" }, properties: { "attr.tabindex": "focused() && !disabled() ? 0 : -1", "attr.aria-current": "isToday() ? 'date' : null", "attr.aria-disabled": "dayDisabled() ? 'true' : null", "attr.aria-label": "ariaLabel()", "attr.aria-selected": "selected() ? 'true' : null", "attr.data-range-preview": "rangePreviewed() ? 'true' : null", "class": "baseClass()" } }, ngImport: i0 }); }
421
412
  }
422
413
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: MonthDayDirective, decorators: [{
423
414
  type: Directive,
424
415
  args: [{
425
416
  selector: "[monaMonthDay]",
426
417
  host: {
427
- "[attr.tabindex]": "focused() ? 0 : -1",
428
- "[attr.aria-pressed]": "selected() ? 'true' : 'false'",
418
+ "[attr.tabindex]": "focused() && !disabled() ? 0 : -1",
429
419
  "[attr.aria-current]": "isToday() ? 'date' : null",
430
420
  "[attr.aria-disabled]": "dayDisabled() ? 'true' : null",
421
+ "[attr.aria-label]": "ariaLabel()",
422
+ "[attr.aria-selected]": "selected() ? 'true' : null",
431
423
  "[attr.data-range-preview]": "rangePreviewed() ? 'true' : null",
432
424
  "[class]": "baseClass()",
433
425
  "(click)": "onClick($event)",
434
426
  "(pointerenter)": "onPointerEnter()",
435
- role: "button"
427
+ role: "gridcell"
436
428
  }
437
429
  }]
438
- }], propDecorators: { dayPointerEnter: [{ type: i0.Output, args: ["dayPointerEnter"] }], daySelect: [{ type: i0.Output, args: ["daySelect"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: true }] }], disabledDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledDates", required: true }] }], entry: [{ type: i0.Input, args: [{ isSignal: true, alias: "entry", required: true }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: true }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: true }] }], monthBounds: [{ type: i0.Input, args: [{ isSignal: true, alias: "monthBounds", required: true }] }], navigatedDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "navigatedDate", required: true }] }], rangePreview: [{ type: i0.Input, args: [{ isSignal: true, alias: "rangePreview", required: true }] }], rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }] } });
430
+ }], propDecorators: { dayPointerEnter: [{ type: i0.Output, args: ["dayPointerEnter"] }], daySelect: [{ type: i0.Output, args: ["daySelect"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: true }] }], entry: [{ type: i0.Input, args: [{ isSignal: true, alias: "entry", required: true }] }], isDayUnavailable: [{ type: i0.Input, args: [{ isSignal: true, alias: "isDayUnavailable", required: true }] }], monthBounds: [{ type: i0.Input, args: [{ isSignal: true, alias: "monthBounds", required: true }] }], navigatedDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "navigatedDate", required: true }] }], rangePreviewKeys: [{ type: i0.Input, args: [{ isSignal: true, alias: "rangePreviewKeys", required: true }] }], rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: true }] }], selectedKeys: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedKeys", required: true }] }], today: [{ type: i0.Input, args: [{ isSignal: true, alias: "today", required: true }] }] } });
439
431
 
432
+ /** One month of the year view: a grid cell named by the long month and the year ("November 2026"). */
440
433
  class YearMonthDirective {
441
434
  constructor() {
435
+ this.#i18n = inject(MonaI18nService);
442
436
  this.ariaLabel = computed(() => {
443
- const monthName = this.monthName();
444
- return `${monthName} ${this.navigatedDate().getFullYear()}`;
437
+ const date = new Date(this.navigatedDate().getFullYear(), this.month() - 1, 1);
438
+ return formatGregorianDateToLocaleString(date, this.#i18n.localeId(), { year: "numeric", month: "long" });
445
439
  }, /* @ts-ignore */
446
440
  ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
447
441
  this.baseClass = computed(() => {
@@ -471,10 +465,11 @@ class YearMonthDirective {
471
465
  return this.month() === selDate.month && navDate.year === selDate.year;
472
466
  }, /* @ts-ignore */
473
467
  ...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
468
+ /** Whether the whole calendar is disabled. */
469
+ this.disabled = input(false, /* @ts-ignore */
470
+ ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
474
471
  this.month = input.required(/* @ts-ignore */
475
472
  ...(ngDevMode ? [{ debugName: "month" }] : /* istanbul ignore next */ []));
476
- this.monthName = input.required(/* @ts-ignore */
477
- ...(ngDevMode ? [{ debugName: "monthName" }] : /* istanbul ignore next */ []));
478
473
  this.navigatedDate = input.required(/* @ts-ignore */
479
474
  ...(ngDevMode ? [{ debugName: "navigatedDate" }] : /* istanbul ignore next */ []));
480
475
  this.rounded = input.required(/* @ts-ignore */
@@ -482,24 +477,34 @@ class YearMonthDirective {
482
477
  this.selectedDate = input(/* @ts-ignore */
483
478
  ...(ngDevMode ? [undefined, { debugName: "selectedDate" }] : /* istanbul ignore next */ []));
484
479
  }
480
+ #i18n;
485
481
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: YearMonthDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
486
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.6", type: YearMonthDirective, isStandalone: true, selector: "[monaYearMonth]", inputs: { month: { classPropertyName: "month", publicName: "month", isSignal: true, isRequired: true, transformFunction: null }, monthName: { classPropertyName: "monthName", publicName: "monthName", isSignal: true, isRequired: true, transformFunction: null }, navigatedDate: { classPropertyName: "navigatedDate", publicName: "navigatedDate", isSignal: true, isRequired: true, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: true, transformFunction: null }, selectedDate: { classPropertyName: "selectedDate", publicName: "selectedDate", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "gridcell" }, properties: { "attr.tabindex": "focused() ? 0 : -1", "attr.aria-current": "isCurrent() ? 'date' : null", "attr.aria-label": "ariaLabel()", "attr.aria-selected": "selected() ? 'true' : null", "class": "baseClass()" } }, ngImport: i0 }); }
482
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.6", type: YearMonthDirective, isStandalone: true, selector: "[monaYearMonth]", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, month: { classPropertyName: "month", publicName: "month", isSignal: true, isRequired: true, transformFunction: null }, navigatedDate: { classPropertyName: "navigatedDate", publicName: "navigatedDate", isSignal: true, isRequired: true, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: true, transformFunction: null }, selectedDate: { classPropertyName: "selectedDate", publicName: "selectedDate", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "gridcell" }, properties: { "attr.tabindex": "focused() && !disabled() ? 0 : -1", "attr.aria-current": "isCurrent() ? 'date' : null", "attr.aria-disabled": "disabled() ? 'true' : null", "attr.aria-label": "ariaLabel()", "attr.aria-selected": "selected() ? 'true' : null", "class": "baseClass()" } }, ngImport: i0 }); }
487
483
  }
488
484
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: YearMonthDirective, decorators: [{
489
485
  type: Directive,
490
486
  args: [{
491
487
  selector: "[monaYearMonth]",
492
488
  host: {
493
- "[attr.tabindex]": "focused() ? 0 : -1",
489
+ "[attr.tabindex]": "focused() && !disabled() ? 0 : -1",
494
490
  "[attr.aria-current]": "isCurrent() ? 'date' : null",
491
+ "[attr.aria-disabled]": "disabled() ? 'true' : null",
495
492
  "[attr.aria-label]": "ariaLabel()",
496
493
  "[attr.aria-selected]": "selected() ? 'true' : null",
497
494
  "[class]": "baseClass()",
498
495
  role: "gridcell"
499
496
  }
500
497
  }]
501
- }], propDecorators: { month: [{ type: i0.Input, args: [{ isSignal: true, alias: "month", required: true }] }], monthName: [{ type: i0.Input, args: [{ isSignal: true, alias: "monthName", required: true }] }], navigatedDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "navigatedDate", required: true }] }], rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: true }] }], selectedDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedDate", required: false }] }] } });
498
+ }], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], month: [{ type: i0.Input, args: [{ isSignal: true, alias: "month", required: true }] }], navigatedDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "navigatedDate", required: true }] }], rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: true }] }], selectedDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedDate", required: false }] }] } });
502
499
 
500
+ /** Midnight at the start of the local day `date` falls on. */
501
+ function startOfDay(date) {
502
+ return DateTime.fromJSDate(date).startOf("day").toJSDate();
503
+ }
504
+ /** Whole calendar days from `start` to `end`, whatever their times and across DST changes. */
505
+ function calendarDaysBetween(start, end) {
506
+ return Math.round(end.startOf("day").diff(start.startOf("day"), "days").days);
507
+ }
503
508
  const FIRST_DAY_OF_WEEK_TO_ISO = {
504
509
  monday: 1,
505
510
  tuesday: 2,
@@ -638,6 +643,25 @@ class CalendarComponent {
638
643
  ...(ngDevMode ? [{ debugName: "headerYear" }] : /* istanbul ignore next */ []));
639
644
  this.invalidState = computed(() => this.touched() && (this.invalid() || (this.required() && this.isEmptyValue())), /* @ts-ignore */
640
645
  ...(ngDevMode ? [{ debugName: "invalidState" }] : /* istanbul ignore next */ []));
646
+ /**
647
+ * Whether a day can't be picked: outside `minDate`/`maxDate` or in `disabledDates`. An iterable of disabled
648
+ * dates is turned into a set of day keys once, so each of the 42 cells answers in constant time.
649
+ */
650
+ this.isDayUnavailable = computed(() => {
651
+ const disabledDates = this.disabledDates();
652
+ const min = this.minDate();
653
+ const max = this.maxDate();
654
+ const isOutOfRange = (date) => compareDates(date, max, ">") || compareDates(date, min, "<");
655
+ if (typeof disabledDates === "function") {
656
+ return date => isOutOfRange(date) || disabledDates(date);
657
+ }
658
+ const keys = new Set();
659
+ for (const disabledDate of disabledDates ?? []) {
660
+ keys.add(toDayKey(disabledDate));
661
+ }
662
+ return date => isOutOfRange(date) || keys.has(toDayKey(date));
663
+ }, /* @ts-ignore */
664
+ ...(ngDevMode ? [{ debugName: "isDayUnavailable" }] : /* istanbul ignore next */ []));
641
665
  this.messages = this.#i18n.componentMessages("calendar", CALENDAR_DEFAULT_MESSAGES);
642
666
  this.monthBounds = computed(() => {
643
667
  const navigatedDate = this.navigatedDate();
@@ -675,7 +699,8 @@ class CalendarComponent {
675
699
  .toImmutableSet();
676
700
  }, /* @ts-ignore */
677
701
  ...(ngDevMode ? [{ debugName: "months" }] : /* istanbul ignore next */ []));
678
- this.navigatedDate = signal(new Date(), /* @ts-ignore */
702
+ // Midnight, so a date picked with the keyboard before any value exists carries no clock time.
703
+ this.navigatedDate = signal(startOfDay(new Date()), /* @ts-ignore */
679
704
  ...(ngDevMode ? [{ debugName: "navigatedDate" }] : /* istanbul ignore next */ []));
680
705
  this.nextButtonLabel = computed(() => {
681
706
  const view = this.calendarView();
@@ -718,6 +743,8 @@ class CalendarComponent {
718
743
  return this.getInclusiveDateRange(pendingRangeStart, this.rangePreviewDate() ?? this.navigatedDate());
719
744
  }, /* @ts-ignore */
720
745
  ...(ngDevMode ? [{ debugName: "rangePreviewDates" }] : /* istanbul ignore next */ []));
746
+ this.rangePreviewKeys = computed(() => new Set(this.rangePreviewDates().map(toDayKey)), /* @ts-ignore */
747
+ ...(ngDevMode ? [{ debugName: "rangePreviewKeys" }] : /* istanbul ignore next */ []));
721
748
  this.selectedDates = linkedSignal(() => {
722
749
  const v = this.value();
723
750
  const selection = this.selection();
@@ -729,7 +756,7 @@ class CalendarComponent {
729
756
  const date2 = DateTime.fromJSDate(v[v.length - 1]);
730
757
  const startDate = date1 <= date2 ? date1 : date2;
731
758
  const endDate = date1 <= date2 ? date2 : date1;
732
- const totalDays = endDate.diff(startDate, "days").days + 1;
759
+ const totalDays = calendarDaysBetween(startDate, endDate) + 1;
733
760
  return range(0, totalDays)
734
761
  .select(i => startDate.plus({ days: i }).toJSDate())
735
762
  .toArray();
@@ -737,10 +764,14 @@ class CalendarComponent {
737
764
  return Array.isArray(v) ? v : [v];
738
765
  }, /* @ts-ignore */
739
766
  ...(ngDevMode ? [{ debugName: "selectedDates" }] : /* istanbul ignore next */ []));
740
- this.timezone = DateTime.local().zoneName ?? undefined;
767
+ this.selectedKeys = computed(() => new Set(this.selectedDates().map(toDayKey)), /* @ts-ignore */
768
+ ...(ngDevMode ? [{ debugName: "selectedKeys" }] : /* istanbul ignore next */ []));
769
+ /** Today at midnight. Refreshed when focus enters the calendar, so a page left open overnight moves on. */
770
+ this.today = signal(startOfDay(new Date()), /* @ts-ignore */
771
+ ...(ngDevMode ? [{ debugName: "today" }] : /* istanbul ignore next */ []));
741
772
  this.todayButtonLabel = computed(() => {
742
773
  const locale = this.#i18n.localeId();
743
- const todayStr = formatGregorianDateToLocaleString(new Date(), locale, {
774
+ const todayStr = formatGregorianDateToLocaleString(this.today(), locale, {
744
775
  year: "numeric",
745
776
  month: "long",
746
777
  day: "numeric"
@@ -748,6 +779,8 @@ class CalendarComponent {
748
779
  return this.messages().goToToday(todayStr);
749
780
  }, /* @ts-ignore */
750
781
  ...(ngDevMode ? [{ debugName: "todayButtonLabel" }] : /* istanbul ignore next */ []));
782
+ this.todayUnavailable = computed(() => this.isDayUnavailable()(this.today()), /* @ts-ignore */
783
+ ...(ngDevMode ? [{ debugName: "todayUnavailable" }] : /* istanbul ignore next */ []));
751
784
  this.viewSwitchButtonLabel = computed(() => {
752
785
  const view = this.calendarView();
753
786
  const locale = this.#i18n.localeId();
@@ -795,8 +828,7 @@ class CalendarComponent {
795
828
  /**
796
829
  * @description Sets the disabled state of the calendar.
797
830
  */
798
- this.disabled = model(false, /* @ts-ignore */
799
- ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
831
+ this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
800
832
  /**
801
833
  * @description Sets the disabled dates of the calendar.
802
834
  * Accepts either an iterable of Date objects or a predicate function.
@@ -809,13 +841,18 @@ class CalendarComponent {
809
841
  */
810
842
  this.firstDay = input(null, /* @ts-ignore */
811
843
  ...(ngDevMode ? [{ debugName: "firstDay" }] : /* istanbul ignore next */ []));
844
+ /**
845
+ * @description Moves focus to the active day when the calendar first renders. An inline calendar on a page
846
+ * should leave focus where it is; a calendar that opens in a popup sets this so focus moves into it.
847
+ * @default false
848
+ */
849
+ this.focusOnMount = input(false, { ...(ngDevMode ? { debugName: "focusOnMount" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
812
850
  /**
813
851
  * @description Marks the calendar as invalid. When bound to a signal form field via `[formField]`,
814
852
  * this is written by the `FormField` directive.
815
853
  * @default false
816
854
  */
817
- this.invalid = input(false, /* @ts-ignore */
818
- ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
855
+ this.invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
819
856
  /**
820
857
  * @description Sets the maximum date that can be selected.
821
858
  */
@@ -830,15 +867,13 @@ class CalendarComponent {
830
867
  * @description Sets the readonly state of the calendar.
831
868
  * @default false
832
869
  */
833
- this.readonly = input(false, /* @ts-ignore */
834
- ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
870
+ this.readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
835
871
  /**
836
872
  * @description Sets whether the calendar is required. When bound to a signal form field via `[formField]`,
837
873
  * this is written by the `FormField` directive.
838
874
  * @default false
839
875
  */
840
- this.required = input(false, /* @ts-ignore */
841
- ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
876
+ this.required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
842
877
  /**
843
878
  * @description Sets the border radius of the calendar.
844
879
  * @default "medium"
@@ -852,8 +887,8 @@ class CalendarComponent {
852
887
  this.selection = input("single", /* @ts-ignore */
853
888
  ...(ngDevMode ? [{ debugName: "selection" }] : /* istanbul ignore next */ []));
854
889
  /**
855
- * @description Emitted when the calendar value is changed by user interaction.
856
- * The `FormField` directive listens to this to mark the field as touched.
890
+ * @description Emitted when focus leaves the calendar, as a native input is touched on blur. Moving between
891
+ * its buttons and days doesn't count. The `FormField` directive listens to this to mark the field as touched.
857
892
  */
858
893
  this.touch = output();
859
894
  /**
@@ -861,14 +896,14 @@ class CalendarComponent {
861
896
  * this is written by the `FormField` directive.
862
897
  * @default false
863
898
  */
864
- this.touched = input(false, /* @ts-ignore */
865
- ...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
899
+ this.touched = input(false, { ...(ngDevMode ? { debugName: "touched" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
866
900
  /**
867
901
  * @description Adds custom CSS classes to the calendar host element.
868
902
  */
869
903
  this.userClass = input("", { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: "class" });
870
904
  /**
871
- * @description The current value of the calendar.
905
+ * @description The current value of the calendar: a `Date` in single selection, the selected dates in multiple
906
+ * selection, and `[start, end]` in range selection. A range is written once both ends are picked.
872
907
  * @default null
873
908
  */
874
909
  this.value = model(null, /* @ts-ignore */
@@ -877,33 +912,36 @@ class CalendarComponent {
877
912
  * @description Enables the display of week numbers in the calendar.
878
913
  * @default false
879
914
  */
880
- this.weekNumber = input(false, /* @ts-ignore */
881
- ...(ngDevMode ? [{ debugName: "weekNumber" }] : /* istanbul ignore next */ []));
915
+ this.weekNumber = input(false, { ...(ngDevMode ? { debugName: "weekNumber" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
882
916
  afterNextRender({
883
917
  read: () => {
884
918
  this.setupKeyboardNavigation();
885
- this.focusActiveCell();
919
+ if (this.focusOnMount()) {
920
+ this.focusActiveCell();
921
+ }
886
922
  }
887
923
  });
888
924
  effect(() => {
889
925
  const min = this.minDate();
890
926
  const max = this.maxDate();
891
- this.disabledDates();
892
927
  untracked(() => {
928
+ // Keep the active day within the range. A day disabled through disabledDates can stay active: it is
929
+ // focusable and announced as unavailable, so the keyboard can move past it.
893
930
  const navigationDate = this.navigatedDate();
894
- if (this.isDateDisabled(navigationDate)) {
895
- const newDate = min ?? max;
896
- if (newDate) {
897
- this.navigatedDate.set(newDate);
898
- }
931
+ if (compareDates(navigationDate, min, "<") && min) {
932
+ this.navigatedDate.set(min);
933
+ }
934
+ else if (compareDates(navigationDate, max, ">") && max) {
935
+ this.navigatedDate.set(max);
899
936
  }
900
937
  });
901
938
  });
902
939
  effect(() => {
903
940
  const v = this.value();
904
941
  untracked(() => {
905
- if (v != null) {
906
- const lastDate = Array.isArray(v) ? (lastOrDefault(v) ?? DateTime.now().toJSDate()) : v;
942
+ // Show the last selected date. Clearing the selection leaves the view where it is.
943
+ const lastDate = Array.isArray(v) ? lastOrDefault(v) : v;
944
+ if (lastDate) {
907
945
  this.navigatedDate.set(lastDate);
908
946
  }
909
947
  });
@@ -957,6 +995,17 @@ class CalendarComponent {
957
995
  }
958
996
  this.rangePreviewDate.set(date);
959
997
  }
998
+ onFocusOut(event) {
999
+ // Removing a focused calendar from the page fires focusout after it is destroyed.
1000
+ if (this.#destroyRef.destroyed) {
1001
+ return;
1002
+ }
1003
+ const nextTarget = event.relatedTarget;
1004
+ if (nextTarget instanceof Node && this.#hostElementRef.nativeElement.contains(nextTarget)) {
1005
+ return;
1006
+ }
1007
+ this.touch.emit();
1008
+ }
960
1009
  onMonthClick(month) {
961
1010
  this.navigatedDate.set(DateTime.fromJSDate(this.navigatedDate()).set({ month }).toJSDate());
962
1011
  this.calendarView.set("month");
@@ -982,18 +1031,19 @@ class CalendarComponent {
982
1031
  this.navigatedDate.set(direction === "prev" ? date.minus(unit).toJSDate() : date.plus(unit).toJSDate());
983
1032
  }
984
1033
  onTodayButtonClick() {
985
- if (this.disabled() || this.readonly()) {
1034
+ this.refreshToday();
1035
+ if (this.disabled() || this.readonly() || this.todayUnavailable()) {
986
1036
  return;
987
1037
  }
988
- const currentDate = DateTime.now();
989
- const navigatedDate = DateTime.fromJSDate(this.navigatedDate()).set({
990
- year: currentDate.year,
991
- month: currentDate.month,
992
- day: currentDate.day
993
- });
994
- this.clearPendingRange();
995
- this.navigatedDate.set(navigatedDate.toJSDate());
996
- this.setCurrentDate(navigatedDate.toJSDate());
1038
+ // Today is picked as a click on its day would pick it, so the same rules apply.
1039
+ const today = this.today();
1040
+ if (this.selection() === "range") {
1041
+ this.handleRangeSelection(today);
1042
+ this.navigatedDate.set(today);
1043
+ }
1044
+ else {
1045
+ this.handleSingleSelection(today);
1046
+ }
997
1047
  this.calendarView.set("month");
998
1048
  this.commitUserSelection();
999
1049
  }
@@ -1004,13 +1054,22 @@ class CalendarComponent {
1004
1054
  this.navigatedDate.set(DateTime.fromJSDate(this.navigatedDate()).set({ year }).toJSDate());
1005
1055
  this.calendarView.set("year");
1006
1056
  }
1057
+ refreshToday() {
1058
+ const today = startOfDay(new Date());
1059
+ if (!compareDates(today, this.today(), "==")) {
1060
+ this.today.set(today);
1061
+ }
1062
+ }
1007
1063
  clearPendingRange() {
1008
1064
  this.pendingRangeStart.set(null);
1009
1065
  this.rangePreviewDate.set(null);
1010
1066
  }
1011
1067
  commitUserSelection() {
1068
+ // A range is written once both ends are picked; the first click only starts it.
1069
+ if (this.selection() === "range" && this.pendingRangeStart() != null) {
1070
+ return;
1071
+ }
1012
1072
  this.value.set(this.#outputValue());
1013
- this.touch.emit();
1014
1073
  }
1015
1074
  extendSelection(offset) {
1016
1075
  const currentDate = this.navigatedDate();
@@ -1048,7 +1107,7 @@ class CalendarComponent {
1048
1107
  const lastSelectedDate = lastOrDefault(this.selectedDates()) ?? this.navigatedDate();
1049
1108
  const startDate = lastSelectedDate < date ? lastSelectedDate : date;
1050
1109
  const endDate = this.navigatedDate() > date ? this.navigatedDate() : date;
1051
- const totalDays = DateTime.fromJSDate(endDate).diff(DateTime.fromJSDate(startDate), "days").days + 1;
1110
+ const totalDays = calendarDaysBetween(DateTime.fromJSDate(startDate), DateTime.fromJSDate(endDate)) + 1;
1052
1111
  return range(0, totalDays)
1053
1112
  .select(i => DateTime.fromJSDate(startDate).plus({ days: i }).toJSDate())
1054
1113
  .toArray();
@@ -1058,7 +1117,7 @@ class CalendarComponent {
1058
1117
  const dateTime2 = DateTime.fromJSDate(date2);
1059
1118
  const startDate = dateTime1 <= dateTime2 ? dateTime1 : dateTime2;
1060
1119
  const endDate = dateTime1 <= dateTime2 ? dateTime2 : dateTime1;
1061
- const totalDays = endDate.diff(startDate, "days").days + 1;
1120
+ const totalDays = calendarDaysBetween(startDate, endDate) + 1;
1062
1121
  return range(0, totalDays)
1063
1122
  .select(i => startDate.plus({ days: i }).toJSDate())
1064
1123
  .toArray();
@@ -1072,6 +1131,10 @@ class CalendarComponent {
1072
1131
  if (preventableEvent.isDefaultPrevented()) {
1073
1132
  return;
1074
1133
  }
1134
+ // Keys pressed on the header buttons belong to the buttons: the arrows don't move the active day.
1135
+ if (event.target.closest("button")) {
1136
+ return;
1137
+ }
1075
1138
  const view = this.calendarView();
1076
1139
  const isCtrlOrCmd = event.ctrlKey || event.metaKey;
1077
1140
  const isShift = event.shiftKey;
@@ -1127,10 +1190,6 @@ class CalendarComponent {
1127
1190
  break;
1128
1191
  case "Enter":
1129
1192
  case " ": {
1130
- const target = event.target;
1131
- if (target.tagName === "BUTTON" || target.closest("button")) {
1132
- return;
1133
- }
1134
1193
  event.preventDefault();
1135
1194
  const previousView = this.calendarView();
1136
1195
  if (this.readonly() && previousView === "month") {
@@ -1164,12 +1223,13 @@ class CalendarComponent {
1164
1223
  break;
1165
1224
  case "PageUp":
1166
1225
  event.preventDefault();
1167
- this.navigateByPeriod(-1, view);
1226
+ // Shift+PageUp moves a year in the month view, as in the WAI-ARIA date picker pattern.
1227
+ this.navigateByPeriod(isShift && view === "month" ? -12 : -1, view);
1168
1228
  shouldFocusCell = true;
1169
1229
  break;
1170
1230
  case "PageDown":
1171
1231
  event.preventDefault();
1172
- this.navigateByPeriod(1, view);
1232
+ this.navigateByPeriod(isShift && view === "month" ? 12 : 1, view);
1173
1233
  shouldFocusCell = true;
1174
1234
  break;
1175
1235
  case "t":
@@ -1200,10 +1260,11 @@ class CalendarComponent {
1200
1260
  const date1 = DateTime.fromJSDate(date);
1201
1261
  const valueList = this.getDateArray(value);
1202
1262
  const selectedDates = select(valueList, e => DateTime.fromJSDate(e));
1203
- const alreadySelected = selectedDates.any(e => e.equals(date1));
1263
+ // Compare by day: a selected value carries a time, the clicked day is midnight.
1264
+ const alreadySelected = selectedDates.any(e => e.hasSame(date1, "day"));
1204
1265
  if (alreadySelected) {
1205
1266
  const newDates = selectedDates
1206
- .where(e => !e.equals(date1))
1267
+ .where(e => !e.hasSame(date1, "day"))
1207
1268
  .select(e => e.toJSDate())
1208
1269
  .toArray();
1209
1270
  this.setCurrentDate(newDates);
@@ -1288,22 +1349,15 @@ class CalendarComponent {
1288
1349
  return isRtl ? "prev" : "next";
1289
1350
  }
1290
1351
  isDateDisabled(date) {
1291
- const disabledDates = this.disabledDates();
1292
- const max = this.maxDate();
1293
- const min = this.minDate();
1294
- let isDisabledByInput = false;
1295
- if (typeof disabledDates === "function") {
1296
- isDisabledByInput = disabledDates(date);
1297
- }
1298
- else if (disabledDates) {
1299
- isDisabledByInput = any(disabledDates, d => compareDates(date, d, "=="));
1300
- }
1301
- return isDisabledByInput || compareDates(date, max, ">") || compareDates(date, min, "<");
1352
+ return this.isDayUnavailable()(date);
1302
1353
  }
1303
1354
  isEmptyValue() {
1304
1355
  const value = this.value();
1305
1356
  return value == null || (Array.isArray(value) && value.length === 0);
1306
1357
  }
1358
+ isOutOfRange(date) {
1359
+ return compareDates(date, this.maxDate(), ">") || compareDates(date, this.minDate(), "<");
1360
+ }
1307
1361
  navigateByDaysOrCells(offset, view) {
1308
1362
  const currentDate = this.navigatedDate();
1309
1363
  const dateTime = DateTime.fromJSDate(currentDate);
@@ -1319,7 +1373,8 @@ class CalendarComponent {
1319
1373
  newDate = dateTime.plus({ years: offset }).toJSDate();
1320
1374
  break;
1321
1375
  }
1322
- if (view === "month" && this.isDateDisabled(newDate)) {
1376
+ // A disabled day can be focused (it is announced as unavailable); only the range bounds stop the arrows.
1377
+ if (view === "month" && this.isOutOfRange(newDate)) {
1323
1378
  return;
1324
1379
  }
1325
1380
  this.rangePreviewDate.set(null);
@@ -1371,7 +1426,8 @@ class CalendarComponent {
1371
1426
  newDate = dateTime.plus({ years: offset * 4 }).toJSDate();
1372
1427
  break;
1373
1428
  }
1374
- if (view === "month" && this.isDateDisabled(newDate)) {
1429
+ // A disabled day can be focused (it is announced as unavailable); only the range bounds stop the arrows.
1430
+ if (view === "month" && this.isOutOfRange(newDate)) {
1375
1431
  return;
1376
1432
  }
1377
1433
  this.rangePreviewDate.set(null);
@@ -1447,7 +1503,8 @@ class CalendarComponent {
1447
1503
  this.navigatedDate.set(newDate);
1448
1504
  }
1449
1505
  navigateToToday() {
1450
- const today = DateTime.now().toJSDate();
1506
+ this.refreshToday();
1507
+ const today = this.today();
1451
1508
  if (this.isDateDisabled(today)) {
1452
1509
  return;
1453
1510
  }
@@ -1536,7 +1593,7 @@ class CalendarComponent {
1536
1593
  }
1537
1594
  }
1538
1595
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: CalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1539
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: CalendarComponent, isStandalone: true, selector: "mona-calendar", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, disabledDates: { classPropertyName: "disabledDates", publicName: "disabledDates", isSignal: true, isRequired: false, transformFunction: null }, firstDay: { classPropertyName: "firstDay", publicName: "firstDay", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, selection: { classPropertyName: "selection", publicName: "selection", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, weekNumber: { classPropertyName: "weekNumber", publicName: "weekNumber", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", touch: "touch", value: "valueChange" }, host: { attributes: { "role": "application" }, properties: { "attr.aria-label": "ariaLabel()", "attr.aria-invalid": "invalidState() ? 'true' : null", "attr.data-invalid": "invalidState() || null", "attr.data-required": "required() || null", "attr.tabindex": "disabled() ? -1 : 0", "class": "baseClass()" } }, queries: [{ propertyName: "decadeCellTemplate", first: true, predicate: CalendarDecadeCellTemplateDirective, descendants: true, isSignal: true }, { propertyName: "monthCellTemplate", first: true, predicate: CalendarMonthCellTemplateDirective, descendants: true, isSignal: true }, { propertyName: "yearCellTemplate", first: true, predicate: CalendarYearCellTemplateDirective, descendants: true, isSignal: true }], ngImport: i0, template: "<div [class]=\"headerClass()\">\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [size]=\"'small'\"\n (click)=\"onTodayButtonClick()\"\n [attr.aria-label]=\"todayButtonLabel()\">\n <span>{{ messages().today }}</span>\n </button>\n @switch (calendarView()) {\n @case (\"month\") {\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n (click)=\"onViewChangeClick('year')\"\n [attr.aria-label]=\"viewSwitchButtonLabel()\">\n <span class=\"text-primary font-semibold\" [id]=\"gridId + '-heading'\">{{\n headerMonthYear()\n }}</span>\n </button>\n }\n @case (\"year\") {\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n (click)=\"onViewChangeClick('decade')\"\n [attr.aria-label]=\"viewSwitchButtonLabel()\">\n <span class=\"text-primary font-semibold\" [id]=\"gridId + '-heading'\">{{\n headerYear()\n }}</span>\n </button>\n }\n @case (\"decade\") {\n <button monaButton look=\"ghost\" [rounded]=\"rounded()\" [attr.aria-label]=\"viewSwitchButtonLabel()\">\n <span class=\"text-primary font-semibold\" [id]=\"gridId + '-heading'\"\n >{{ formatInteger(decadeStart()) }} - {{ formatInteger(decadeEnd()) }}</span\n >\n </button>\n }\n }\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [iconOnly]=\"true\"\n [size]=\"'small'\"\n (click)=\"onNavigationClick('prev')\"\n [attr.aria-label]=\"prevButtonLabel()\">\n <svg lucideChevronLeft class=\"rtl:rotate-180\"></svg>\n </button>\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [iconOnly]=\"true\"\n [size]=\"'small'\"\n (click)=\"onNavigationClick('next')\"\n [attr.aria-label]=\"nextButtonLabel()\">\n <svg lucideChevronRight class=\"rtl:rotate-180\"></svg>\n </button>\n</div>\n\n<div aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\">{{ ariaLabel() }}</div>\n\n@if (calendarView() === \"month\") {\n @let columnCount = weekNumber() ? 8 : 7;\n <div [class]=\"monthGridHeaderClass()\" [style.grid-template-columns]=\"`repeat(${columnCount}, 32px)`\">\n @if (weekNumber()) {\n <div></div>\n }\n @for (day of weekdays(); track day.full) {\n <div>\n <span aria-hidden=\"true\">{{ day.display }}</span>\n <span class=\"sr-only\">{{ day.full }}</span>\n </div>\n }\n </div>\n <div\n [class]=\"monthGridClass()\"\n [attr.aria-labelledby]=\"gridId + '-heading'\"\n (pointerleave)=\"onMonthGridPointerLeave()\"\n [style.grid-template-columns]=\"`repeat(${columnCount}, 32px)`\">\n @for (row of monthDictChunked(); track $index) {\n @if (weekNumber()) {\n @let firstEntry = row | monaTakeFirst;\n @if (firstEntry) {\n @let week = getWeekNumber(firstEntry.key);\n <div>{{ formatInteger(week) }}</div>\n }\n }\n @for (entry of row; track entry.key) {\n <div\n (dayPointerEnter)=\"onDayPointerEnter($event)\"\n (daySelect)=\"onDayClick($event.date, $event.event)\"\n monaMonthDay\n [disabled]=\"disabled()\"\n [disabledDates]=\"disabledDates()\"\n [min]=\"minDate()\"\n [max]=\"maxDate()\"\n [monthBounds]=\"[monthBounds().start, monthBounds().end]\"\n [navigatedDate]=\"navigatedDate()\"\n [rangePreview]=\"rangePreviewDates()\"\n [rounded]=\"rounded()\"\n [value]=\"selectedDates()\"\n [entry]=\"entry\">\n @if (monthCellTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"monthCellTemplate()?.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: entry.value, date: entry.key }\"></ng-container>\n } @else {\n <span>{{ formatInteger(entry.value) }}</span>\n }\n </div>\n }\n }\n </div>\n} @else if (calendarView() === \"year\") {\n <div [class]=\"yearGridClass()\" [attr.aria-labelledby]=\"gridId + '-heading'\">\n @for (row of months(); track $index) {\n @for (monthItem of row; track monthItem) {\n <div\n (click)=\"onMonthClick(monthItem[0])\"\n monaYearMonth\n [month]=\"monthItem[0]\"\n [monthName]=\"monthItem[1]\"\n [navigatedDate]=\"navigatedDate()\"\n [rounded]=\"rounded()\"\n [selectedDate]=\"selectedDates()[0]\">\n @if (yearCellTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"yearCellTemplate()?.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: monthItem[0], text: monthItem[1] }\">\n </ng-container>\n } @else {\n <span>{{ monthItem[1] }}</span>\n }\n </div>\n }\n }\n </div>\n} @else if (calendarView() === \"decade\") {\n <div [class]=\"decadeGridClass()\" [attr.aria-labelledby]=\"gridId + '-heading'\">\n @for (row of decadeYears(); track $index) {\n @for (year of row; track year) {\n <div\n (click)=\"onYearClick(year)\"\n monaDecadeYear\n [navigatedDate]=\"navigatedDate()\"\n [rounded]=\"rounded()\"\n [year]=\"year\"\n [selectedDate]=\"selectedDates()[0]\">\n @if (decadeCellTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"decadeCellTemplate()?.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: year }\">\n </ng-container>\n } @else {\n <span>{{ formatInteger(year) }}</span>\n }\n </div>\n }\n }\n </div>\n}\n", dependencies: [{ kind: "directive", type: ButtonDirective, selector: "button[monaButton]", inputs: ["aria-haspopup", "disabled", "iconOnly", "loading", "look", "rounded", "selected", "size", "tabindex", "toggleable", "type", "class"], outputs: ["lookChange", "selectedChange"] }, { kind: "directive", type: MonthDayDirective, selector: "[monaMonthDay]", inputs: ["disabled", "disabledDates", "entry", "max", "min", "monthBounds", "navigatedDate", "rangePreview", "rounded", "value"], outputs: ["dayPointerEnter", "daySelect"] }, { kind: "directive", type: DecadeYearDirective, selector: "[monaDecadeYear]", inputs: ["navigatedDate", "rounded", "selectedDate", "year"] }, { kind: "directive", type: YearMonthDirective, selector: "[monaYearMonth]", inputs: ["month", "monthName", "navigatedDate", "rounded", "selectedDate"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: LucideChevronLeft, selector: "svg[lucideChevronLeft]" }, { kind: "component", type: LucideChevronRight, selector: "svg[lucideChevronRight]" }, { kind: "pipe", type: TakeFirstPipe, name: "monaTakeFirst" }] }); }
1596
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: CalendarComponent, isStandalone: true, selector: "mona-calendar", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, disabledDates: { classPropertyName: "disabledDates", publicName: "disabledDates", isSignal: true, isRequired: false, transformFunction: null }, firstDay: { classPropertyName: "firstDay", publicName: "firstDay", isSignal: true, isRequired: false, transformFunction: null }, focusOnMount: { classPropertyName: "focusOnMount", publicName: "focusOnMount", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, selection: { classPropertyName: "selection", publicName: "selection", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, weekNumber: { classPropertyName: "weekNumber", publicName: "weekNumber", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { touch: "touch", value: "valueChange" }, host: { listeners: { "focusin": "refreshToday()", "focusout": "onFocusOut($event)" }, properties: { "attr.aria-label": "null", "attr.data-disabled": "disabled() || null", "attr.data-invalid": "invalidState() || null", "attr.data-required": "required() || null", "class": "baseClass()" } }, queries: [{ propertyName: "decadeCellTemplate", first: true, predicate: CalendarDecadeCellTemplateDirective, descendants: true, isSignal: true }, { propertyName: "monthCellTemplate", first: true, predicate: CalendarMonthCellTemplateDirective, descendants: true, isSignal: true }, { propertyName: "yearCellTemplate", first: true, predicate: CalendarYearCellTemplateDirective, descendants: true, isSignal: true }], ngImport: i0, template: "<div [class]=\"headerClass()\">\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [size]=\"'small'\"\n [disabled]=\"disabled() || todayUnavailable()\"\n (click)=\"onTodayButtonClick()\"\n [attr.aria-label]=\"todayButtonLabel()\">\n <span>{{ messages().today }}</span>\n </button>\n @switch (calendarView()) {\n @case (\"month\") {\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [disabled]=\"disabled()\"\n (click)=\"onViewChangeClick('year')\"\n [attr.aria-label]=\"viewSwitchButtonLabel()\">\n <span class=\"text-primary font-semibold\" [id]=\"gridId + '-heading'\">{{\n headerMonthYear()\n }}</span>\n </button>\n }\n @case (\"year\") {\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [disabled]=\"disabled()\"\n (click)=\"onViewChangeClick('decade')\"\n [attr.aria-label]=\"viewSwitchButtonLabel()\">\n <span class=\"text-primary font-semibold\" [id]=\"gridId + '-heading'\">{{\n headerYear()\n }}</span>\n </button>\n }\n @case (\"decade\") {\n <!-- The decade is the top view, so its heading isn't a button. It names the grid with the locale's\n wording of the range, and shows the digits. -->\n <span\n class=\"text-primary inline-flex h-9 items-center px-4 text-sm font-semibold\"\n [id]=\"gridId + '-heading'\"\n ><span aria-hidden=\"true\">{{ formatInteger(decadeStart()) }} - {{ formatInteger(decadeEnd()) }}</span\n ><span class=\"sr-only\">{{ viewSwitchButtonLabel() }}</span></span\n >\n }\n }\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [iconOnly]=\"true\"\n [size]=\"'small'\"\n [disabled]=\"disabled()\"\n (click)=\"onNavigationClick('prev')\"\n [attr.aria-label]=\"prevButtonLabel()\">\n <svg lucideChevronLeft class=\"rtl:rotate-180\"></svg>\n </button>\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [iconOnly]=\"true\"\n [size]=\"'small'\"\n [disabled]=\"disabled()\"\n (click)=\"onNavigationClick('next')\"\n [attr.aria-label]=\"nextButtonLabel()\">\n <svg lucideChevronRight class=\"rtl:rotate-180\"></svg>\n </button>\n</div>\n\n<div aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\">{{ ariaLabel() }}</div>\n\n@if (calendarView() === \"month\") {\n @let columnCount = weekNumber() ? 8 : 7;\n <div\n role=\"grid\"\n class=\"flex flex-col gap-0.5\"\n [attr.aria-labelledby]=\"gridId + '-heading'\"\n [attr.aria-disabled]=\"disabled() || null\"\n [attr.aria-invalid]=\"invalidState() ? 'true' : null\"\n [attr.aria-readonly]=\"readonly() || null\"\n [attr.aria-required]=\"required() || null\"\n (pointerleave)=\"onMonthGridPointerLeave()\">\n <div role=\"row\" [class]=\"monthGridHeaderClass()\" [style.grid-template-columns]=\"`repeat(${columnCount}, 32px)`\">\n @if (weekNumber()) {\n <!-- Week numbers are visual only: every day is already named by its full date. -->\n <div aria-hidden=\"true\"></div>\n }\n @for (day of weekdays(); track day.full) {\n <div role=\"columnheader\">\n <span aria-hidden=\"true\">{{ day.display }}</span>\n <span class=\"sr-only\">{{ day.full }}</span>\n </div>\n }\n </div>\n @for (row of monthDictChunked(); track $index) {\n <div role=\"row\" [class]=\"monthGridClass()\" [style.grid-template-columns]=\"`repeat(${columnCount}, 32px)`\">\n @if (weekNumber()) {\n @let firstEntry = row | monaTakeFirst;\n @if (firstEntry) {\n @let week = getWeekNumber(firstEntry.key);\n <div aria-hidden=\"true\">{{ formatInteger(week) }}</div>\n }\n }\n <!-- Track by time: the month is rebuilt with new Date objects on every navigation. -->\n @for (entry of row; track entry.key.getTime()) {\n <div\n (dayPointerEnter)=\"onDayPointerEnter($event)\"\n (daySelect)=\"onDayClick($event.date, $event.event)\"\n monaMonthDay\n [disabled]=\"disabled()\"\n [isDayUnavailable]=\"isDayUnavailable()\"\n [monthBounds]=\"[monthBounds().start, monthBounds().end]\"\n [navigatedDate]=\"navigatedDate()\"\n [rangePreviewKeys]=\"rangePreviewKeys()\"\n [rounded]=\"rounded()\"\n [selectedKeys]=\"selectedKeys()\"\n [today]=\"today()\"\n [entry]=\"entry\">\n @if (monthCellTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"monthCellTemplate()?.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: entry.value, date: entry.key }\"></ng-container>\n } @else {\n <span>{{ formatInteger(entry.value) }}</span>\n }\n </div>\n }\n </div>\n }\n </div>\n} @else if (calendarView() === \"year\") {\n <div role=\"grid\" class=\"flex flex-col gap-0.5\" [attr.aria-labelledby]=\"gridId + '-heading'\">\n @for (row of months(); track $index) {\n <div role=\"row\" [class]=\"yearGridClass()\">\n @for (monthItem of row; track monthItem) {\n <div\n (click)=\"!disabled() && onMonthClick(monthItem[0])\"\n monaYearMonth\n [disabled]=\"disabled()\"\n [month]=\"monthItem[0]\"\n [navigatedDate]=\"navigatedDate()\"\n [rounded]=\"rounded()\"\n [selectedDate]=\"selectedDates()[0]\">\n @if (yearCellTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"yearCellTemplate()?.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: monthItem[0], text: monthItem[1] }\">\n </ng-container>\n } @else {\n <span>{{ monthItem[1] }}</span>\n }\n </div>\n }\n </div>\n }\n </div>\n} @else if (calendarView() === \"decade\") {\n <div role=\"grid\" class=\"flex flex-col gap-0.5\" [attr.aria-labelledby]=\"gridId + '-heading'\">\n @for (row of decadeYears(); track $index) {\n <div role=\"row\" [class]=\"decadeGridClass()\">\n @for (year of row; track year) {\n <div\n (click)=\"!disabled() && onYearClick(year)\"\n monaDecadeYear\n [disabled]=\"disabled()\"\n [navigatedDate]=\"navigatedDate()\"\n [rounded]=\"rounded()\"\n [year]=\"year\"\n [selectedDate]=\"selectedDates()[0]\">\n @if (decadeCellTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"decadeCellTemplate()?.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: year }\">\n </ng-container>\n } @else {\n <span>{{ formatInteger(year) }}</span>\n }\n </div>\n }\n </div>\n }\n </div>\n}\n", dependencies: [{ kind: "directive", type: ButtonDirective, selector: "button[monaButton]", inputs: ["aria-haspopup", "disabled", "iconOnly", "loading", "look", "rounded", "selected", "size", "tabindex", "toggleable", "type", "class"], outputs: ["lookChange", "selectedChange"] }, { kind: "directive", type: MonthDayDirective, selector: "[monaMonthDay]", inputs: ["disabled", "entry", "isDayUnavailable", "monthBounds", "navigatedDate", "rangePreviewKeys", "rounded", "selectedKeys", "today"], outputs: ["dayPointerEnter", "daySelect"] }, { kind: "directive", type: DecadeYearDirective, selector: "[monaDecadeYear]", inputs: ["disabled", "navigatedDate", "rounded", "selectedDate", "year"] }, { kind: "directive", type: YearMonthDirective, selector: "[monaYearMonth]", inputs: ["disabled", "month", "navigatedDate", "rounded", "selectedDate"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: LucideChevronLeft, selector: "svg[lucideChevronLeft]" }, { kind: "component", type: LucideChevronRight, selector: "svg[lucideChevronRight]" }, { kind: "pipe", type: TakeFirstPipe, name: "monaTakeFirst" }] }); }
1540
1597
  }
1541
1598
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: CalendarComponent, decorators: [{
1542
1599
  type: Component,
@@ -1550,15 +1607,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImpor
1550
1607
  LucideChevronLeft,
1551
1608
  LucideChevronRight
1552
1609
  ], host: {
1553
- role: "application",
1554
- "[attr.aria-label]": "ariaLabel()",
1555
- "[attr.aria-invalid]": "invalidState() ? 'true' : null",
1610
+ // The host is a plain container: the grid inside it is the widget, and focus moves through its cells. A
1611
+ // static aria-label written on <mona-calendar> would otherwise stay on the role-less host.
1612
+ "[attr.aria-label]": "null",
1613
+ "[attr.data-disabled]": "disabled() || null",
1556
1614
  "[attr.data-invalid]": "invalidState() || null",
1557
1615
  "[attr.data-required]": "required() || null",
1558
- "[attr.tabindex]": "disabled() ? -1 : 0",
1559
- "[class]": "baseClass()"
1560
- }, template: "<div [class]=\"headerClass()\">\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [size]=\"'small'\"\n (click)=\"onTodayButtonClick()\"\n [attr.aria-label]=\"todayButtonLabel()\">\n <span>{{ messages().today }}</span>\n </button>\n @switch (calendarView()) {\n @case (\"month\") {\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n (click)=\"onViewChangeClick('year')\"\n [attr.aria-label]=\"viewSwitchButtonLabel()\">\n <span class=\"text-primary font-semibold\" [id]=\"gridId + '-heading'\">{{\n headerMonthYear()\n }}</span>\n </button>\n }\n @case (\"year\") {\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n (click)=\"onViewChangeClick('decade')\"\n [attr.aria-label]=\"viewSwitchButtonLabel()\">\n <span class=\"text-primary font-semibold\" [id]=\"gridId + '-heading'\">{{\n headerYear()\n }}</span>\n </button>\n }\n @case (\"decade\") {\n <button monaButton look=\"ghost\" [rounded]=\"rounded()\" [attr.aria-label]=\"viewSwitchButtonLabel()\">\n <span class=\"text-primary font-semibold\" [id]=\"gridId + '-heading'\"\n >{{ formatInteger(decadeStart()) }} - {{ formatInteger(decadeEnd()) }}</span\n >\n </button>\n }\n }\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [iconOnly]=\"true\"\n [size]=\"'small'\"\n (click)=\"onNavigationClick('prev')\"\n [attr.aria-label]=\"prevButtonLabel()\">\n <svg lucideChevronLeft class=\"rtl:rotate-180\"></svg>\n </button>\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [iconOnly]=\"true\"\n [size]=\"'small'\"\n (click)=\"onNavigationClick('next')\"\n [attr.aria-label]=\"nextButtonLabel()\">\n <svg lucideChevronRight class=\"rtl:rotate-180\"></svg>\n </button>\n</div>\n\n<div aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\">{{ ariaLabel() }}</div>\n\n@if (calendarView() === \"month\") {\n @let columnCount = weekNumber() ? 8 : 7;\n <div [class]=\"monthGridHeaderClass()\" [style.grid-template-columns]=\"`repeat(${columnCount}, 32px)`\">\n @if (weekNumber()) {\n <div></div>\n }\n @for (day of weekdays(); track day.full) {\n <div>\n <span aria-hidden=\"true\">{{ day.display }}</span>\n <span class=\"sr-only\">{{ day.full }}</span>\n </div>\n }\n </div>\n <div\n [class]=\"monthGridClass()\"\n [attr.aria-labelledby]=\"gridId + '-heading'\"\n (pointerleave)=\"onMonthGridPointerLeave()\"\n [style.grid-template-columns]=\"`repeat(${columnCount}, 32px)`\">\n @for (row of monthDictChunked(); track $index) {\n @if (weekNumber()) {\n @let firstEntry = row | monaTakeFirst;\n @if (firstEntry) {\n @let week = getWeekNumber(firstEntry.key);\n <div>{{ formatInteger(week) }}</div>\n }\n }\n @for (entry of row; track entry.key) {\n <div\n (dayPointerEnter)=\"onDayPointerEnter($event)\"\n (daySelect)=\"onDayClick($event.date, $event.event)\"\n monaMonthDay\n [disabled]=\"disabled()\"\n [disabledDates]=\"disabledDates()\"\n [min]=\"minDate()\"\n [max]=\"maxDate()\"\n [monthBounds]=\"[monthBounds().start, monthBounds().end]\"\n [navigatedDate]=\"navigatedDate()\"\n [rangePreview]=\"rangePreviewDates()\"\n [rounded]=\"rounded()\"\n [value]=\"selectedDates()\"\n [entry]=\"entry\">\n @if (monthCellTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"monthCellTemplate()?.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: entry.value, date: entry.key }\"></ng-container>\n } @else {\n <span>{{ formatInteger(entry.value) }}</span>\n }\n </div>\n }\n }\n </div>\n} @else if (calendarView() === \"year\") {\n <div [class]=\"yearGridClass()\" [attr.aria-labelledby]=\"gridId + '-heading'\">\n @for (row of months(); track $index) {\n @for (monthItem of row; track monthItem) {\n <div\n (click)=\"onMonthClick(monthItem[0])\"\n monaYearMonth\n [month]=\"monthItem[0]\"\n [monthName]=\"monthItem[1]\"\n [navigatedDate]=\"navigatedDate()\"\n [rounded]=\"rounded()\"\n [selectedDate]=\"selectedDates()[0]\">\n @if (yearCellTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"yearCellTemplate()?.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: monthItem[0], text: monthItem[1] }\">\n </ng-container>\n } @else {\n <span>{{ monthItem[1] }}</span>\n }\n </div>\n }\n }\n </div>\n} @else if (calendarView() === \"decade\") {\n <div [class]=\"decadeGridClass()\" [attr.aria-labelledby]=\"gridId + '-heading'\">\n @for (row of decadeYears(); track $index) {\n @for (year of row; track year) {\n <div\n (click)=\"onYearClick(year)\"\n monaDecadeYear\n [navigatedDate]=\"navigatedDate()\"\n [rounded]=\"rounded()\"\n [year]=\"year\"\n [selectedDate]=\"selectedDates()[0]\">\n @if (decadeCellTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"decadeCellTemplate()?.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: year }\">\n </ng-container>\n } @else {\n <span>{{ formatInteger(year) }}</span>\n }\n </div>\n }\n }\n </div>\n}\n" }]
1561
- }], ctorParameters: () => [], propDecorators: { decadeCellTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => CalendarDecadeCellTemplateDirective), { isSignal: true }] }], monthCellTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => CalendarMonthCellTemplateDirective), { isSignal: true }] }], yearCellTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => CalendarYearCellTemplateDirective), { isSignal: true }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], disabledDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledDates", required: false }] }], firstDay: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstDay", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: false }] }], selection: [{ type: i0.Input, args: [{ isSignal: true, alias: "selection", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], weekNumber: [{ type: i0.Input, args: [{ isSignal: true, alias: "weekNumber", required: false }] }] } });
1616
+ "[class]": "baseClass()",
1617
+ "(focusin)": "refreshToday()",
1618
+ "(focusout)": "onFocusOut($event)"
1619
+ }, template: "<div [class]=\"headerClass()\">\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [size]=\"'small'\"\n [disabled]=\"disabled() || todayUnavailable()\"\n (click)=\"onTodayButtonClick()\"\n [attr.aria-label]=\"todayButtonLabel()\">\n <span>{{ messages().today }}</span>\n </button>\n @switch (calendarView()) {\n @case (\"month\") {\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [disabled]=\"disabled()\"\n (click)=\"onViewChangeClick('year')\"\n [attr.aria-label]=\"viewSwitchButtonLabel()\">\n <span class=\"text-primary font-semibold\" [id]=\"gridId + '-heading'\">{{\n headerMonthYear()\n }}</span>\n </button>\n }\n @case (\"year\") {\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [disabled]=\"disabled()\"\n (click)=\"onViewChangeClick('decade')\"\n [attr.aria-label]=\"viewSwitchButtonLabel()\">\n <span class=\"text-primary font-semibold\" [id]=\"gridId + '-heading'\">{{\n headerYear()\n }}</span>\n </button>\n }\n @case (\"decade\") {\n <!-- The decade is the top view, so its heading isn't a button. It names the grid with the locale's\n wording of the range, and shows the digits. -->\n <span\n class=\"text-primary inline-flex h-9 items-center px-4 text-sm font-semibold\"\n [id]=\"gridId + '-heading'\"\n ><span aria-hidden=\"true\">{{ formatInteger(decadeStart()) }} - {{ formatInteger(decadeEnd()) }}</span\n ><span class=\"sr-only\">{{ viewSwitchButtonLabel() }}</span></span\n >\n }\n }\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [iconOnly]=\"true\"\n [size]=\"'small'\"\n [disabled]=\"disabled()\"\n (click)=\"onNavigationClick('prev')\"\n [attr.aria-label]=\"prevButtonLabel()\">\n <svg lucideChevronLeft class=\"rtl:rotate-180\"></svg>\n </button>\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [iconOnly]=\"true\"\n [size]=\"'small'\"\n [disabled]=\"disabled()\"\n (click)=\"onNavigationClick('next')\"\n [attr.aria-label]=\"nextButtonLabel()\">\n <svg lucideChevronRight class=\"rtl:rotate-180\"></svg>\n </button>\n</div>\n\n<div aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\">{{ ariaLabel() }}</div>\n\n@if (calendarView() === \"month\") {\n @let columnCount = weekNumber() ? 8 : 7;\n <div\n role=\"grid\"\n class=\"flex flex-col gap-0.5\"\n [attr.aria-labelledby]=\"gridId + '-heading'\"\n [attr.aria-disabled]=\"disabled() || null\"\n [attr.aria-invalid]=\"invalidState() ? 'true' : null\"\n [attr.aria-readonly]=\"readonly() || null\"\n [attr.aria-required]=\"required() || null\"\n (pointerleave)=\"onMonthGridPointerLeave()\">\n <div role=\"row\" [class]=\"monthGridHeaderClass()\" [style.grid-template-columns]=\"`repeat(${columnCount}, 32px)`\">\n @if (weekNumber()) {\n <!-- Week numbers are visual only: every day is already named by its full date. -->\n <div aria-hidden=\"true\"></div>\n }\n @for (day of weekdays(); track day.full) {\n <div role=\"columnheader\">\n <span aria-hidden=\"true\">{{ day.display }}</span>\n <span class=\"sr-only\">{{ day.full }}</span>\n </div>\n }\n </div>\n @for (row of monthDictChunked(); track $index) {\n <div role=\"row\" [class]=\"monthGridClass()\" [style.grid-template-columns]=\"`repeat(${columnCount}, 32px)`\">\n @if (weekNumber()) {\n @let firstEntry = row | monaTakeFirst;\n @if (firstEntry) {\n @let week = getWeekNumber(firstEntry.key);\n <div aria-hidden=\"true\">{{ formatInteger(week) }}</div>\n }\n }\n <!-- Track by time: the month is rebuilt with new Date objects on every navigation. -->\n @for (entry of row; track entry.key.getTime()) {\n <div\n (dayPointerEnter)=\"onDayPointerEnter($event)\"\n (daySelect)=\"onDayClick($event.date, $event.event)\"\n monaMonthDay\n [disabled]=\"disabled()\"\n [isDayUnavailable]=\"isDayUnavailable()\"\n [monthBounds]=\"[monthBounds().start, monthBounds().end]\"\n [navigatedDate]=\"navigatedDate()\"\n [rangePreviewKeys]=\"rangePreviewKeys()\"\n [rounded]=\"rounded()\"\n [selectedKeys]=\"selectedKeys()\"\n [today]=\"today()\"\n [entry]=\"entry\">\n @if (monthCellTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"monthCellTemplate()?.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: entry.value, date: entry.key }\"></ng-container>\n } @else {\n <span>{{ formatInteger(entry.value) }}</span>\n }\n </div>\n }\n </div>\n }\n </div>\n} @else if (calendarView() === \"year\") {\n <div role=\"grid\" class=\"flex flex-col gap-0.5\" [attr.aria-labelledby]=\"gridId + '-heading'\">\n @for (row of months(); track $index) {\n <div role=\"row\" [class]=\"yearGridClass()\">\n @for (monthItem of row; track monthItem) {\n <div\n (click)=\"!disabled() && onMonthClick(monthItem[0])\"\n monaYearMonth\n [disabled]=\"disabled()\"\n [month]=\"monthItem[0]\"\n [navigatedDate]=\"navigatedDate()\"\n [rounded]=\"rounded()\"\n [selectedDate]=\"selectedDates()[0]\">\n @if (yearCellTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"yearCellTemplate()?.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: monthItem[0], text: monthItem[1] }\">\n </ng-container>\n } @else {\n <span>{{ monthItem[1] }}</span>\n }\n </div>\n }\n </div>\n }\n </div>\n} @else if (calendarView() === \"decade\") {\n <div role=\"grid\" class=\"flex flex-col gap-0.5\" [attr.aria-labelledby]=\"gridId + '-heading'\">\n @for (row of decadeYears(); track $index) {\n <div role=\"row\" [class]=\"decadeGridClass()\">\n @for (year of row; track year) {\n <div\n (click)=\"!disabled() && onYearClick(year)\"\n monaDecadeYear\n [disabled]=\"disabled()\"\n [navigatedDate]=\"navigatedDate()\"\n [rounded]=\"rounded()\"\n [year]=\"year\"\n [selectedDate]=\"selectedDates()[0]\">\n @if (decadeCellTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"decadeCellTemplate()?.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: year }\">\n </ng-container>\n } @else {\n <span>{{ formatInteger(year) }}</span>\n }\n </div>\n }\n </div>\n }\n </div>\n}\n" }]
1620
+ }], ctorParameters: () => [], propDecorators: { decadeCellTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => CalendarDecadeCellTemplateDirective), { isSignal: true }] }], monthCellTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => CalendarMonthCellTemplateDirective), { isSignal: true }] }], yearCellTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => CalendarYearCellTemplateDirective), { isSignal: true }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], disabledDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledDates", required: false }] }], firstDay: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstDay", required: false }] }], focusOnMount: [{ type: i0.Input, args: [{ isSignal: true, alias: "focusOnMount", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: false }] }], selection: [{ type: i0.Input, args: [{ isSignal: true, alias: "selection", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], weekNumber: [{ type: i0.Input, args: [{ isSignal: true, alias: "weekNumber", required: false }] }] } });
1562
1621
 
1563
1622
  /*
1564
1623
  * Public API Surface of @nanahoshi/mona-ui/calendar