@ngneers/controls 0.0.1-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/fesm2022/ngneers-controls-accordion.mjs +234 -0
  2. package/fesm2022/ngneers-controls-accordion.mjs.map +1 -0
  3. package/fesm2022/ngneers-controls-api-ng.mjs +959 -0
  4. package/fesm2022/ngneers-controls-api-ng.mjs.map +1 -0
  5. package/fesm2022/ngneers-controls-api-resize.mjs +712 -0
  6. package/fesm2022/ngneers-controls-api-resize.mjs.map +1 -0
  7. package/fesm2022/ngneers-controls-api.mjs +347 -0
  8. package/fesm2022/ngneers-controls-api.mjs.map +1 -0
  9. package/fesm2022/ngneers-controls-avatar.mjs +77 -0
  10. package/fesm2022/ngneers-controls-avatar.mjs.map +1 -0
  11. package/fesm2022/ngneers-controls-base.mjs +620 -0
  12. package/fesm2022/ngneers-controls-base.mjs.map +1 -0
  13. package/fesm2022/ngneers-controls-breadcrumb.mjs +100 -0
  14. package/fesm2022/ngneers-controls-breadcrumb.mjs.map +1 -0
  15. package/fesm2022/ngneers-controls-button-group.mjs +110 -0
  16. package/fesm2022/ngneers-controls-button-group.mjs.map +1 -0
  17. package/fesm2022/ngneers-controls-button.mjs +83 -0
  18. package/fesm2022/ngneers-controls-button.mjs.map +1 -0
  19. package/fesm2022/ngneers-controls-calendar-time-CJT5AFlA.mjs +74 -0
  20. package/fesm2022/ngneers-controls-calendar-time-CJT5AFlA.mjs.map +1 -0
  21. package/fesm2022/ngneers-controls-calendar.mjs +801 -0
  22. package/fesm2022/ngneers-controls-calendar.mjs.map +1 -0
  23. package/fesm2022/ngneers-controls-checkbox.mjs +63 -0
  24. package/fesm2022/ngneers-controls-checkbox.mjs.map +1 -0
  25. package/fesm2022/ngneers-controls-chip.mjs +55 -0
  26. package/fesm2022/ngneers-controls-chip.mjs.map +1 -0
  27. package/fesm2022/ngneers-controls-default-icons.mjs +82 -0
  28. package/fesm2022/ngneers-controls-default-icons.mjs.map +1 -0
  29. package/fesm2022/ngneers-controls-defer.mjs +72 -0
  30. package/fesm2022/ngneers-controls-defer.mjs.map +1 -0
  31. package/fesm2022/ngneers-controls-dialog.mjs +407 -0
  32. package/fesm2022/ngneers-controls-dialog.mjs.map +1 -0
  33. package/fesm2022/ngneers-controls-directives.mjs +498 -0
  34. package/fesm2022/ngneers-controls-directives.mjs.map +1 -0
  35. package/fesm2022/ngneers-controls-drawer.mjs +271 -0
  36. package/fesm2022/ngneers-controls-drawer.mjs.map +1 -0
  37. package/fesm2022/ngneers-controls-edit-inplace.mjs +127 -0
  38. package/fesm2022/ngneers-controls-edit-inplace.mjs.map +1 -0
  39. package/fesm2022/ngneers-controls-errors.mjs +329 -0
  40. package/fesm2022/ngneers-controls-errors.mjs.map +1 -0
  41. package/fesm2022/ngneers-controls-filter.mjs +708 -0
  42. package/fesm2022/ngneers-controls-filter.mjs.map +1 -0
  43. package/fesm2022/ngneers-controls-hint.mjs +153 -0
  44. package/fesm2022/ngneers-controls-hint.mjs.map +1 -0
  45. package/fesm2022/ngneers-controls-i18n-translations-de.mjs +170 -0
  46. package/fesm2022/ngneers-controls-i18n-translations-de.mjs.map +1 -0
  47. package/fesm2022/ngneers-controls-i18n-translations-en.mjs +170 -0
  48. package/fesm2022/ngneers-controls-i18n-translations-en.mjs.map +1 -0
  49. package/fesm2022/ngneers-controls-i18n.mjs +57 -0
  50. package/fesm2022/ngneers-controls-i18n.mjs.map +1 -0
  51. package/fesm2022/ngneers-controls-icon.mjs +195 -0
  52. package/fesm2022/ngneers-controls-icon.mjs.map +1 -0
  53. package/fesm2022/ngneers-controls-inplace.mjs +150 -0
  54. package/fesm2022/ngneers-controls-inplace.mjs.map +1 -0
  55. package/fesm2022/ngneers-controls-input-field.mjs +165 -0
  56. package/fesm2022/ngneers-controls-input-field.mjs.map +1 -0
  57. package/fesm2022/ngneers-controls-input.mjs +72 -0
  58. package/fesm2022/ngneers-controls-input.mjs.map +1 -0
  59. package/fesm2022/ngneers-controls-item-view.mjs +473 -0
  60. package/fesm2022/ngneers-controls-item-view.mjs.map +1 -0
  61. package/fesm2022/ngneers-controls-list-box.mjs +281 -0
  62. package/fesm2022/ngneers-controls-list-box.mjs.map +1 -0
  63. package/fesm2022/ngneers-controls-mask-input.mjs +888 -0
  64. package/fesm2022/ngneers-controls-mask-input.mjs.map +1 -0
  65. package/fesm2022/ngneers-controls-menu.mjs +371 -0
  66. package/fesm2022/ngneers-controls-menu.mjs.map +1 -0
  67. package/fesm2022/ngneers-controls-message.mjs +30 -0
  68. package/fesm2022/ngneers-controls-message.mjs.map +1 -0
  69. package/fesm2022/ngneers-controls-number-input.mjs +366 -0
  70. package/fesm2022/ngneers-controls-number-input.mjs.map +1 -0
  71. package/fesm2022/ngneers-controls-paginator.mjs +129 -0
  72. package/fesm2022/ngneers-controls-paginator.mjs.map +1 -0
  73. package/fesm2022/ngneers-controls-popover.mjs +215 -0
  74. package/fesm2022/ngneers-controls-popover.mjs.map +1 -0
  75. package/fesm2022/ngneers-controls-progress.mjs +98 -0
  76. package/fesm2022/ngneers-controls-progress.mjs.map +1 -0
  77. package/fesm2022/ngneers-controls-radio.mjs +152 -0
  78. package/fesm2022/ngneers-controls-radio.mjs.map +1 -0
  79. package/fesm2022/ngneers-controls-roving-focus.mjs +323 -0
  80. package/fesm2022/ngneers-controls-roving-focus.mjs.map +1 -0
  81. package/fesm2022/ngneers-controls-scroll-shadow.mjs +65 -0
  82. package/fesm2022/ngneers-controls-scroll-shadow.mjs.map +1 -0
  83. package/fesm2022/ngneers-controls-scroller.mjs +308 -0
  84. package/fesm2022/ngneers-controls-scroller.mjs.map +1 -0
  85. package/fesm2022/ngneers-controls-select-button.mjs +58 -0
  86. package/fesm2022/ngneers-controls-select-button.mjs.map +1 -0
  87. package/fesm2022/ngneers-controls-select.mjs +417 -0
  88. package/fesm2022/ngneers-controls-select.mjs.map +1 -0
  89. package/fesm2022/ngneers-controls-slider.mjs +167 -0
  90. package/fesm2022/ngneers-controls-slider.mjs.map +1 -0
  91. package/fesm2022/ngneers-controls-snackbar.mjs +414 -0
  92. package/fesm2022/ngneers-controls-snackbar.mjs.map +1 -0
  93. package/fesm2022/ngneers-controls-spin-buttons.mjs +126 -0
  94. package/fesm2022/ngneers-controls-spin-buttons.mjs.map +1 -0
  95. package/fesm2022/ngneers-controls-spinner.mjs +184 -0
  96. package/fesm2022/ngneers-controls-spinner.mjs.map +1 -0
  97. package/fesm2022/ngneers-controls-splitter.mjs +604 -0
  98. package/fesm2022/ngneers-controls-splitter.mjs.map +1 -0
  99. package/fesm2022/ngneers-controls-state.mjs +185 -0
  100. package/fesm2022/ngneers-controls-state.mjs.map +1 -0
  101. package/fesm2022/ngneers-controls-switch.mjs +39 -0
  102. package/fesm2022/ngneers-controls-switch.mjs.map +1 -0
  103. package/fesm2022/ngneers-controls-table.mjs +2634 -0
  104. package/fesm2022/ngneers-controls-table.mjs.map +1 -0
  105. package/fesm2022/ngneers-controls-tabs.mjs +336 -0
  106. package/fesm2022/ngneers-controls-tabs.mjs.map +1 -0
  107. package/fesm2022/ngneers-controls-tag.mjs +30 -0
  108. package/fesm2022/ngneers-controls-tag.mjs.map +1 -0
  109. package/fesm2022/ngneers-controls-toast.mjs +350 -0
  110. package/fesm2022/ngneers-controls-toast.mjs.map +1 -0
  111. package/fesm2022/ngneers-controls-toggle-button.mjs +70 -0
  112. package/fesm2022/ngneers-controls-toggle-button.mjs.map +1 -0
  113. package/fesm2022/ngneers-controls-tooltip.mjs +506 -0
  114. package/fesm2022/ngneers-controls-tooltip.mjs.map +1 -0
  115. package/fesm2022/ngneers-controls-tree.mjs +599 -0
  116. package/fesm2022/ngneers-controls-tree.mjs.map +1 -0
  117. package/fesm2022/ngneers-controls-upload.mjs +377 -0
  118. package/fesm2022/ngneers-controls-upload.mjs.map +1 -0
  119. package/fesm2022/ngneers-controls-utils-ng.mjs +411 -0
  120. package/fesm2022/ngneers-controls-utils-ng.mjs.map +1 -0
  121. package/fesm2022/ngneers-controls-utils.mjs +261 -0
  122. package/fesm2022/ngneers-controls-utils.mjs.map +1 -0
  123. package/fesm2022/ngneers-controls.mjs +6 -0
  124. package/fesm2022/ngneers-controls.mjs.map +1 -0
  125. package/package.json +302 -0
  126. package/types/ngneers-controls-accordion.d.ts +139 -0
  127. package/types/ngneers-controls-api-ng.d.ts +364 -0
  128. package/types/ngneers-controls-api-resize.d.ts +318 -0
  129. package/types/ngneers-controls-api.d.ts +145 -0
  130. package/types/ngneers-controls-avatar.d.ts +54 -0
  131. package/types/ngneers-controls-base.d.ts +277 -0
  132. package/types/ngneers-controls-breadcrumb.d.ts +272 -0
  133. package/types/ngneers-controls-button-group.d.ts +46 -0
  134. package/types/ngneers-controls-button.d.ts +48 -0
  135. package/types/ngneers-controls-calendar.d.ts +466 -0
  136. package/types/ngneers-controls-checkbox.d.ts +40 -0
  137. package/types/ngneers-controls-chip.d.ts +202 -0
  138. package/types/ngneers-controls-default-icons.d.ts +5 -0
  139. package/types/ngneers-controls-defer.d.ts +48 -0
  140. package/types/ngneers-controls-dialog.d.ts +399 -0
  141. package/types/ngneers-controls-directives.d.ts +171 -0
  142. package/types/ngneers-controls-drawer.d.ts +308 -0
  143. package/types/ngneers-controls-edit-inplace.d.ts +263 -0
  144. package/types/ngneers-controls-errors.d.ts +155 -0
  145. package/types/ngneers-controls-filter.d.ts +609 -0
  146. package/types/ngneers-controls-hint.d.ts +88 -0
  147. package/types/ngneers-controls-i18n-translations-de.d.ts +164 -0
  148. package/types/ngneers-controls-i18n-translations-en.d.ts +164 -0
  149. package/types/ngneers-controls-i18n.d.ts +186 -0
  150. package/types/ngneers-controls-icon.d.ts +68 -0
  151. package/types/ngneers-controls-inplace.d.ts +98 -0
  152. package/types/ngneers-controls-input-field.d.ts +248 -0
  153. package/types/ngneers-controls-input.d.ts +30 -0
  154. package/types/ngneers-controls-item-view.d.ts +215 -0
  155. package/types/ngneers-controls-list-box.d.ts +334 -0
  156. package/types/ngneers-controls-mask-input.d.ts +434 -0
  157. package/types/ngneers-controls-menu.d.ts +192 -0
  158. package/types/ngneers-controls-message.d.ts +21 -0
  159. package/types/ngneers-controls-number-input.d.ts +146 -0
  160. package/types/ngneers-controls-paginator.d.ts +255 -0
  161. package/types/ngneers-controls-popover.d.ts +116 -0
  162. package/types/ngneers-controls-progress.d.ts +49 -0
  163. package/types/ngneers-controls-radio.d.ts +91 -0
  164. package/types/ngneers-controls-roving-focus.d.ts +107 -0
  165. package/types/ngneers-controls-scroll-shadow.d.ts +25 -0
  166. package/types/ngneers-controls-scroller.d.ts +151 -0
  167. package/types/ngneers-controls-select-button.d.ts +51 -0
  168. package/types/ngneers-controls-select.d.ts +409 -0
  169. package/types/ngneers-controls-slider.d.ts +57 -0
  170. package/types/ngneers-controls-snackbar.d.ts +330 -0
  171. package/types/ngneers-controls-spin-buttons.d.ts +69 -0
  172. package/types/ngneers-controls-spinner.d.ts +117 -0
  173. package/types/ngneers-controls-splitter.d.ts +465 -0
  174. package/types/ngneers-controls-state.d.ts +102 -0
  175. package/types/ngneers-controls-switch.d.ts +18 -0
  176. package/types/ngneers-controls-table.d.ts +3127 -0
  177. package/types/ngneers-controls-tabs.d.ts +118 -0
  178. package/types/ngneers-controls-tag.d.ts +21 -0
  179. package/types/ngneers-controls-toast.d.ts +298 -0
  180. package/types/ngneers-controls-toggle-button.d.ts +48 -0
  181. package/types/ngneers-controls-tooltip.d.ts +189 -0
  182. package/types/ngneers-controls-tree.d.ts +409 -0
  183. package/types/ngneers-controls-upload.d.ts +347 -0
  184. package/types/ngneers-controls-utils-ng.d.ts +129 -0
  185. package/types/ngneers-controls-utils.d.ts +130 -0
  186. package/types/ngneers-controls.d.ts +2 -0
@@ -0,0 +1,801 @@
1
+ import { NgTemplateOutlet } from '@angular/common';
2
+ import * as i0 from '@angular/core';
3
+ import { viewChild, contentChild, input, computed, Directive, output, inject, viewChildren, Component, booleanAttribute, linkedSignal, signal, effect } from '@angular/core';
4
+ import { templateTypesFn, Platform, NgnTemplate } from '@ngneers/controls/api/ng';
5
+ import { ValueControlBase, NgnPt, provideSelf } from '@ngneers/controls/base';
6
+ import { I18n } from '@ngneers/controls/i18n';
7
+ import { NgnIcon } from '@ngneers/controls/icon';
8
+ import { NgnMaskInput, getDateOrTimeMask } from '@ngneers/controls/mask-input';
9
+ import { NgnPopover } from '@ngneers/controls/popover';
10
+ import { throwExp, NgnError } from '@ngneers/controls/utils';
11
+ import { calendarControlTemplate } from '@ngneers/controls-themes/templates/calendar';
12
+ import { NgnButton } from '@ngneers/controls/button';
13
+
14
+ class CalendarTemplates extends ValueControlBase {
15
+ // Day template
16
+ _defaultDayTemplate = viewChild.required('defaultDayTemplate');
17
+ _userDayTemplate = contentChild('day', /* @ts-ignore */
18
+ ...(ngDevMode ? [{ debugName: "_userDayTemplate" }] : /* istanbul ignore next */ []));
19
+ /**
20
+ * Set a custom template for a day.
21
+ * Can also be set using an `<ng-template>` element with `#day` template reference variable.
22
+ */
23
+ templateDay = input(null, /* @ts-ignore */
24
+ ...(ngDevMode ? [{ debugName: "templateDay" }] : /* istanbul ignore next */ []));
25
+ dayTemplate = computed(() => this._userDayTemplate() ?? this.templateDay() ?? this._defaultDayTemplate(), /* @ts-ignore */
26
+ ...(ngDevMode ? [{ debugName: "dayTemplate" }] : /* istanbul ignore next */ []));
27
+ // Week day template
28
+ _defaultWeekDayTemplate = viewChild.required('defaultWeekDayTemplate');
29
+ _userWeekDayTemplate = contentChild('weekDay', /* @ts-ignore */
30
+ ...(ngDevMode ? [{ debugName: "_userWeekDayTemplate" }] : /* istanbul ignore next */ []));
31
+ /**
32
+ * Set a custom template for a week day.
33
+ * Can also be set using an `<ng-template>` element with `#weekDay` template reference variable.
34
+ */
35
+ templateWeekDay = input(null, /* @ts-ignore */
36
+ ...(ngDevMode ? [{ debugName: "templateWeekDay" }] : /* istanbul ignore next */ []));
37
+ weekDayTemplate = computed(() => this._userWeekDayTemplate() ?? this.templateWeekDay() ?? this._defaultWeekDayTemplate(), /* @ts-ignore */
38
+ ...(ngDevMode ? [{ debugName: "weekDayTemplate" }] : /* istanbul ignore next */ []));
39
+ // Month template
40
+ _defaultMonthTemplate = viewChild.required('defaultMonthTemplate');
41
+ _userMonthTemplate = contentChild('month', /* @ts-ignore */
42
+ ...(ngDevMode ? [{ debugName: "_userMonthTemplate" }] : /* istanbul ignore next */ []));
43
+ /**
44
+ * Set a custom template for a month.
45
+ * Can also be set using an `<ng-template>` element with `#month` template reference variable.
46
+ */
47
+ templateMonth = input(null, /* @ts-ignore */
48
+ ...(ngDevMode ? [{ debugName: "templateMonth" }] : /* istanbul ignore next */ []));
49
+ monthTemplate = computed(() => this._userMonthTemplate() ?? this.templateMonth() ?? this._defaultMonthTemplate(), /* @ts-ignore */
50
+ ...(ngDevMode ? [{ debugName: "monthTemplate" }] : /* istanbul ignore next */ []));
51
+ // Time template
52
+ _defaultTimeTemplate = viewChild.required('defaultTimeTemplate');
53
+ _userTimeTemplate = contentChild('time', /* @ts-ignore */
54
+ ...(ngDevMode ? [{ debugName: "_userTimeTemplate" }] : /* istanbul ignore next */ []));
55
+ /**
56
+ * Set a custom template for the time input.
57
+ * Can also be set using an `<ng-template>` element with `#time` template reference variable.
58
+ */
59
+ templateTime = input(null, /* @ts-ignore */
60
+ ...(ngDevMode ? [{ debugName: "templateTime" }] : /* istanbul ignore next */ []));
61
+ timeTemplate = computed(() => this._userTimeTemplate() ?? this.templateTime() ?? this._defaultTimeTemplate(), /* @ts-ignore */
62
+ ...(ngDevMode ? [{ debugName: "timeTemplate" }] : /* istanbul ignore next */ []));
63
+ // Year template
64
+ _defaultYearTemplate = viewChild.required('defaultYearTemplate');
65
+ _userYearTemplate = contentChild('year', /* @ts-ignore */
66
+ ...(ngDevMode ? [{ debugName: "_userYearTemplate" }] : /* istanbul ignore next */ []));
67
+ /**
68
+ * Set a custom template for the year input.
69
+ * Can also be set using an `<ng-template>` element with `#year` template reference variable.
70
+ */
71
+ templateYear = input(null, /* @ts-ignore */
72
+ ...(ngDevMode ? [{ debugName: "templateYear" }] : /* istanbul ignore next */ []));
73
+ yearTemplate = computed(() => this._userYearTemplate() ?? this.templateYear() ?? this._defaultYearTemplate(), /* @ts-ignore */
74
+ ...(ngDevMode ? [{ debugName: "yearTemplate" }] : /* istanbul ignore next */ []));
75
+ /**
76
+ * Types for the calendar templates.
77
+ */
78
+ templateTypes = templateTypesFn();
79
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: CalendarTemplates, deps: null, target: i0.ɵɵFactoryTarget.Directive });
80
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "22.0.5", type: CalendarTemplates, isStandalone: true, inputs: { templateDay: { classPropertyName: "templateDay", publicName: "templateDay", isSignal: true, isRequired: false, transformFunction: null }, templateWeekDay: { classPropertyName: "templateWeekDay", publicName: "templateWeekDay", isSignal: true, isRequired: false, transformFunction: null }, templateMonth: { classPropertyName: "templateMonth", publicName: "templateMonth", isSignal: true, isRequired: false, transformFunction: null }, templateTime: { classPropertyName: "templateTime", publicName: "templateTime", isSignal: true, isRequired: false, transformFunction: null }, templateYear: { classPropertyName: "templateYear", publicName: "templateYear", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "_userDayTemplate", first: true, predicate: ["day"], descendants: true, isSignal: true }, { propertyName: "_userWeekDayTemplate", first: true, predicate: ["weekDay"], descendants: true, isSignal: true }, { propertyName: "_userMonthTemplate", first: true, predicate: ["month"], descendants: true, isSignal: true }, { propertyName: "_userTimeTemplate", first: true, predicate: ["time"], descendants: true, isSignal: true }, { propertyName: "_userYearTemplate", first: true, predicate: ["year"], descendants: true, isSignal: true }], viewQueries: [{ propertyName: "_defaultDayTemplate", first: true, predicate: ["defaultDayTemplate"], descendants: true, isSignal: true }, { propertyName: "_defaultWeekDayTemplate", first: true, predicate: ["defaultWeekDayTemplate"], descendants: true, isSignal: true }, { propertyName: "_defaultMonthTemplate", first: true, predicate: ["defaultMonthTemplate"], descendants: true, isSignal: true }, { propertyName: "_defaultTimeTemplate", first: true, predicate: ["defaultTimeTemplate"], descendants: true, isSignal: true }, { propertyName: "_defaultYearTemplate", first: true, predicate: ["defaultYearTemplate"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0 });
81
+ }
82
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: CalendarTemplates, decorators: [{
83
+ type: Directive
84
+ }], propDecorators: { _defaultDayTemplate: [{ type: i0.ViewChild, args: ['defaultDayTemplate', { isSignal: true }] }], _userDayTemplate: [{ type: i0.ContentChild, args: ['day', { isSignal: true }] }], templateDay: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateDay", required: false }] }], _defaultWeekDayTemplate: [{ type: i0.ViewChild, args: ['defaultWeekDayTemplate', { isSignal: true }] }], _userWeekDayTemplate: [{ type: i0.ContentChild, args: ['weekDay', { isSignal: true }] }], templateWeekDay: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateWeekDay", required: false }] }], _defaultMonthTemplate: [{ type: i0.ViewChild, args: ['defaultMonthTemplate', { isSignal: true }] }], _userMonthTemplate: [{ type: i0.ContentChild, args: ['month', { isSignal: true }] }], templateMonth: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateMonth", required: false }] }], _defaultTimeTemplate: [{ type: i0.ViewChild, args: ['defaultTimeTemplate', { isSignal: true }] }], _userTimeTemplate: [{ type: i0.ContentChild, args: ['time', { isSignal: true }] }], templateTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateTime", required: false }] }], _defaultYearTemplate: [{ type: i0.ViewChild, args: ['defaultYearTemplate', { isSignal: true }] }], _userYearTemplate: [{ type: i0.ContentChild, args: ['year', { isSignal: true }] }], templateYear: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateYear", required: false }] }] } });
85
+
86
+ const MONTHS = [
87
+ 'january',
88
+ 'february',
89
+ 'march',
90
+ 'april',
91
+ 'may',
92
+ 'june',
93
+ 'july',
94
+ 'august',
95
+ 'september',
96
+ 'october',
97
+ 'november',
98
+ 'december',
99
+ ];
100
+ const WEEK_DAYS = [
101
+ 'sunday',
102
+ 'monday',
103
+ 'tuesday',
104
+ 'wednesday',
105
+ 'thursday',
106
+ 'friday',
107
+ 'saturday',
108
+ ];
109
+
110
+ // Configuration: Number of weeks to show before and after the current month
111
+ const WEEKS_BEFORE = 1;
112
+ const WEEKS_AFTER = 1;
113
+ class CalendarDays {
114
+ component = input.required(/* @ts-ignore */
115
+ ...(ngDevMode ? [{ debugName: "component" }] : /* istanbul ignore next */ []));
116
+ theme = input.required(/* @ts-ignore */
117
+ ...(ngDevMode ? [{ debugName: "theme" }] : /* istanbul ignore next */ []));
118
+ year = input.required(/* @ts-ignore */
119
+ ...(ngDevMode ? [{ debugName: "year" }] : /* istanbul ignore next */ []));
120
+ month = input.required(/* @ts-ignore */
121
+ ...(ngDevMode ? [{ debugName: "month" }] : /* istanbul ignore next */ []));
122
+ currentValue = input.required(/* @ts-ignore */
123
+ ...(ngDevMode ? [{ debugName: "currentValue" }] : /* istanbul ignore next */ []));
124
+ firstDayOfWeek = input.required(/* @ts-ignore */
125
+ ...(ngDevMode ? [{ debugName: "firstDayOfWeek" }] : /* istanbul ignore next */ []));
126
+ dayTemplate = input.required(/* @ts-ignore */
127
+ ...(ngDevMode ? [{ debugName: "dayTemplate" }] : /* istanbul ignore next */ []));
128
+ weekDayTemplate = input.required(/* @ts-ignore */
129
+ ...(ngDevMode ? [{ debugName: "weekDayTemplate" }] : /* istanbul ignore next */ []));
130
+ timeTemplate = input.required(/* @ts-ignore */
131
+ ...(ngDevMode ? [{ debugName: "timeTemplate" }] : /* istanbul ignore next */ []));
132
+ yearTemplate = input.required(/* @ts-ignore */
133
+ ...(ngDevMode ? [{ debugName: "yearTemplate" }] : /* istanbul ignore next */ []));
134
+ monthTemplate = input.required(/* @ts-ignore */
135
+ ...(ngDevMode ? [{ debugName: "monthTemplate" }] : /* istanbul ignore next */ []));
136
+ showTime = input.required(/* @ts-ignore */
137
+ ...(ngDevMode ? [{ debugName: "showTime" }] : /* istanbul ignore next */ []));
138
+ showSeconds = input.required(/* @ts-ignore */
139
+ ...(ngDevMode ? [{ debugName: "showSeconds" }] : /* istanbul ignore next */ []));
140
+ previousMonth = output();
141
+ nextMonth = output();
142
+ daySelected = output();
143
+ yearSelected = output();
144
+ monthSelected = output();
145
+ timeChanged = output();
146
+ MONTHS = MONTHS;
147
+ i18n = inject(I18n).translations;
148
+ todaysDay = new Date().getDate();
149
+ todaysMonth = new Date().getMonth();
150
+ todaysYear = new Date().getFullYear();
151
+ doTimeChange = (t) => this.timeChanged.emit(t);
152
+ doYearChange = (t) => this.yearSelected.emit(t);
153
+ doMonthChange = (t) => this.monthSelected.emit(t);
154
+ weekDaysSorted = computed(() => WEEK_DAYS.slice(this._firstDayOfWeekIndex())
155
+ .concat(WEEK_DAYS.slice(0, this._firstDayOfWeekIndex()))
156
+ .map(day => ({
157
+ weekDay: day,
158
+ translation: this.i18n[`calendar_weekdaysShort_${day}`],
159
+ })), /* @ts-ignore */
160
+ ...(ngDevMode ? [{ debugName: "weekDaysSorted" }] : /* istanbul ignore next */ []));
161
+ _dayButton = viewChildren('dayButton', /* @ts-ignore */
162
+ ...(ngDevMode ? [{ debugName: "_dayButton" }] : /* istanbul ignore next */ []));
163
+ _firstDayOfWeekIndex = computed(() => WEEK_DAYS.indexOf(this.firstDayOfWeek()), /* @ts-ignore */
164
+ ...(ngDevMode ? [{ debugName: "_firstDayOfWeekIndex" }] : /* istanbul ignore next */ []));
165
+ _daysInMonth = computed(() => new Date(this.year(), this.month() + 1, 0).getDate(), /* @ts-ignore */
166
+ ...(ngDevMode ? [{ debugName: "_daysInMonth" }] : /* istanbul ignore next */ []));
167
+ _daysInPreviousMonth = computed(() => new Date(this.year(), this.month(), 0).getDate(), /* @ts-ignore */
168
+ ...(ngDevMode ? [{ debugName: "_daysInPreviousMonth" }] : /* istanbul ignore next */ []));
169
+ _firstDayOfMonth = computed(() => new Date(this.year(), this.month(), 1).getDay(), /* @ts-ignore */
170
+ ...(ngDevMode ? [{ debugName: "_firstDayOfMonth" }] : /* istanbul ignore next */ []));
171
+ monthModel = computed(() => {
172
+ const firstDayOfMonth = this._firstDayOfMonth();
173
+ const firstDayOfWeek = this._firstDayOfWeekIndex();
174
+ const daysInMonth = this._daysInMonth();
175
+ const daysInPreviousMonth = this._daysInPreviousMonth();
176
+ // Calculate starting point and total days needed
177
+ const firstDayOffset = (firstDayOfMonth - firstDayOfWeek + 7) % 7;
178
+ const daysFromPreviousMonth = firstDayOffset + WEEKS_BEFORE * 7;
179
+ const daysToNextMonth = (7 - ((daysFromPreviousMonth + daysInMonth) % 7)) % 7;
180
+ const totalDays = daysFromPreviousMonth + daysInMonth + daysToNextMonth + WEEKS_AFTER * 7;
181
+ const startDay = daysInPreviousMonth - daysFromPreviousMonth + 1;
182
+ // Build all days in one pass
183
+ const allDays = [];
184
+ let currentDate = startDay;
185
+ let currentMonth = -1; // -1 = previous, 0 = current, 1 = next
186
+ for (let i = 0; i < totalDays; i++) {
187
+ // Determine which month we're in
188
+ if (currentDate > daysInPreviousMonth && currentMonth === -1) {
189
+ currentDate = 1;
190
+ currentMonth = 0;
191
+ }
192
+ else if (currentDate > daysInMonth && currentMonth === 0) {
193
+ currentDate = 1;
194
+ currentMonth = 1;
195
+ }
196
+ allDays.push({
197
+ date: currentDate,
198
+ monthOffset: currentMonth,
199
+ });
200
+ currentDate++;
201
+ }
202
+ // Group into weeks
203
+ const weeks = [];
204
+ for (let i = 0; i < allDays.length; i += 7) {
205
+ weeks.push({
206
+ days: allDays.slice(i, i + 7),
207
+ });
208
+ }
209
+ return { weeks };
210
+ }, /* @ts-ignore */
211
+ ...(ngDevMode ? [{ debugName: "monthModel" }] : /* istanbul ignore next */ []));
212
+ tabFocusDay = computed(() => {
213
+ const val = this.currentValue();
214
+ if (val && val.getMonth() === this.month() && val.getFullYear() === this.year()) {
215
+ return val.getDate();
216
+ }
217
+ return 1;
218
+ }, /* @ts-ignore */
219
+ ...(ngDevMode ? [{ debugName: "tabFocusDay" }] : /* istanbul ignore next */ []));
220
+ /** Accessible name of the day grid — the visible month and year. */
221
+ gridLabel = computed(() => new Date(this.year(), this.month(), 1).toLocaleDateString(undefined, {
222
+ month: 'long',
223
+ year: 'numeric',
224
+ }), /* @ts-ignore */
225
+ ...(ngDevMode ? [{ debugName: "gridLabel" }] : /* istanbul ignore next */ []));
226
+ /** Full, localized date used as each day cell's accessible name (e.g. "Thursday, 15 January 2026"). */
227
+ dayLabel(day) {
228
+ return new Date(this.year(), this.month() + day.monthOffset, day.date).toLocaleDateString(undefined, { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
229
+ }
230
+ /** Whether the given day cell holds the currently selected value. */
231
+ isSelected(day) {
232
+ const val = this.currentValue();
233
+ return (!!val &&
234
+ val.getDate() === day.date &&
235
+ val.getMonth() === this.month() + day.monthOffset &&
236
+ val.getFullYear() === this.year());
237
+ }
238
+ /** Whether the given day cell is today. */
239
+ isToday(day) {
240
+ return (this.todaysMonth === this.month() + day.monthOffset &&
241
+ this.todaysDay === day.date &&
242
+ this.todaysYear === this.year());
243
+ }
244
+ prev() {
245
+ this.previousMonth.emit();
246
+ }
247
+ next() {
248
+ this.nextMonth.emit();
249
+ }
250
+ selectYear(year) {
251
+ this.yearSelected.emit(year);
252
+ }
253
+ dayKeydown(event, day) {
254
+ if (['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(event.key)) {
255
+ event.preventDefault();
256
+ const getCurrentMonthButtons = () => {
257
+ return this._dayButton()
258
+ .map(ref => ref.nativeElement)
259
+ .filter(x => !x.classList.contains(this.theme().class('day-other-month')));
260
+ };
261
+ const allDayButtons = getCurrentMonthButtons();
262
+ const index = allDayButtons.indexOf(day);
263
+ const daysInMonth = this._daysInMonth();
264
+ if (event.key === 'ArrowRight') {
265
+ if (index < daysInMonth - 1) {
266
+ allDayButtons[index + 1]?.focus();
267
+ }
268
+ else {
269
+ this.next();
270
+ setTimeout(() => {
271
+ getCurrentMonthButtons()[0]?.focus();
272
+ });
273
+ }
274
+ }
275
+ else if (event.key === 'ArrowLeft') {
276
+ if (index > 0) {
277
+ allDayButtons[index - 1]?.focus();
278
+ }
279
+ else {
280
+ this.prev();
281
+ setTimeout(() => {
282
+ const buttons = getCurrentMonthButtons();
283
+ buttons[buttons.length - 1]?.focus();
284
+ });
285
+ }
286
+ }
287
+ else if (event.key === 'ArrowDown') {
288
+ if (index < daysInMonth - 7) {
289
+ allDayButtons[index + 7]?.focus();
290
+ }
291
+ else {
292
+ this.next();
293
+ const nextIndex = (index + 7) % daysInMonth;
294
+ setTimeout(() => {
295
+ getCurrentMonthButtons()[nextIndex]?.focus();
296
+ });
297
+ }
298
+ }
299
+ else if (event.key === 'ArrowUp') {
300
+ if (index >= 7) {
301
+ allDayButtons[index - 7]?.focus();
302
+ }
303
+ else {
304
+ this.prev();
305
+ setTimeout(() => {
306
+ const buttons = getCurrentMonthButtons();
307
+ const targetIndex = Math.min(buttons.length - 7 + index, buttons.length - 1);
308
+ buttons[targetIndex]?.focus();
309
+ });
310
+ }
311
+ }
312
+ }
313
+ }
314
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: CalendarDays, deps: [], target: i0.ɵɵFactoryTarget.Component });
315
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: CalendarDays, isStandalone: true, selector: "ngn-calendar-days", inputs: { component: { classPropertyName: "component", publicName: "component", isSignal: true, isRequired: true, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: true, transformFunction: null }, year: { classPropertyName: "year", publicName: "year", isSignal: true, isRequired: true, transformFunction: null }, month: { classPropertyName: "month", publicName: "month", isSignal: true, isRequired: true, transformFunction: null }, currentValue: { classPropertyName: "currentValue", publicName: "currentValue", isSignal: true, isRequired: true, transformFunction: null }, firstDayOfWeek: { classPropertyName: "firstDayOfWeek", publicName: "firstDayOfWeek", isSignal: true, isRequired: true, transformFunction: null }, dayTemplate: { classPropertyName: "dayTemplate", publicName: "dayTemplate", isSignal: true, isRequired: true, transformFunction: null }, weekDayTemplate: { classPropertyName: "weekDayTemplate", publicName: "weekDayTemplate", isSignal: true, isRequired: true, transformFunction: null }, timeTemplate: { classPropertyName: "timeTemplate", publicName: "timeTemplate", isSignal: true, isRequired: true, transformFunction: null }, yearTemplate: { classPropertyName: "yearTemplate", publicName: "yearTemplate", isSignal: true, isRequired: true, transformFunction: null }, monthTemplate: { classPropertyName: "monthTemplate", publicName: "monthTemplate", isSignal: true, isRequired: true, transformFunction: null }, showTime: { classPropertyName: "showTime", publicName: "showTime", isSignal: true, isRequired: true, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { previousMonth: "previousMonth", nextMonth: "nextMonth", daySelected: "daySelected", yearSelected: "yearSelected", monthSelected: "monthSelected", timeChanged: "timeChanged" }, viewQueries: [{ propertyName: "_dayButton", predicate: ["dayButton"], descendants: true, isSignal: true }], ngImport: i0, template: "<div [ptInt]=\"component()\" [ptClass]=\"'details'\">\n <div [ptInt]=\"component()\" [ptClass]=\"'header'\">\n <div [ptInt]=\"component()\" [ptClass]=\"'navigation'\">\n <button\n ngnButton\n [kind]=\"'icon'\"\n [ptInt]=\"component()\"\n [ptDep]=\"'previous'\"\n [attr.aria-label]=\"i18n['calendar_previousMonth']()\"\n (click)=\"prev()\"\n >\n <ngn-icon [defaultIcon]=\"'calendar-previous-month'\" />\n </button>\n <button\n ngnButton\n [kind]=\"'icon'\"\n [ptInt]=\"component()\"\n [ptDep]=\"'next'\"\n [attr.aria-label]=\"i18n['calendar_nextMonth']()\"\n (click)=\"next()\"\n >\n <ngn-icon [defaultIcon]=\"'calendar-next-month'\" />\n </button>\n </div>\n <ng-container\n *ngTemplateOutlet=\"\n monthTemplate();\n context: {\n $implicit: {\n month: MONTHS[month()],\n change: doMonthChange,\n },\n }\n \"\n />\n\n <ng-container\n *ngTemplateOutlet=\"\n yearTemplate();\n context: {\n $implicit: {\n year: year(),\n change: doYearChange,\n },\n }\n \"\n />\n </div>\n <div class=\"ngn-calendar-days\" role=\"grid\" [attr.aria-label]=\"gridLabel()\">\n <div role=\"row\" style=\"display: contents\">\n @for (weekDay of weekDaysSorted(); track weekDay) {\n <span role=\"columnheader\" [ptInt]=\"component()\" [ptClass]=\"'week-day'\">\n <ng-container\n *ngTemplateOutlet=\"\n weekDayTemplate();\n context: {\n $implicit: {\n weekDay: weekDay.weekDay,\n translation: weekDay.translation(),\n },\n }\n \"\n />\n </span>\n }\n </div>\n @for (item of monthModel().weeks; track $index) {\n <div role=\"row\" style=\"display: contents\">\n @for (day of item.days; track $index) {\n <div\n role=\"gridcell\"\n style=\"display: contents\"\n [attr.aria-selected]=\"isSelected(day) ? 'true' : null\"\n >\n <button\n #dayButton\n [ptInt]=\"component()\"\n [ptClass]=\"{\n day: true,\n 'day-other-month': day.monthOffset !== 0,\n 'day-today': isToday(day),\n 'day-selected': isSelected(day),\n }\"\n [tabIndex]=\"!day.monthOffset && tabFocusDay() === day.date ? 0 : -1\"\n [attr.aria-current]=\"isToday(day) ? 'date' : null\"\n [attr.aria-label]=\"dayLabel(day)\"\n type=\"button\"\n (click)=\"\n daySelected.emit({\n date: day.date,\n monthOffset: day.monthOffset,\n })\n \"\n (keydown)=\"dayKeydown($event, dayButton)\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n dayTemplate();\n context: {\n $implicit: {\n date: day.date,\n fromOtherMonth: day.monthOffset !== 0,\n selected: isSelected(day),\n today: isToday(day),\n },\n }\n \"\n />\n </button>\n </div>\n }\n </div>\n }\n </div>\n @if (showTime()) {\n <ng-container\n *ngTemplateOutlet=\"\n timeTemplate();\n context: {\n $implicit: { time: currentValue(), showSeconds: showSeconds(), change: doTimeChange },\n }\n \"\n />\n }\n</div>\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgnPt, selector: "[ptInt]", inputs: ["ptInt", "ptClass", "ptDep"] }, { kind: "directive", type: NgnButton, selector: "button[ngnButton], a[ngnButton]", inputs: ["ngnButtonInline"], exportAs: ["ngnButton"] }, { kind: "component", type: NgnIcon, selector: "ngn-icon", inputs: ["defaultIcon", "icon"] }] });
316
+ }
317
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: CalendarDays, decorators: [{
318
+ type: Component,
319
+ args: [{ selector: 'ngn-calendar-days', imports: [NgTemplateOutlet, NgnPt, NgnButton, NgnIcon], template: "<div [ptInt]=\"component()\" [ptClass]=\"'details'\">\n <div [ptInt]=\"component()\" [ptClass]=\"'header'\">\n <div [ptInt]=\"component()\" [ptClass]=\"'navigation'\">\n <button\n ngnButton\n [kind]=\"'icon'\"\n [ptInt]=\"component()\"\n [ptDep]=\"'previous'\"\n [attr.aria-label]=\"i18n['calendar_previousMonth']()\"\n (click)=\"prev()\"\n >\n <ngn-icon [defaultIcon]=\"'calendar-previous-month'\" />\n </button>\n <button\n ngnButton\n [kind]=\"'icon'\"\n [ptInt]=\"component()\"\n [ptDep]=\"'next'\"\n [attr.aria-label]=\"i18n['calendar_nextMonth']()\"\n (click)=\"next()\"\n >\n <ngn-icon [defaultIcon]=\"'calendar-next-month'\" />\n </button>\n </div>\n <ng-container\n *ngTemplateOutlet=\"\n monthTemplate();\n context: {\n $implicit: {\n month: MONTHS[month()],\n change: doMonthChange,\n },\n }\n \"\n />\n\n <ng-container\n *ngTemplateOutlet=\"\n yearTemplate();\n context: {\n $implicit: {\n year: year(),\n change: doYearChange,\n },\n }\n \"\n />\n </div>\n <div class=\"ngn-calendar-days\" role=\"grid\" [attr.aria-label]=\"gridLabel()\">\n <div role=\"row\" style=\"display: contents\">\n @for (weekDay of weekDaysSorted(); track weekDay) {\n <span role=\"columnheader\" [ptInt]=\"component()\" [ptClass]=\"'week-day'\">\n <ng-container\n *ngTemplateOutlet=\"\n weekDayTemplate();\n context: {\n $implicit: {\n weekDay: weekDay.weekDay,\n translation: weekDay.translation(),\n },\n }\n \"\n />\n </span>\n }\n </div>\n @for (item of monthModel().weeks; track $index) {\n <div role=\"row\" style=\"display: contents\">\n @for (day of item.days; track $index) {\n <div\n role=\"gridcell\"\n style=\"display: contents\"\n [attr.aria-selected]=\"isSelected(day) ? 'true' : null\"\n >\n <button\n #dayButton\n [ptInt]=\"component()\"\n [ptClass]=\"{\n day: true,\n 'day-other-month': day.monthOffset !== 0,\n 'day-today': isToday(day),\n 'day-selected': isSelected(day),\n }\"\n [tabIndex]=\"!day.monthOffset && tabFocusDay() === day.date ? 0 : -1\"\n [attr.aria-current]=\"isToday(day) ? 'date' : null\"\n [attr.aria-label]=\"dayLabel(day)\"\n type=\"button\"\n (click)=\"\n daySelected.emit({\n date: day.date,\n monthOffset: day.monthOffset,\n })\n \"\n (keydown)=\"dayKeydown($event, dayButton)\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n dayTemplate();\n context: {\n $implicit: {\n date: day.date,\n fromOtherMonth: day.monthOffset !== 0,\n selected: isSelected(day),\n today: isToday(day),\n },\n }\n \"\n />\n </button>\n </div>\n }\n </div>\n }\n </div>\n @if (showTime()) {\n <ng-container\n *ngTemplateOutlet=\"\n timeTemplate();\n context: {\n $implicit: { time: currentValue(), showSeconds: showSeconds(), change: doTimeChange },\n }\n \"\n />\n }\n</div>\n" }]
320
+ }], propDecorators: { component: [{ type: i0.Input, args: [{ isSignal: true, alias: "component", required: true }] }], theme: [{ type: i0.Input, args: [{ isSignal: true, alias: "theme", required: true }] }], year: [{ type: i0.Input, args: [{ isSignal: true, alias: "year", required: true }] }], month: [{ type: i0.Input, args: [{ isSignal: true, alias: "month", required: true }] }], currentValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentValue", required: true }] }], firstDayOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstDayOfWeek", required: true }] }], dayTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "dayTemplate", required: true }] }], weekDayTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "weekDayTemplate", required: true }] }], timeTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeTemplate", required: true }] }], yearTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "yearTemplate", required: true }] }], monthTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "monthTemplate", required: true }] }], showTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTime", required: true }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: true }] }], previousMonth: [{ type: i0.Output, args: ["previousMonth"] }], nextMonth: [{ type: i0.Output, args: ["nextMonth"] }], daySelected: [{ type: i0.Output, args: ["daySelected"] }], yearSelected: [{ type: i0.Output, args: ["yearSelected"] }], monthSelected: [{ type: i0.Output, args: ["monthSelected"] }], timeChanged: [{ type: i0.Output, args: ["timeChanged"] }], _dayButton: [{ type: i0.ViewChildren, args: ['dayButton', { isSignal: true }] }] } });
321
+
322
+ /**
323
+ * Formats a Date object into a string based on the provided format.
324
+ * @param value The Date object to format. If null, an empty string is returned.
325
+ * @param format The format string that specifies how the date should be formatted. Supported tokens include:
326
+ * Tokens follow the standard (Unicode/moment-style) convention — uppercase `M` is
327
+ * month, lowercase `m` is minute — matching `getDateOrTimeMask`:
328
+ * - 'dd': Day of the month, 2 digits with leading zeros (01 to 31)
329
+ * - 'd': Day of the month without leading zeros (1 to 31)
330
+ * - 'MM': Month, 2 digits with leading zeros (01 to 12)
331
+ * - 'M': Month without leading zeros (1 to 12)
332
+ * - 'yyyy': Year, 4 digits (e.g., 2024)
333
+ * - 'yy': Year, 2 digits (e.g., 24)
334
+ * - 'HH': Hours (24-hour), 2 digits with leading zeros (00 to 23)
335
+ * - 'H': Hours (24-hour) without leading zeros (0 to 23)
336
+ * - 'hh': Hours (12-hour), 2 digits with leading zeros (01 to 12)
337
+ * - 'h': Hours (12-hour) without leading zeros (1 to 12)
338
+ * - 'mm': Minutes, 2 digits with leading zeros (00 to 59)
339
+ * - 'm': Minutes without leading zeros (0 to 59)
340
+ * - 'ss': Seconds, 2 digits with leading zeros (00 to 59)
341
+ * - 's': Seconds without leading zeros (0 to 59)
342
+ * - 'a': AM/PM marker
343
+ * - 'SSS': Milliseconds, 3 digits with leading zeros (000 to 999)
344
+ * @returns The formatted date string.
345
+ */
346
+ const DATE_TOKEN = /^(yyyy|yy|MM|M|dd|d|HH|H|hh|h|mm|m|ss|s|SSS|a)/;
347
+ /** Maximum digit count per numeric token — bounds the capture so adjacent
348
+ * numeric tokens (separator-free formats like `MMddyyyy`) still parse. */
349
+ const TOKEN_MAX_DIGITS = {
350
+ yyyy: 4,
351
+ yy: 2,
352
+ MM: 2,
353
+ M: 2,
354
+ dd: 2,
355
+ d: 2,
356
+ HH: 2,
357
+ H: 2,
358
+ hh: 2,
359
+ h: 2,
360
+ mm: 2,
361
+ m: 2,
362
+ ss: 2,
363
+ s: 2,
364
+ SSS: 3,
365
+ };
366
+ /**
367
+ * Parses a date string according to `format`, the inverse of {@link formatDate}.
368
+ *
369
+ * Unlike `new Date(string)` this is format-aware (so e.g. `dd.MM.yyyy` parses
370
+ * correctly) and, crucially, **clamps the day to the number of days in the
371
+ * resolved month/year** instead of rolling over: `31` in February becomes the
372
+ * 28th/29th rather than spilling into March. Returns `null` when the string does
373
+ * not match the format.
374
+ *
375
+ * Two-digit years (`yy`) are interpreted as 2000–2099. Numeric tokens are capped
376
+ * at their natural digit count so separator-free formats parse unambiguously.
377
+ */
378
+ function parseDate(str, format) {
379
+ // Build a regex from the format, remembering the token captured at each group.
380
+ let pattern = '';
381
+ const tokens = [];
382
+ let i = 0;
383
+ while (i < format.length) {
384
+ const m = DATE_TOKEN.exec(format.slice(i));
385
+ if (m) {
386
+ const tok = m[0]; // the whole match is the token
387
+ tokens.push(tok);
388
+ pattern += tok === 'a' ? '(AM|PM)' : `(\\d{1,${TOKEN_MAX_DIGITS[tok]}})`;
389
+ i += tok.length;
390
+ }
391
+ else {
392
+ pattern += format.charAt(i).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
393
+ i++;
394
+ }
395
+ }
396
+ const match = new RegExp(`^${pattern}$`).exec(str);
397
+ if (!match)
398
+ return null;
399
+ const part = {};
400
+ tokens.forEach((tok, idx) => (part[tok] = match[idx + 1] ?? ''));
401
+ const num = (...keys) => {
402
+ for (const k of keys)
403
+ if (part[k] !== undefined)
404
+ return Number(part[k]);
405
+ return undefined;
406
+ };
407
+ const now = new Date();
408
+ const year = num('yyyy') ?? (part['yy'] !== undefined ? 2000 + Number(part['yy']) : now.getFullYear());
409
+ const month = num('MM', 'M') ?? 1; // 1-12
410
+ const dayRaw = num('dd', 'd') ?? 1;
411
+ let hours = num('HH', 'H') ?? 0;
412
+ const hour12 = num('hh', 'h');
413
+ if (hour12 !== undefined) {
414
+ if (hour12 < 1 || hour12 > 12)
415
+ return null;
416
+ const pm = part['a'] === 'PM';
417
+ hours = (hour12 % 12) + (pm ? 12 : 0);
418
+ }
419
+ const minutes = num('mm', 'm') ?? 0;
420
+ const seconds = num('ss', 's') ?? 0;
421
+ const ms = num('SSS') ?? 0;
422
+ // Reject out-of-range components rather than letting `new Date` silently
423
+ // normalize them (e.g. month 13 → next year, hour 25 → next day).
424
+ if (month < 1 ||
425
+ month > 12 ||
426
+ hours < 0 ||
427
+ hours > 23 ||
428
+ minutes < 0 ||
429
+ minutes > 59 ||
430
+ seconds < 0 ||
431
+ seconds > 59 ||
432
+ ms < 0 ||
433
+ ms > 999) {
434
+ return null;
435
+ }
436
+ // Clamp the day to the resolved month's length (handles leap years) so an
437
+ // out-of-range day never rolls over into the next month.
438
+ const daysInMonth = new Date(year, month, 0).getDate();
439
+ const day = Math.max(1, Math.min(dayRaw, daysInMonth));
440
+ const date = new Date(year, month - 1, day, hours, minutes, seconds, ms);
441
+ return isNaN(date.getTime()) ? null : date;
442
+ }
443
+ function formatDate(value, format) {
444
+ if (!value) {
445
+ return '';
446
+ }
447
+ const day = value.getDate();
448
+ const month = value.getMonth() + 1;
449
+ const year = value.getFullYear();
450
+ const hours = value.getHours();
451
+ const minutes = value.getMinutes();
452
+ const seconds = value.getSeconds();
453
+ const milliseconds = value.getMilliseconds();
454
+ const ampm = hours >= 12 ? 'PM' : 'AM';
455
+ const hour12 = hours % 12 || 12;
456
+ // Longest tokens first within each group; 'a' (AM/PM) last so the inserted
457
+ // letters are never re-matched by an earlier numeric replacement.
458
+ return format
459
+ .replace(/yyyy/g, String(year))
460
+ .replace(/yy/g, String(year).slice(-2))
461
+ .replace(/dd/g, String(day).padStart(2, '0'))
462
+ .replace(/d/g, String(day))
463
+ .replace(/MM/g, String(month).padStart(2, '0'))
464
+ .replace(/M/g, String(month))
465
+ .replace(/HH/g, String(hours).padStart(2, '0'))
466
+ .replace(/H/g, String(hours))
467
+ .replace(/hh/g, String(hour12).padStart(2, '0'))
468
+ .replace(/h/g, String(hour12))
469
+ .replace(/mm/g, String(minutes).padStart(2, '0'))
470
+ .replace(/m/g, String(minutes))
471
+ .replace(/ss/g, String(seconds).padStart(2, '0'))
472
+ .replace(/s/g, String(seconds))
473
+ .replace(/SSS/g, String(milliseconds).padStart(3, '0'))
474
+ .replace(/a/g, ampm);
475
+ }
476
+
477
+ function generateYearOptions() {
478
+ const MAX_ITEMS = 200;
479
+ const currentYear = new Date().getFullYear();
480
+ return Array.from({ length: MAX_ITEMS }, (_, i) => ({
481
+ label: (currentYear - MAX_ITEMS / 2 + i).toString(),
482
+ value: currentYear - MAX_ITEMS / 2 + i,
483
+ }));
484
+ }
485
+ /**
486
+ * @category control
487
+ */
488
+ class NgnCalendar extends CalendarTemplates {
489
+ /**
490
+ * Set the first day of the week.
491
+ * @default 'monday'
492
+ */
493
+ firstDayOfWeek = input('monday', /* @ts-ignore */
494
+ ...(ngDevMode ? [{ debugName: "firstDayOfWeek" }] : /* istanbul ignore next */ []));
495
+ /**
496
+ * Whether to show the time input.
497
+ * @default false
498
+ */
499
+ showTime = input(false, { ...(ngDevMode ? { debugName: "showTime" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
500
+ /**
501
+ * Whether to show seconds in the time input.
502
+ * @default false
503
+ */
504
+ showSeconds = input(false, { ...(ngDevMode ? { debugName: "showSeconds" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
505
+ /**
506
+ * Whether to show the calendar inline instead of with a input field & popup.
507
+ * @default false
508
+ */
509
+ inline = input(false, { ...(ngDevMode ? { debugName: "inline" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
510
+ /**
511
+ * The format of the date displayed in the input field.
512
+ * @default 'MM/dd/yyyy'
513
+ */
514
+ format = input('MM/dd/yyyy', /* @ts-ignore */
515
+ ...(ngDevMode ? [{ debugName: "format" }] : /* istanbul ignore next */ []));
516
+ _popover = viewChild(NgnPopover, /* @ts-ignore */
517
+ ...(ngDevMode ? [{ debugName: "_popover" }] : /* istanbul ignore next */ []));
518
+ _mask = viewChild(NgnMaskInput, /* @ts-ignore */
519
+ ...(ngDevMode ? [{ debugName: "_mask" }] : /* istanbul ignore next */ []));
520
+ _platform = inject(Platform);
521
+ i18n = inject(I18n).translations;
522
+ isFieldControl = true;
523
+ theme = this.injectThemeTemplate(calendarControlTemplate);
524
+ get anchorElement() {
525
+ return (this.element.nativeElement.closest('ngn-input-field') ??
526
+ this.element.nativeElement);
527
+ }
528
+ year = linkedSignal(() => this.value()?.getFullYear() || new Date().getFullYear(), /* @ts-ignore */
529
+ ...(ngDevMode ? [{ debugName: "year" }] : /* istanbul ignore next */ []));
530
+ month = linkedSignal(() => this.value()?.getMonth() ?? new Date().getMonth(), /* @ts-ignore */
531
+ ...(ngDevMode ? [{ debugName: "month" }] : /* istanbul ignore next */ []));
532
+ yearOptions = generateYearOptions();
533
+ monthOptions = computed(() => {
534
+ const months = Array.from({ length: 12 }, (_, i) => ({
535
+ label: this.i18n[`calendar_months_${MONTHS[i] ?? throwExp('calendar', 'invalid month index')}`],
536
+ value: MONTHS[i],
537
+ testId: `calendar-month-${MONTHS[i]}`,
538
+ }));
539
+ return months;
540
+ }, /* @ts-ignore */
541
+ ...(ngDevMode ? [{ debugName: "monthOptions" }] : /* istanbul ignore next */ []));
542
+ valueStr = computed(() => {
543
+ const value = this.value();
544
+ const format = this.format();
545
+ if (!value) {
546
+ return null;
547
+ }
548
+ return formatDate(value, format);
549
+ }, /* @ts-ignore */
550
+ ...(ngDevMode ? [{ debugName: "valueStr" }] : /* istanbul ignore next */ []));
551
+ maskCfg = computed(() => {
552
+ const format = this.format();
553
+ const mask = getDateOrTimeMask(format);
554
+ const value = this.value();
555
+ if (!value) {
556
+ return mask;
557
+ }
558
+ // Narrow the day field's max to the current month's length (leap-aware) so
559
+ // the mask wraps/limits the day correctly within the month (e.g. Feb caps at
560
+ // 28/29, stepping up from 28 wraps to 1). The mask keeps the typed value
561
+ // across this change because only min/max — not the structure — differs.
562
+ const daysInMonth = new Date(value.getFullYear(), value.getMonth() + 1, 0).getDate();
563
+ return mask.map(seg => typeof seg !== 'string' && seg.kind === 'number' && seg.segment === 'day'
564
+ ? { ...seg, max: daysInMonth }
565
+ : seg);
566
+ }, /* @ts-ignore */
567
+ ...(ngDevMode ? [{ debugName: "maskCfg" }] : /* istanbul ignore next */ []));
568
+ previousMonth = () => {
569
+ const currentMonth = this.month();
570
+ const currentYear = this.year();
571
+ if (currentMonth === 0) {
572
+ this.year.set(currentYear - 1);
573
+ this.month.set(11); // December
574
+ }
575
+ else {
576
+ this.month.set(currentMonth - 1);
577
+ }
578
+ };
579
+ nextMonth = () => {
580
+ const currentMonth = this.month();
581
+ const currentYear = this.year();
582
+ if (currentMonth === 11) {
583
+ this.year.set(currentYear + 1);
584
+ this.month.set(0); // January
585
+ }
586
+ else {
587
+ this.month.set(currentMonth + 1);
588
+ }
589
+ };
590
+ previousYear = () => {
591
+ this.year.set(this.year() - 1);
592
+ };
593
+ nextYear = () => {
594
+ this.year.set(this.year() + 1);
595
+ };
596
+ selectMonth(month) {
597
+ this.month.set(MONTHS.indexOf(month));
598
+ }
599
+ selectYear(year) {
600
+ this.year.set(year);
601
+ }
602
+ selectDay(day) {
603
+ const newValue = new Date(this.value() || new Date());
604
+ newValue.setFullYear(this.year());
605
+ newValue.setMonth(this.month() + day.monthOffset);
606
+ newValue.setDate(day.date);
607
+ this.value.set(newValue);
608
+ }
609
+ changeTime(newTime) {
610
+ if (!newTime) {
611
+ this.value.set(null);
612
+ return;
613
+ }
614
+ const currentValue = this.value();
615
+ if (currentValue) {
616
+ const newValue = new Date(currentValue);
617
+ newValue.setHours(newTime.getHours());
618
+ newValue.setMinutes(newTime.getMinutes());
619
+ newValue.setSeconds(newTime.getSeconds());
620
+ this.value.set(newValue);
621
+ }
622
+ }
623
+ /**
624
+ * Places focus from a pointer event: forwards the location to the embedded
625
+ * mask so the section nearest the cursor is selected, then opens the popup.
626
+ * Implemented as the `NgnBase.focusFromPointer` hook so it also works when the
627
+ * calendar is wrapped in an `ngn-input-field` — the outer field delegates the
628
+ * click here (with the real coordinates) instead of synthesising a
629
+ * coordinate-less click. Invoked by the calendar's own field click too.
630
+ */
631
+ focusFromPointer(event) {
632
+ const handled = this._mask()?.focusFromPointer(event) ?? false;
633
+ if (!this.inline()) {
634
+ this.show();
635
+ }
636
+ return handled;
637
+ }
638
+ /**
639
+ * Shows the calendar popup. Only works if `inline` is `false`.
640
+ */
641
+ show() {
642
+ if (this.inline()) {
643
+ throw new NgnError('calendar', 'cannot open inline calendar');
644
+ }
645
+ if (this._platform.isTouchDevice() || this.disabled() || this.readonly()) {
646
+ return;
647
+ }
648
+ const popover = this._popover();
649
+ if (!popover) {
650
+ throw new NgnError('calendar', 'popover not found despite inline being false');
651
+ }
652
+ popover.show();
653
+ }
654
+ /**
655
+ * Hides the calendar popup. Only works if `inline` is `false`.
656
+ */
657
+ hide() {
658
+ if (this.inline()) {
659
+ throw new NgnError('calendar', 'cannot close inline calendar');
660
+ }
661
+ const popover = this._popover();
662
+ if (!popover) {
663
+ throw new NgnError('calendar', 'popover not found despite inline being false');
664
+ }
665
+ popover.hide();
666
+ }
667
+ onKeyDown(event) {
668
+ // @todo: handle date selection with keys
669
+ // if event is not handled by the listbox, we can handle it here
670
+ if (event.key === 'Enter' && !this.inline()) {
671
+ const popover = this._popover();
672
+ if (!popover) {
673
+ throw new NgnError('calendar', 'popover not found despite inline being false');
674
+ }
675
+ popover.toggle();
676
+ event.stopPropagation();
677
+ event.preventDefault();
678
+ }
679
+ }
680
+ /** The current (possibly partial) text in the mask field, awaiting blur. */
681
+ _inputString = signal(null, /* @ts-ignore */
682
+ ...(ngDevMode ? [{ debugName: "_inputString" }] : /* istanbul ignore next */ []));
683
+ _clearingMaskInput = signal(false, /* @ts-ignore */
684
+ ...(ngDevMode ? [{ debugName: "_clearingMaskInput" }] : /* istanbul ignore next */ []));
685
+ _clearValueWhenMaskBecomesEmpty = effect(() => {
686
+ if (!this._clearingMaskInput() || !this._mask()?.empty()) {
687
+ return;
688
+ }
689
+ this._clearingMaskInput.set(false);
690
+ this.value.set(null);
691
+ }, /* @ts-ignore */
692
+ ...(ngDevMode ? [{ debugName: "_clearValueWhenMaskBecomesEmpty" }] : /* istanbul ignore next */ []));
693
+ stringValueChange(newValue) {
694
+ this._inputString.set(newValue);
695
+ // The mask emits null both while mid-typing and when fully cleared. Only the
696
+ // fully-cleared case should null out the bound value; a partially-typed entry
697
+ // leaves the previous value intact (one-directional sync).
698
+ if (!newValue) {
699
+ if (this._mask()?.empty()) {
700
+ this._clearingMaskInput.set(false);
701
+ this.value.set(null);
702
+ }
703
+ else {
704
+ this._clearingMaskInput.set(true);
705
+ }
706
+ return;
707
+ }
708
+ this._clearingMaskInput.set(false);
709
+ // One-directional sync: typing updates the calendar value (and thus the
710
+ // dropdown UI) only once the mask is COMPLETE — a fully filled, parseable
711
+ // date. Half-typed input never moves the calendar and is never reformatted
712
+ // back over the input. The calendar UI updates the value directly via
713
+ // selectDay / selectMonth / selectYear / changeTime (which then flow back
714
+ // out to the mask text via `valueStr`).
715
+ if (this._mask()?.complete()) {
716
+ this.parseInputString();
717
+ }
718
+ }
719
+ /** Parse the complete mask string into the calendar value. */
720
+ parseInputString() {
721
+ const raw = this._inputString();
722
+ if (!raw) {
723
+ return;
724
+ }
725
+ // Format-aware parse that clamps an out-of-range day to the month's length
726
+ // (e.g. Feb 31 → Feb 28) instead of rolling over into the next month.
727
+ const date = parseDate(raw, this.format());
728
+ if (!date) {
729
+ return;
730
+ }
731
+ if (!this.showTime()) {
732
+ date.setHours(this.value()?.getHours() ?? 0);
733
+ date.setMinutes(this.value()?.getMinutes() ?? 0);
734
+ date.setSeconds(this.value()?.getSeconds() ?? 0);
735
+ }
736
+ else if (!this.showSeconds()) {
737
+ date.setSeconds(this.value()?.getSeconds() ?? 0);
738
+ }
739
+ // Skip if unchanged — prevents an echo loop when our own valueStr→input
740
+ // write re-emits a (complete) valueChange for the value we just set.
741
+ const current = this.value();
742
+ if (current && current.getTime() === date.getTime()) {
743
+ // The value is unchanged, but the mask may be showing a non-canonical
744
+ // string (e.g. a clamped Feb 31 → Feb 28). Push the canonical text back so
745
+ // the displayed sections match the real value.
746
+ const canonical = formatDate(date, this.format());
747
+ if (canonical !== raw) {
748
+ this._mask()?.value.set(canonical);
749
+ }
750
+ return;
751
+ }
752
+ this.value.set(date);
753
+ }
754
+ potentiallyBlurred() {
755
+ setTimeout(() => {
756
+ if (this.element.nativeElement.contains(document.activeElement) || this._popover()?.open()) {
757
+ return;
758
+ }
759
+ this.touched.set(true);
760
+ });
761
+ }
762
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgnCalendar, deps: null, target: i0.ɵɵFactoryTarget.Component });
763
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: NgnCalendar, isStandalone: true, selector: "ngn-calendar", inputs: { firstDayOfWeek: { classPropertyName: "firstDayOfWeek", publicName: "firstDayOfWeek", isSignal: true, isRequired: false, transformFunction: null }, showTime: { classPropertyName: "showTime", publicName: "showTime", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, inline: { classPropertyName: "inline", publicName: "inline", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.display": "\"block\"", "style.width": "inline() ? \"fit-content\" : \"100%\"", "attr.aria-invalid": "invalid() ? \"true\" : null" } }, providers: [provideSelf(NgnCalendar)], viewQueries: [{ propertyName: "_popover", first: true, predicate: NgnPopover, descendants: true, isSignal: true }, { propertyName: "_mask", first: true, predicate: NgnMaskInput, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "@if (inline()) {\n <ng-container *ngTemplateOutlet=\"calendar\"></ng-container>\n} @else {\n <div\n #field\n [ptInt]=\"this\"\n [ptClass]=\"{ 'input-field': true, invalid: invalid() }\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n (click)=\"focusFromPointer($event)\"\n (keydown)=\"onKeyDown($event)\"\n (focusout)=\"potentiallyBlurred()\"\n [tabindex]=\"disabled() ? -1 : 0\"\n >\n <ngn-mask-input\n [ptInt]=\"this\"\n [ptDep]=\"'input'\"\n [label]=\"i18n['calendar_input']()\"\n [mask]=\"maskCfg()\"\n [invalid]=\"invalid()\"\n [value]=\"valueStr()\"\n (valueChange)=\"stringValueChange($event)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n />\n <ngn-icon defaultIcon=\"calendar-trigger\" [ptInt]=\"this\" [ptDep]=\"'trigger-icon'\" />\n </div>\n <ngn-popover\n #popover\n [ptInt]=\"this\"\n [ptDep]=\"'popover'\"\n [anchor]=\"anchorElement\"\n [id]=\"inputId() + '_popover'\"\n (closing)=\"potentiallyBlurred()\"\n >\n <ng-template #lazy>\n <ng-container *ngTemplateOutlet=\"calendar\"></ng-container>\n </ng-template>\n </ngn-popover>\n}\n\n<ng-template #calendar>\n <div\n [ptInt]=\"this\"\n [ptClass]=\"{\n root: true,\n inline: inline(),\n }\"\n >\n <ngn-calendar-days\n [component]=\"this\"\n [theme]=\"theme\"\n [year]=\"year()\"\n [month]=\"month()\"\n [currentValue]=\"value()\"\n [firstDayOfWeek]=\"firstDayOfWeek()\"\n (previousMonth)=\"previousMonth()\"\n (nextMonth)=\"nextMonth()\"\n (daySelected)=\"selectDay($event)\"\n (monthSelected)=\"selectMonth($event)\"\n (yearSelected)=\"selectYear($event)\"\n (timeChanged)=\"changeTime($event)\"\n [dayTemplate]=\"dayTemplate()\"\n [weekDayTemplate]=\"weekDayTemplate()\"\n [timeTemplate]=\"timeTemplate()\"\n [yearTemplate]=\"yearTemplate()\"\n [monthTemplate]=\"monthTemplate()\"\n [showTime]=\"showTime()\"\n [showSeconds]=\"showSeconds()\"\n (focusout)=\"potentiallyBlurred()\"\n />\n </div>\n</ng-template>\n<ng-template #defaultDayTemplate [ngnTemplate]=\"templateTypes.day\" let-day>\n {{ day.date }}\n</ng-template>\n\n<ng-template #defaultWeekDayTemplate [ngnTemplate]=\"templateTypes.weekDay\" let-weekDay>\n <span>\n {{ weekDay.translation }}\n </span>\n</ng-template>\n\n<ng-template #defaultTimeTemplate [ngnTemplate]=\"templateTypes.time\" let-time>\n @defer {\n <div [ptInt]=\"this\" [ptClass]=\"'time'\">\n <ngn-calendar-time\n [component]=\"this\"\n [currentValue]=\"time.time\"\n [showSeconds]=\"time.showSeconds\"\n (timeChange)=\"time.change($event)\"\n />\n </div>\n }\n</ng-template>\n\n<ng-template #defaultYearTemplate [ngnTemplate]=\"templateTypes.year\" let-y>\n @defer {\n <ngn-input-field [ptInt]=\"this\" [ptDep]=\"'current-year-field'\">\n <ngn-select\n [ptInt]=\"this\"\n [ptDep]=\"'current-year'\"\n [editable]=\"true\"\n [value]=\"year() + ''\"\n (valueChange)=\"y.change(+($event || 0))\"\n [options]=\"yearOptions\"\n [virtual]=\"true\"\n [itemHeight]=\"40\"\n [popoverOptions]=\"{ sizeConstraints: { maxHeight: '300px' } }\"\n [scrollToSelectedItemOnOpen]=\"'center'\"\n [editableAutoFilter]=\"false\"\n [tabindex]=\"-1\"\n >\n <input ngnInput type=\"number\" [attr.aria-label]=\"i18n['calendar_selectYear']()\" />\n </ngn-select>\n </ngn-input-field>\n }\n</ng-template>\n\n<ng-template #defaultMonthTemplate [ngnTemplate]=\"templateTypes.month\" let-m>\n @defer {\n <ngn-input-field [ptInt]=\"this\" [ptDep]=\"'current-month-field'\">\n <ngn-select\n [ptInt]=\"this\"\n [ptDep]=\"'current-month'\"\n [label]=\"i18n['calendar_selectMonth']()\"\n [value]=\"m.month\"\n (valueChange)=\"m.change($event!)\"\n [options]=\"monthOptions()\"\n [popoverOptions]=\"{\n sizeConstraints: { maxHeight: '300px', width: '130px', maxWidth: '130px' },\n }\"\n [scrollToSelectedItemOnOpen]=\"'center'\"\n [tabindex]=\"-1\"\n />\n </ngn-input-field>\n }\n</ng-template>\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgnTemplate, selector: "ng-template[ngnTemplate]", inputs: ["ngnTemplate"] }, { kind: "directive", type: NgnPt, selector: "[ptInt]", inputs: ["ptInt", "ptClass", "ptDep"] }, { kind: "component", type: NgnIcon, selector: "ngn-icon", inputs: ["defaultIcon", "icon"] }, { kind: "component", type: NgnPopover, selector: "ngn-popover", inputs: ["open", "anchor", "options", "hasShrinkableContent", "closeBy"], outputs: ["closed", "closing", "openChange"] }, { kind: "component", type: CalendarDays, selector: "ngn-calendar-days", inputs: ["component", "theme", "year", "month", "currentValue", "firstDayOfWeek", "dayTemplate", "weekDayTemplate", "timeTemplate", "yearTemplate", "monthTemplate", "showTime", "showSeconds"], outputs: ["previousMonth", "nextMonth", "daySelected", "yearSelected", "monthSelected", "timeChanged"] }, { kind: "component", type: NgnMaskInput, selector: "ngn-mask-input", inputs: ["mask"] }], deferBlockDependencies: [() => [NgnPt, /* @ts-ignore */
764
+ import('./ngneers-controls-calendar-time-CJT5AFlA.mjs').then(m => m.CalendarTime)], () => [NgnPt, /* @ts-ignore */
765
+ import('@ngneers/controls/input').then(m => m.NgnInput), /* @ts-ignore */
766
+ import('@ngneers/controls/select').then(m => m.NgnSelect), /* @ts-ignore */
767
+ import('@ngneers/controls/input-field').then(m => m.NgnInputField)], () => [NgnPt, /* @ts-ignore */
768
+ import('@ngneers/controls/select').then(m => m.NgnSelect), /* @ts-ignore */
769
+ import('@ngneers/controls/input-field').then(m => m.NgnInputField)]] });
770
+ }
771
+ i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "22.0.5", ngImport: i0, type: NgnCalendar, resolveDeferredDeps: () => [/* @ts-ignore */
772
+ import('./ngneers-controls-calendar-time-CJT5AFlA.mjs').then(m => m.CalendarTime), /* @ts-ignore */
773
+ import('@ngneers/controls/input').then(m => m.NgnInput), /* @ts-ignore */
774
+ import('@ngneers/controls/select').then(m => m.NgnSelect), /* @ts-ignore */
775
+ import('@ngneers/controls/input-field').then(m => m.NgnInputField)], resolveMetadata: (CalendarTime, NgnInput, NgnSelect, NgnInputField) => ({ decorators: [{
776
+ type: Component,
777
+ args: [{ selector: 'ngn-calendar', imports: [
778
+ NgTemplateOutlet,
779
+ NgnTemplate,
780
+ NgnPt,
781
+ NgnInput,
782
+ NgnIcon,
783
+ NgnSelect,
784
+ NgnPopover,
785
+ CalendarDays,
786
+ CalendarTime,
787
+ NgnInputField,
788
+ NgnMaskInput,
789
+ ], providers: [provideSelf(NgnCalendar)], host: {
790
+ '[style.display]': '"block"',
791
+ '[style.width]': 'inline() ? "fit-content" : "100%"',
792
+ '[attr.aria-invalid]': 'invalid() ? "true" : null',
793
+ }, template: "@if (inline()) {\n <ng-container *ngTemplateOutlet=\"calendar\"></ng-container>\n} @else {\n <div\n #field\n [ptInt]=\"this\"\n [ptClass]=\"{ 'input-field': true, invalid: invalid() }\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n (click)=\"focusFromPointer($event)\"\n (keydown)=\"onKeyDown($event)\"\n (focusout)=\"potentiallyBlurred()\"\n [tabindex]=\"disabled() ? -1 : 0\"\n >\n <ngn-mask-input\n [ptInt]=\"this\"\n [ptDep]=\"'input'\"\n [label]=\"i18n['calendar_input']()\"\n [mask]=\"maskCfg()\"\n [invalid]=\"invalid()\"\n [value]=\"valueStr()\"\n (valueChange)=\"stringValueChange($event)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n />\n <ngn-icon defaultIcon=\"calendar-trigger\" [ptInt]=\"this\" [ptDep]=\"'trigger-icon'\" />\n </div>\n <ngn-popover\n #popover\n [ptInt]=\"this\"\n [ptDep]=\"'popover'\"\n [anchor]=\"anchorElement\"\n [id]=\"inputId() + '_popover'\"\n (closing)=\"potentiallyBlurred()\"\n >\n <ng-template #lazy>\n <ng-container *ngTemplateOutlet=\"calendar\"></ng-container>\n </ng-template>\n </ngn-popover>\n}\n\n<ng-template #calendar>\n <div\n [ptInt]=\"this\"\n [ptClass]=\"{\n root: true,\n inline: inline(),\n }\"\n >\n <ngn-calendar-days\n [component]=\"this\"\n [theme]=\"theme\"\n [year]=\"year()\"\n [month]=\"month()\"\n [currentValue]=\"value()\"\n [firstDayOfWeek]=\"firstDayOfWeek()\"\n (previousMonth)=\"previousMonth()\"\n (nextMonth)=\"nextMonth()\"\n (daySelected)=\"selectDay($event)\"\n (monthSelected)=\"selectMonth($event)\"\n (yearSelected)=\"selectYear($event)\"\n (timeChanged)=\"changeTime($event)\"\n [dayTemplate]=\"dayTemplate()\"\n [weekDayTemplate]=\"weekDayTemplate()\"\n [timeTemplate]=\"timeTemplate()\"\n [yearTemplate]=\"yearTemplate()\"\n [monthTemplate]=\"monthTemplate()\"\n [showTime]=\"showTime()\"\n [showSeconds]=\"showSeconds()\"\n (focusout)=\"potentiallyBlurred()\"\n />\n </div>\n</ng-template>\n<ng-template #defaultDayTemplate [ngnTemplate]=\"templateTypes.day\" let-day>\n {{ day.date }}\n</ng-template>\n\n<ng-template #defaultWeekDayTemplate [ngnTemplate]=\"templateTypes.weekDay\" let-weekDay>\n <span>\n {{ weekDay.translation }}\n </span>\n</ng-template>\n\n<ng-template #defaultTimeTemplate [ngnTemplate]=\"templateTypes.time\" let-time>\n @defer {\n <div [ptInt]=\"this\" [ptClass]=\"'time'\">\n <ngn-calendar-time\n [component]=\"this\"\n [currentValue]=\"time.time\"\n [showSeconds]=\"time.showSeconds\"\n (timeChange)=\"time.change($event)\"\n />\n </div>\n }\n</ng-template>\n\n<ng-template #defaultYearTemplate [ngnTemplate]=\"templateTypes.year\" let-y>\n @defer {\n <ngn-input-field [ptInt]=\"this\" [ptDep]=\"'current-year-field'\">\n <ngn-select\n [ptInt]=\"this\"\n [ptDep]=\"'current-year'\"\n [editable]=\"true\"\n [value]=\"year() + ''\"\n (valueChange)=\"y.change(+($event || 0))\"\n [options]=\"yearOptions\"\n [virtual]=\"true\"\n [itemHeight]=\"40\"\n [popoverOptions]=\"{ sizeConstraints: { maxHeight: '300px' } }\"\n [scrollToSelectedItemOnOpen]=\"'center'\"\n [editableAutoFilter]=\"false\"\n [tabindex]=\"-1\"\n >\n <input ngnInput type=\"number\" [attr.aria-label]=\"i18n['calendar_selectYear']()\" />\n </ngn-select>\n </ngn-input-field>\n }\n</ng-template>\n\n<ng-template #defaultMonthTemplate [ngnTemplate]=\"templateTypes.month\" let-m>\n @defer {\n <ngn-input-field [ptInt]=\"this\" [ptDep]=\"'current-month-field'\">\n <ngn-select\n [ptInt]=\"this\"\n [ptDep]=\"'current-month'\"\n [label]=\"i18n['calendar_selectMonth']()\"\n [value]=\"m.month\"\n (valueChange)=\"m.change($event!)\"\n [options]=\"monthOptions()\"\n [popoverOptions]=\"{\n sizeConstraints: { maxHeight: '300px', width: '130px', maxWidth: '130px' },\n }\"\n [scrollToSelectedItemOnOpen]=\"'center'\"\n [tabindex]=\"-1\"\n />\n </ngn-input-field>\n }\n</ng-template>\n" }]
794
+ }], ctorParameters: null, propDecorators: { firstDayOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstDayOfWeek", required: false }] }], showTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTime", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], inline: [{ type: i0.Input, args: [{ isSignal: true, alias: "inline", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], _popover: [{ type: i0.ViewChild, args: [i0.forwardRef(() => NgnPopover), { isSignal: true }] }], _mask: [{ type: i0.ViewChild, args: [i0.forwardRef(() => NgnMaskInput), { isSignal: true }] }] } }) });
795
+
796
+ /**
797
+ * Generated bundle index. Do not edit.
798
+ */
799
+
800
+ export { MONTHS, NgnCalendar, WEEK_DAYS, formatDate, parseDate };
801
+ //# sourceMappingURL=ngneers-controls-calendar.mjs.map