@raintonic/formaui 0.3.1 → 0.9.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 (238) hide show
  1. package/CHANGELOG.md +80 -35
  2. package/README.md +22 -26
  3. package/fesm2022/raintonic-formaui-cdk-drag-drop.mjs +39 -41
  4. package/fesm2022/raintonic-formaui-cdk-drag-drop.mjs.map +1 -1
  5. package/fesm2022/raintonic-formaui-cdk-form-field.mjs +207 -3
  6. package/fesm2022/raintonic-formaui-cdk-form-field.mjs.map +1 -1
  7. package/fesm2022/raintonic-formaui-cdk-overlay.mjs +27 -2
  8. package/fesm2022/raintonic-formaui-cdk-overlay.mjs.map +1 -1
  9. package/fesm2022/raintonic-formaui-cdk-virtual-scroll.mjs +5 -12
  10. package/fesm2022/raintonic-formaui-cdk-virtual-scroll.mjs.map +1 -1
  11. package/fesm2022/raintonic-formaui-components-accordion.mjs +8 -5
  12. package/fesm2022/raintonic-formaui-components-accordion.mjs.map +1 -1
  13. package/fesm2022/raintonic-formaui-components-alert.mjs +16 -2
  14. package/fesm2022/raintonic-formaui-components-alert.mjs.map +1 -1
  15. package/fesm2022/raintonic-formaui-components-autocomplete.mjs +255 -462
  16. package/fesm2022/raintonic-formaui-components-autocomplete.mjs.map +1 -1
  17. package/fesm2022/raintonic-formaui-components-avatar.mjs +34 -59
  18. package/fesm2022/raintonic-formaui-components-avatar.mjs.map +1 -1
  19. package/fesm2022/raintonic-formaui-components-badge.mjs +2 -2
  20. package/fesm2022/raintonic-formaui-components-badge.mjs.map +1 -1
  21. package/fesm2022/raintonic-formaui-components-breadcrumb.mjs +4 -4
  22. package/fesm2022/raintonic-formaui-components-breadcrumb.mjs.map +1 -1
  23. package/fesm2022/raintonic-formaui-components-button-group.mjs +2 -2
  24. package/fesm2022/raintonic-formaui-components-button-group.mjs.map +1 -1
  25. package/fesm2022/raintonic-formaui-components-button.mjs +15 -20
  26. package/fesm2022/raintonic-formaui-components-button.mjs.map +1 -1
  27. package/fesm2022/raintonic-formaui-components-card.mjs +2 -2
  28. package/fesm2022/raintonic-formaui-components-card.mjs.map +1 -1
  29. package/fesm2022/raintonic-formaui-components-checkbox.mjs +2 -2
  30. package/fesm2022/raintonic-formaui-components-checkbox.mjs.map +1 -1
  31. package/fesm2022/raintonic-formaui-components-chip.mjs +97 -0
  32. package/fesm2022/raintonic-formaui-components-chip.mjs.map +1 -0
  33. package/fesm2022/raintonic-formaui-components-data-table.mjs +69 -29
  34. package/fesm2022/raintonic-formaui-components-data-table.mjs.map +1 -1
  35. package/fesm2022/raintonic-formaui-components-date-picker.mjs +223 -144
  36. package/fesm2022/raintonic-formaui-components-date-picker.mjs.map +1 -1
  37. package/fesm2022/raintonic-formaui-components-divider.mjs +2 -2
  38. package/fesm2022/raintonic-formaui-components-divider.mjs.map +1 -1
  39. package/fesm2022/raintonic-formaui-components-drawer.mjs +2 -2
  40. package/fesm2022/raintonic-formaui-components-drawer.mjs.map +1 -1
  41. package/fesm2022/raintonic-formaui-components-dropdown-menu.mjs +888 -0
  42. package/fesm2022/raintonic-formaui-components-dropdown-menu.mjs.map +1 -0
  43. package/fesm2022/raintonic-formaui-components-dual-tier-navigation.mjs +774 -0
  44. package/fesm2022/raintonic-formaui-components-dual-tier-navigation.mjs.map +1 -0
  45. package/fesm2022/raintonic-formaui-components-empty-state.mjs +2 -2
  46. package/fesm2022/raintonic-formaui-components-empty-state.mjs.map +1 -1
  47. package/fesm2022/raintonic-formaui-components-file-upload.mjs +2 -2
  48. package/fesm2022/raintonic-formaui-components-file-upload.mjs.map +1 -1
  49. package/fesm2022/raintonic-formaui-components-form-field.mjs +81 -50
  50. package/fesm2022/raintonic-formaui-components-form-field.mjs.map +1 -1
  51. package/fesm2022/raintonic-formaui-components-icon.mjs +2 -2
  52. package/fesm2022/raintonic-formaui-components-icon.mjs.map +1 -1
  53. package/fesm2022/raintonic-formaui-components-input.mjs +47 -12
  54. package/fesm2022/raintonic-formaui-components-input.mjs.map +1 -1
  55. package/fesm2022/raintonic-formaui-components-list.mjs +4 -4
  56. package/fesm2022/raintonic-formaui-components-list.mjs.map +1 -1
  57. package/fesm2022/raintonic-formaui-components-number-input.mjs +20 -12
  58. package/fesm2022/raintonic-formaui-components-number-input.mjs.map +1 -1
  59. package/fesm2022/raintonic-formaui-components-paginator.mjs +2 -2
  60. package/fesm2022/raintonic-formaui-components-paginator.mjs.map +1 -1
  61. package/fesm2022/raintonic-formaui-components-password-input.mjs +35 -110
  62. package/fesm2022/raintonic-formaui-components-password-input.mjs.map +1 -1
  63. package/fesm2022/raintonic-formaui-components-popover.mjs +3 -2
  64. package/fesm2022/raintonic-formaui-components-popover.mjs.map +1 -1
  65. package/fesm2022/raintonic-formaui-components-progressbar.mjs +3 -2
  66. package/fesm2022/raintonic-formaui-components-progressbar.mjs.map +1 -1
  67. package/fesm2022/raintonic-formaui-components-radio.mjs +5 -6
  68. package/fesm2022/raintonic-formaui-components-radio.mjs.map +1 -1
  69. package/fesm2022/raintonic-formaui-components-select.mjs +257 -412
  70. package/fesm2022/raintonic-formaui-components-select.mjs.map +1 -1
  71. package/fesm2022/raintonic-formaui-components-side-panel.mjs +2 -2
  72. package/fesm2022/raintonic-formaui-components-side-panel.mjs.map +1 -1
  73. package/fesm2022/raintonic-formaui-components-sidebar-nav-menu.mjs +525 -0
  74. package/fesm2022/raintonic-formaui-components-sidebar-nav-menu.mjs.map +1 -0
  75. package/fesm2022/raintonic-formaui-components-skeleton.mjs +2 -2
  76. package/fesm2022/raintonic-formaui-components-skeleton.mjs.map +1 -1
  77. package/fesm2022/raintonic-formaui-components-slider.mjs +2 -2
  78. package/fesm2022/raintonic-formaui-components-slider.mjs.map +1 -1
  79. package/fesm2022/raintonic-formaui-components-spinner.mjs +2 -2
  80. package/fesm2022/raintonic-formaui-components-spinner.mjs.map +1 -1
  81. package/fesm2022/raintonic-formaui-components-stepper.mjs +50 -45
  82. package/fesm2022/raintonic-formaui-components-stepper.mjs.map +1 -1
  83. package/fesm2022/raintonic-formaui-components-strength-meter.mjs +149 -0
  84. package/fesm2022/raintonic-formaui-components-strength-meter.mjs.map +1 -0
  85. package/fesm2022/raintonic-formaui-components-tab.mjs +2 -2
  86. package/fesm2022/raintonic-formaui-components-tab.mjs.map +1 -1
  87. package/fesm2022/raintonic-formaui-components-time-picker.mjs +194 -154
  88. package/fesm2022/raintonic-formaui-components-time-picker.mjs.map +1 -1
  89. package/fesm2022/raintonic-formaui-components-toggle-group.mjs +302 -0
  90. package/fesm2022/raintonic-formaui-components-toggle-group.mjs.map +1 -0
  91. package/fesm2022/raintonic-formaui-components-toggle.mjs +2 -2
  92. package/fesm2022/raintonic-formaui-components-toggle.mjs.map +1 -1
  93. package/fesm2022/raintonic-formaui-components-toolbar.mjs +2 -2
  94. package/fesm2022/raintonic-formaui-components-toolbar.mjs.map +1 -1
  95. package/fesm2022/raintonic-formaui-components-tooltip.mjs +10 -4
  96. package/fesm2022/raintonic-formaui-components-tooltip.mjs.map +1 -1
  97. package/fesm2022/raintonic-formaui-components-topbar.mjs +60 -0
  98. package/fesm2022/raintonic-formaui-components-topbar.mjs.map +1 -0
  99. package/fesm2022/raintonic-formaui-components-tree-select.mjs +59 -69
  100. package/fesm2022/raintonic-formaui-components-tree-select.mjs.map +1 -1
  101. package/fesm2022/raintonic-formaui-components-tree-table.mjs +2 -2
  102. package/fesm2022/raintonic-formaui-components-tree-table.mjs.map +1 -1
  103. package/fesm2022/raintonic-formaui-components-tree.mjs +31 -5
  104. package/fesm2022/raintonic-formaui-components-tree.mjs.map +1 -1
  105. package/fesm2022/raintonic-formaui-core.mjs +279 -1
  106. package/fesm2022/raintonic-formaui-core.mjs.map +1 -1
  107. package/fesm2022/raintonic-formaui-services-breakpoint.mjs +93 -0
  108. package/fesm2022/raintonic-formaui-services-breakpoint.mjs.map +1 -0
  109. package/fesm2022/raintonic-formaui-services-dialog.mjs +314 -16
  110. package/fesm2022/raintonic-formaui-services-dialog.mjs.map +1 -1
  111. package/fesm2022/raintonic-formaui-services-notification.mjs +93 -29
  112. package/fesm2022/raintonic-formaui-services-notification.mjs.map +1 -1
  113. package/fesm2022/raintonic-formaui-services-theme.mjs +46 -196
  114. package/fesm2022/raintonic-formaui-services-theme.mjs.map +1 -1
  115. package/fesm2022/raintonic-formaui.mjs +1 -1
  116. package/fesm2022/raintonic-formaui.mjs.map +1 -1
  117. package/llms-full.txt +2329 -450
  118. package/llms.txt +36 -33
  119. package/package.json +42 -19
  120. package/styles/fonts/Geist-Bold.woff2 +0 -0
  121. package/styles/fonts/Geist-Italic.woff2 +0 -0
  122. package/styles/fonts/Geist-Light.woff2 +0 -0
  123. package/styles/fonts/Geist-Medium.woff2 +0 -0
  124. package/styles/fonts/Geist-Regular.woff2 +0 -0
  125. package/styles/fonts/Geist-SemiBold.woff2 +0 -0
  126. package/styles/fonts/GeistMono-Regular.woff2 +0 -0
  127. package/styles/generated/_tokens.scss +906 -0
  128. package/styles/index.scss +11 -10
  129. package/styles/partials/_brand.scss +46 -0
  130. package/styles/partials/_constants.scss +22 -20
  131. package/styles/partials/_fonts.scss +54 -10
  132. package/styles/partials/_grid.scss +29 -18
  133. package/styles/partials/_mixins.scss +69 -27
  134. package/styles/partials/_motion.scss +28 -33
  135. package/styles/partials/_theme.scss +28 -255
  136. package/styles/partials/_type.scss +117 -0
  137. package/styles/partials/_typography.scss +45 -45
  138. package/styles/partials/_utilities.scss +198 -98
  139. package/styles/partials/components/_button.scss +144 -75
  140. package/styles/partials/components/_dialog.scss +181 -180
  141. package/styles/partials/components/_overlay.scss +87 -87
  142. package/styles/partials/themes/_dark.scss +3 -268
  143. package/styles/partials/themes/_light.scss +4 -268
  144. package/styles/styles.css +7744 -0
  145. package/styles/styles.entry.scss +3 -0
  146. package/styles/utilities.css +4802 -0
  147. package/styles/utilities.entry.scss +3 -0
  148. package/types/raintonic-formaui-cdk-drag-drop.d.ts +0 -1
  149. package/types/raintonic-formaui-cdk-drag-drop.d.ts.map +1 -1
  150. package/types/raintonic-formaui-cdk-form-field.d.ts +118 -2
  151. package/types/raintonic-formaui-cdk-form-field.d.ts.map +1 -1
  152. package/types/raintonic-formaui-cdk-overlay.d.ts +2 -0
  153. package/types/raintonic-formaui-cdk-overlay.d.ts.map +1 -1
  154. package/types/raintonic-formaui-cdk-virtual-scroll.d.ts +0 -1
  155. package/types/raintonic-formaui-cdk-virtual-scroll.d.ts.map +1 -1
  156. package/types/raintonic-formaui-components-accordion.d.ts +1 -1
  157. package/types/raintonic-formaui-components-accordion.d.ts.map +1 -1
  158. package/types/raintonic-formaui-components-alert.d.ts +6 -1
  159. package/types/raintonic-formaui-components-alert.d.ts.map +1 -1
  160. package/types/raintonic-formaui-components-autocomplete.d.ts +73 -116
  161. package/types/raintonic-formaui-components-autocomplete.d.ts.map +1 -1
  162. package/types/raintonic-formaui-components-avatar.d.ts +13 -31
  163. package/types/raintonic-formaui-components-avatar.d.ts.map +1 -1
  164. package/types/raintonic-formaui-components-button.d.ts +4 -10
  165. package/types/raintonic-formaui-components-button.d.ts.map +1 -1
  166. package/types/raintonic-formaui-components-chip.d.ts +43 -0
  167. package/types/raintonic-formaui-components-chip.d.ts.map +1 -0
  168. package/types/raintonic-formaui-components-data-table.d.ts +48 -11
  169. package/types/raintonic-formaui-components-data-table.d.ts.map +1 -1
  170. package/types/raintonic-formaui-components-date-picker.d.ts +59 -23
  171. package/types/raintonic-formaui-components-date-picker.d.ts.map +1 -1
  172. package/types/raintonic-formaui-components-dropdown-menu.d.ts +394 -0
  173. package/types/raintonic-formaui-components-dropdown-menu.d.ts.map +1 -0
  174. package/types/raintonic-formaui-components-dual-tier-navigation.d.ts +87 -0
  175. package/types/raintonic-formaui-components-dual-tier-navigation.d.ts.map +1 -0
  176. package/types/raintonic-formaui-components-form-field.d.ts +51 -21
  177. package/types/raintonic-formaui-components-form-field.d.ts.map +1 -1
  178. package/types/raintonic-formaui-components-input.d.ts +20 -11
  179. package/types/raintonic-formaui-components-input.d.ts.map +1 -1
  180. package/types/raintonic-formaui-components-number-input.d.ts +5 -3
  181. package/types/raintonic-formaui-components-number-input.d.ts.map +1 -1
  182. package/types/raintonic-formaui-components-password-input.d.ts +18 -32
  183. package/types/raintonic-formaui-components-password-input.d.ts.map +1 -1
  184. package/types/raintonic-formaui-components-popover.d.ts.map +1 -1
  185. package/types/raintonic-formaui-components-progressbar.d.ts +1 -1
  186. package/types/raintonic-formaui-components-progressbar.d.ts.map +1 -1
  187. package/types/raintonic-formaui-components-radio.d.ts +1 -2
  188. package/types/raintonic-formaui-components-radio.d.ts.map +1 -1
  189. package/types/raintonic-formaui-components-select.d.ts +107 -76
  190. package/types/raintonic-formaui-components-select.d.ts.map +1 -1
  191. package/types/raintonic-formaui-components-sidebar-nav-menu.d.ts +223 -0
  192. package/types/raintonic-formaui-components-sidebar-nav-menu.d.ts.map +1 -0
  193. package/types/raintonic-formaui-components-stepper.d.ts +4 -2
  194. package/types/raintonic-formaui-components-stepper.d.ts.map +1 -1
  195. package/types/raintonic-formaui-components-strength-meter.d.ts +78 -0
  196. package/types/raintonic-formaui-components-strength-meter.d.ts.map +1 -0
  197. package/types/raintonic-formaui-components-time-picker.d.ts +44 -24
  198. package/types/raintonic-formaui-components-time-picker.d.ts.map +1 -1
  199. package/types/raintonic-formaui-components-toggle-group.d.ts +100 -0
  200. package/types/raintonic-formaui-components-toggle-group.d.ts.map +1 -0
  201. package/types/raintonic-formaui-components-tooltip.d.ts +2 -1
  202. package/types/raintonic-formaui-components-tooltip.d.ts.map +1 -1
  203. package/types/raintonic-formaui-components-topbar.d.ts +48 -0
  204. package/types/raintonic-formaui-components-topbar.d.ts.map +1 -0
  205. package/types/raintonic-formaui-components-tree-select.d.ts +25 -9
  206. package/types/raintonic-formaui-components-tree-select.d.ts.map +1 -1
  207. package/types/raintonic-formaui-components-tree.d.ts +12 -1
  208. package/types/raintonic-formaui-components-tree.d.ts.map +1 -1
  209. package/types/raintonic-formaui-core.d.ts +243 -5
  210. package/types/raintonic-formaui-core.d.ts.map +1 -1
  211. package/types/raintonic-formaui-services-breakpoint.d.ts +44 -0
  212. package/types/raintonic-formaui-services-breakpoint.d.ts.map +1 -0
  213. package/types/raintonic-formaui-services-dialog.d.ts +141 -2
  214. package/types/raintonic-formaui-services-dialog.d.ts.map +1 -1
  215. package/types/raintonic-formaui-services-notification.d.ts +24 -2
  216. package/types/raintonic-formaui-services-notification.d.ts.map +1 -1
  217. package/types/raintonic-formaui-services-theme.d.ts +13 -103
  218. package/types/raintonic-formaui-services-theme.d.ts.map +1 -1
  219. package/types/raintonic-formaui.d.ts +1 -1
  220. package/fesm2022/raintonic-formaui-components-big-menu.mjs +0 -86
  221. package/fesm2022/raintonic-formaui-components-big-menu.mjs.map +0 -1
  222. package/fesm2022/raintonic-formaui-components-menu.mjs +0 -896
  223. package/fesm2022/raintonic-formaui-components-menu.mjs.map +0 -1
  224. package/fesm2022/raintonic-formaui-components-sidebar.mjs +0 -275
  225. package/fesm2022/raintonic-formaui-components-sidebar.mjs.map +0 -1
  226. package/fesm2022/raintonic-formaui-components-tag.mjs +0 -95
  227. package/fesm2022/raintonic-formaui-components-tag.mjs.map +0 -1
  228. package/styles/_fonts-entry.scss +0 -3
  229. package/styles/fonts/inter-tight-latin-italic.woff2 +0 -0
  230. package/styles/fonts/inter-tight-latin.woff2 +0 -0
  231. package/types/raintonic-formaui-components-big-menu.d.ts +0 -73
  232. package/types/raintonic-formaui-components-big-menu.d.ts.map +0 -1
  233. package/types/raintonic-formaui-components-menu.d.ts +0 -403
  234. package/types/raintonic-formaui-components-menu.d.ts.map +0 -1
  235. package/types/raintonic-formaui-components-sidebar.d.ts +0 -185
  236. package/types/raintonic-formaui-components-sidebar.d.ts.map +0 -1
  237. package/types/raintonic-formaui-components-tag.d.ts +0 -43
  238. package/types/raintonic-formaui-components-tag.d.ts.map +0 -1
@@ -1,13 +1,12 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, inject, ChangeDetectorRef, signal, input, output, computed, ElementRef, ViewEncapsulation, ChangeDetectionStrategy, Component, NgZone, effect, ViewChild } from '@angular/core';
2
+ import { Injectable, inject, ChangeDetectorRef, signal, input, output, computed, ElementRef, ViewEncapsulation, ChangeDetectionStrategy, Component, effect, ViewChild } from '@angular/core';
3
3
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
- import { NgForm, FormGroupDirective, NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
5
- import { DOCUMENT } from '@angular/common';
6
- import { Subject, Subscription, fromEvent } from 'rxjs';
7
- import { filter } from 'rxjs/operators';
8
- import { injectNgControl, updateErrorState, syncRequiredState, syncNgControlDisabled } from '@raintonic/formaui/cdk/form-field';
9
- import { FuiIntlBase, DefaultErrorStateMatcher, FUI_FORM_FIELD_CONTROL } from '@raintonic/formaui/core';
10
- import { FuiOverlayService } from '@raintonic/formaui/cdk/overlay';
4
+ import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
5
+ import { Subject } from 'rxjs';
6
+ import * as i1 from '@raintonic/formaui/cdk/form-field';
7
+ import { FuiPopupOverlayDirective, FuiFormControlSyncDirective, injectNgControl } from '@raintonic/formaui/cdk/form-field';
8
+ import { FuiIntlBase, FUI_FORM_FIELD_CONTROL } from '@raintonic/formaui/core';
9
+ import { FuiInputDirective } from '@raintonic/formaui/components/input';
11
10
  import { FuiIconComponent } from '@raintonic/formaui/components/icon';
12
11
 
13
12
  class FuiCalendarIntl extends FuiIntlBase {
@@ -241,6 +240,91 @@ function isBetween(date, start, end) {
241
240
  const max = Math.max(s, e);
242
241
  return d >= min && d <= max;
243
242
  }
243
+ /**
244
+ * Built-in date range presets covering the common "this/last week | month | year" shortcuts.
245
+ * Each preset evaluates lazily so values stay correct even if the panel is left open over time.
246
+ *
247
+ * Defaults to Monday as the first day of the week. Pass `{ firstDayOfWeek: 0 }` for Sunday.
248
+ */
249
+ function buildDefaultDateRangePresets(options = {}) {
250
+ const firstDayOfWeek = options.firstDayOfWeek ?? 1;
251
+ const l = {
252
+ thisWeek: 'This week',
253
+ lastWeek: 'Last week',
254
+ thisMonth: 'This month',
255
+ lastMonth: 'Last month',
256
+ thisYear: 'This year',
257
+ lastYear: 'Last year',
258
+ ...options.labels,
259
+ };
260
+ const startOfWeek = (d) => {
261
+ const day = d.getDay();
262
+ const diff = (day - firstDayOfWeek + 7) % 7;
263
+ const start = new Date(d);
264
+ start.setDate(d.getDate() - diff);
265
+ return normalizeDate(start);
266
+ };
267
+ const addDays = (d, n) => {
268
+ const copy = new Date(d);
269
+ copy.setDate(copy.getDate() + n);
270
+ return normalizeDate(copy);
271
+ };
272
+ return [
273
+ {
274
+ label: l.thisWeek,
275
+ value: () => {
276
+ const today = normalizeDate(new Date());
277
+ const start = startOfWeek(today);
278
+ return { start, end: addDays(start, 6) };
279
+ },
280
+ },
281
+ {
282
+ label: l.lastWeek,
283
+ value: () => {
284
+ const today = normalizeDate(new Date());
285
+ const startThis = startOfWeek(today);
286
+ const start = addDays(startThis, -7);
287
+ return { start, end: addDays(start, 6) };
288
+ },
289
+ },
290
+ {
291
+ label: l.thisMonth,
292
+ value: () => {
293
+ const today = new Date();
294
+ const start = normalizeDate(new Date(today.getFullYear(), today.getMonth(), 1));
295
+ const end = normalizeDate(new Date(today.getFullYear(), today.getMonth() + 1, 0));
296
+ return { start, end };
297
+ },
298
+ },
299
+ {
300
+ label: l.lastMonth,
301
+ value: () => {
302
+ const today = new Date();
303
+ const start = normalizeDate(new Date(today.getFullYear(), today.getMonth() - 1, 1));
304
+ const end = normalizeDate(new Date(today.getFullYear(), today.getMonth(), 0));
305
+ return { start, end };
306
+ },
307
+ },
308
+ {
309
+ label: l.thisYear,
310
+ value: () => {
311
+ const today = new Date();
312
+ const start = normalizeDate(new Date(today.getFullYear(), 0, 1));
313
+ const end = normalizeDate(new Date(today.getFullYear(), 11, 31));
314
+ return { start, end };
315
+ },
316
+ },
317
+ {
318
+ label: l.lastYear,
319
+ value: () => {
320
+ const today = new Date();
321
+ const start = normalizeDate(new Date(today.getFullYear() - 1, 0, 1));
322
+ const end = normalizeDate(new Date(today.getFullYear() - 1, 11, 31));
323
+ return { start, end };
324
+ },
325
+ },
326
+ ];
327
+ }
244
328
 
245
329
  /**
246
330
  * @component FuiCalendarComponent
@@ -709,7 +793,7 @@ class FuiCalendarComponent {
709
793
  this._elementRef.nativeElement.focus();
710
794
  }
711
795
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiCalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
712
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiCalendarComponent, isStandalone: true, selector: "fui-calendar", inputs: { selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, rangeStart: { classPropertyName: "rangeStart", publicName: "rangeStart", isSignal: true, isRequired: false, transformFunction: null }, rangeEnd: { classPropertyName: "rangeEnd", publicName: "rangeEnd", isSignal: true, isRequired: false, transformFunction: null }, range: { classPropertyName: "range", publicName: "range", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, startAt: { classPropertyName: "startAt", publicName: "startAt", isSignal: true, isRequired: false, transformFunction: null }, firstDayOfWeek: { classPropertyName: "firstDayOfWeek", publicName: "firstDayOfWeek", isSignal: true, isRequired: false, transformFunction: null }, hoveredDate: { classPropertyName: "hoveredDate", publicName: "hoveredDate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dateSelected: "dateSelected", dateHovered: "dateHovered", monthChanged: "monthChanged" }, host: { attributes: { "tabindex": "0", "role": "application" }, properties: { "attr.aria-label": "intl.rootAriaLabel" }, classAttribute: "fui-calendar" }, ngImport: i0, template: "<!-- Calendar Header -->\r\n<div class=\"fui-calendar__header\">\r\n <button type=\"button\" class=\"fui-calendar__nav-btn\" (click)=\"onPrev()\" [attr.aria-label]=\"prevButtonLabel()\">\r\n <fui-icon name=\"caret-left\" size=\"sm\" />\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"fui-calendar__header-label\"\r\n (click)=\"onHeaderLabelClick()\"\r\n [attr.aria-label]=\"headerButtonLabel()\"\r\n >\r\n @switch (currentView()) {\r\n @case ('days') {\r\n {{ monthYearLabel() }}\r\n }\r\n @case ('months') {\r\n {{ yearLabel() }}\r\n }\r\n @case ('years') {\r\n {{ decadeLabel() }}\r\n }\r\n }\r\n </button>\r\n\r\n <button type=\"button\" class=\"fui-calendar__nav-btn\" (click)=\"onNext()\" [attr.aria-label]=\"nextButtonLabel()\">\r\n <fui-icon name=\"caret-right\" size=\"sm\" />\r\n </button>\r\n</div>\r\n\r\n<!-- Day View -->\r\n@if (currentView() === 'days') {\r\n <table class=\"fui-calendar__grid\" role=\"grid\" [attr.aria-label]=\"monthYearLabel()\" (keydown)=\"onKeydown($event)\">\r\n <thead>\r\n <tr>\r\n @for (header of weekDayHeaders(); track header) {\r\n <th class=\"fui-calendar__weekday\" scope=\"col\">{{ header }}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (week of weeks(); track trackByWeek($index, week)) {\r\n <tr>\r\n @for (day of week; track trackByDay($index, day)) {\r\n <td\r\n class=\"fui-calendar__cell\"\r\n [class.--today]=\"day.isToday\"\r\n [class.--selected]=\"day.isSelected\"\r\n [class.--outside]=\"!day.isCurrentMonth\"\r\n [class.--disabled]=\"day.isDisabled\"\r\n [class.--range-start]=\"day.isRangeStart\"\r\n [class.--range-end]=\"day.isRangeEnd\"\r\n [class.--in-range]=\"day.isInRange\"\r\n [class.--range-preview]=\"day.isRangePreview\"\r\n role=\"gridcell\"\r\n [attr.aria-selected]=\"day.isSelected\"\r\n [attr.aria-disabled]=\"day.isDisabled\"\r\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\r\n [attr.tabindex]=\"day.isCurrentMonth && !day.isDisabled ? 0 : -1\"\r\n (click)=\"onDayClick(day)\"\r\n (mouseenter)=\"onDayMouseEnter(day)\"\r\n (mouseleave)=\"onDayMouseLeave()\"\r\n >\r\n <span class=\"fui-calendar__day\">{{ day.day }}</span>\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n}\r\n\r\n<!-- Month View -->\r\n@if (currentView() === 'months') {\r\n <div class=\"fui-calendar__months\" role=\"grid\" [attr.aria-label]=\"yearLabel()\" (keydown)=\"onKeydown($event)\">\r\n @for (row of monthsGrid(); track trackByRow($index)) {\r\n <div class=\"fui-calendar__months-row\" role=\"row\">\r\n @for (month of row; track trackByMonth($index, month)) {\r\n <button\r\n type=\"button\"\r\n class=\"fui-calendar__month-cell\"\r\n [class.--current]=\"month.isCurrentMonth\"\r\n [class.--selected]=\"month.isSelected\"\r\n [class.--disabled]=\"month.isDisabled\"\r\n role=\"gridcell\"\r\n [attr.aria-selected]=\"month.isSelected\"\r\n [attr.aria-disabled]=\"month.isDisabled\"\r\n [disabled]=\"month.isDisabled\"\r\n (click)=\"onMonthClick(month)\"\r\n >\r\n {{ month.label }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n}\r\n\r\n<!-- Year View -->\r\n@if (currentView() === 'years') {\r\n <div class=\"fui-calendar__years\" role=\"grid\" [attr.aria-label]=\"decadeLabel()\" (keydown)=\"onKeydown($event)\">\r\n @for (row of yearsGrid(); track trackByRow($index)) {\r\n <div class=\"fui-calendar__years-row\" role=\"row\">\r\n @for (year of row; track trackByYear($index, year)) {\r\n <button\r\n type=\"button\"\r\n class=\"fui-calendar__year-cell\"\r\n [class.--current]=\"year.isCurrentYear\"\r\n [class.--selected]=\"year.isSelected\"\r\n [class.--disabled]=\"year.isDisabled\"\r\n role=\"gridcell\"\r\n [attr.aria-selected]=\"year.isSelected\"\r\n [attr.aria-disabled]=\"year.isDisabled\"\r\n [disabled]=\"year.isDisabled\"\r\n (click)=\"onYearClick(year)\"\r\n >\r\n {{ year.year }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n}\r\n\r\n<!-- Live region for screen readers -->\r\n<div class=\"fui-calendar__announcer\" aria-live=\"polite\" aria-atomic=\"true\">\r\n @switch (currentView()) {\r\n @case ('days') {\r\n {{ monthYearLabel() }}\r\n }\r\n @case ('months') {\r\n {{ yearLabel() }}\r\n }\r\n @case ('years') {\r\n {{ decadeLabel() }}\r\n }\r\n }\r\n</div>\r\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-motion-fade-out{transition:opacity var(--fui-duration-fast-01) var(--fui-ease-exit) 0ms}.fui-motion-slide-in-bottom{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition:transform,opacity var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-moderate-01) var(--fui-ease-entrance)}@keyframes fui-popover-enter{0%{opacity:0;transform:translateY(-14px)}60%{opacity:1}to{opacity:1;transform:translateY(0)}}.fui-calendar{display:block;width:280px;-webkit-user-select:none;user-select:none}.fui-calendar__header{display:flex;align-items:center;justify-content:space-between;padding:var(--fui-spacing-02) var(--fui-spacing-03)}.fui-calendar__nav-btn{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-calendar__nav-btn:focus-visible{outline:2px solid var(--fui-primary);outline-offset:2px}.fui-calendar__nav-btn{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:var(--fui-border-radius-sm);color:var(--fui-text-secondary);transition:background-color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-calendar__nav-btn:hover{background-color:var(--fui-surface-02);color:var(--fui-text-primary)}.fui-calendar__nav-btn:focus-visible{outline:2px solid var(--fui-primary);outline-offset:0}.fui-calendar__header-label{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-calendar__header-label:focus-visible{outline:2px solid var(--fui-primary);outline-offset:2px}.fui-calendar__header-label{font-size:var(--fui-font-size-02);font-weight:var(--fui-font-weight-semibold);color:var(--fui-text-primary);padding:var(--fui-spacing-01) var(--fui-spacing-02);border-radius:var(--fui-border-radius-sm);transition:background-color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-calendar__header-label:hover{background-color:var(--fui-surface-02)}.fui-calendar__header-label:focus-visible{outline:2px solid var(--fui-primary);outline-offset:0}.fui-calendar__grid{width:100%;border-collapse:collapse;border-spacing:0;table-layout:fixed;padding:0 var(--fui-spacing-02)}.fui-calendar__weekday{font-size:var(--fui-font-size-01);font-weight:var(--fui-font-weight-semibold);color:var(--fui-text-secondary);text-align:center;padding-bottom:var(--fui-spacing-01);height:2rem;vertical-align:middle}.fui-calendar__cell{text-align:center;padding:1px;cursor:pointer;position:relative;outline:none}.fui-calendar__cell:focus-visible .fui-calendar__day{outline:2px solid var(--fui-primary);outline-offset:0}.fui-calendar__cell.--disabled{cursor:not-allowed}.fui-calendar__cell.--disabled .fui-calendar__day{color:var(--fui-text-disabled);cursor:not-allowed}.fui-calendar__cell.--disabled .fui-calendar__day:hover{background-color:transparent}.fui-calendar__cell.--outside .fui-calendar__day{color:var(--fui-text-disabled);opacity:.4}.fui-calendar__cell.--today .fui-calendar__day{position:relative;font-weight:var(--fui-font-weight-semibold)}.fui-calendar__cell.--today .fui-calendar__day:after{content:\"\";position:absolute;bottom:2px;left:50%;transform:translate(-50%);width:4px;height:4px;border-radius:50%;background-color:var(--fui-primary)}.fui-calendar__cell.--selected .fui-calendar__day{background-color:var(--fui-primary);color:var(--fui-text-on-primary);font-weight:var(--fui-font-weight-semibold)}.fui-calendar__cell.--selected .fui-calendar__day:after{display:none}.fui-calendar__cell.--range-start .fui-calendar__day,.fui-calendar__cell.--range-end .fui-calendar__day{background-color:var(--fui-primary);color:var(--fui-text-on-primary);font-weight:var(--fui-font-weight-semibold)}.fui-calendar__cell.--range-start{background:linear-gradient(to right,transparent 50%,var(--fui-primary-10) 50%)}.fui-calendar__cell.--range-end{background:linear-gradient(to left,transparent 50%,var(--fui-primary-10) 50%)}.fui-calendar__cell.--range-start.--range-end{background:transparent}.fui-calendar__cell.--in-range{background-color:var(--fui-primary-10)}.fui-calendar__cell.--in-range .fui-calendar__day{color:var(--fui-primary);font-weight:var(--fui-font-weight-medium)}.fui-calendar__cell.--range-preview{background-color:var(--fui-primary-10);opacity:.5}.fui-calendar__cell.--range-preview .fui-calendar__day{color:var(--fui-primary)}.fui-calendar__day{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:50%;font-size:var(--fui-font-size-01);color:var(--fui-text-primary);margin:0 auto;transition:background-color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-calendar__day:hover{background-color:var(--fui-surface-02)}.fui-calendar__months,.fui-calendar__years{padding:var(--fui-spacing-03)}.fui-calendar__months-row,.fui-calendar__years-row{display:flex;justify-content:space-around;margin-bottom:var(--fui-spacing-02)}.fui-calendar__months-row:last-child,.fui-calendar__years-row:last-child{margin-bottom:0}.fui-calendar__month-cell,.fui-calendar__year-cell{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-calendar__month-cell:focus-visible,.fui-calendar__year-cell:focus-visible{outline:2px solid var(--fui-primary);outline-offset:2px}.fui-calendar__month-cell,.fui-calendar__year-cell{display:flex;align-items:center;justify-content:center;width:5rem;height:2.5rem;border-radius:var(--fui-border-radius-md);font-size:var(--fui-font-size-01);color:var(--fui-text-primary);transition:background-color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-calendar__month-cell:hover:not(:disabled),.fui-calendar__year-cell:hover:not(:disabled){background-color:var(--fui-surface-02)}.fui-calendar__month-cell:focus-visible,.fui-calendar__year-cell:focus-visible{outline:2px solid var(--fui-primary);outline-offset:0}.fui-calendar__month-cell.--current,.fui-calendar__year-cell.--current{font-weight:var(--fui-font-weight-semibold);color:var(--fui-primary)}.fui-calendar__month-cell.--selected,.fui-calendar__year-cell.--selected{background-color:var(--fui-primary);color:var(--fui-text-on-primary);font-weight:var(--fui-font-weight-semibold)}.fui-calendar__month-cell.--disabled,.fui-calendar__year-cell.--disabled{color:var(--fui-text-disabled);cursor:not-allowed}.fui-calendar__announcer{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}@media(prefers-contrast:high){.fui-calendar__cell.--selected .fui-calendar__day,.fui-calendar__cell.--range-start .fui-calendar__day,.fui-calendar__cell.--range-end .fui-calendar__day{outline:2px solid}}@media(prefers-reduced-motion:reduce){.fui-calendar__day,.fui-calendar__nav-btn,.fui-calendar__header-label,.fui-calendar__month-cell,.fui-calendar__year-cell{transition:none}}\n"], dependencies: [{ kind: "component", type: FuiIconComponent, selector: "fui-icon", inputs: ["name", "size", "weight", "color", "ariaLabel", "spin", "pulse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
796
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiCalendarComponent, isStandalone: true, selector: "fui-calendar", inputs: { selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, rangeStart: { classPropertyName: "rangeStart", publicName: "rangeStart", isSignal: true, isRequired: false, transformFunction: null }, rangeEnd: { classPropertyName: "rangeEnd", publicName: "rangeEnd", isSignal: true, isRequired: false, transformFunction: null }, range: { classPropertyName: "range", publicName: "range", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, startAt: { classPropertyName: "startAt", publicName: "startAt", isSignal: true, isRequired: false, transformFunction: null }, firstDayOfWeek: { classPropertyName: "firstDayOfWeek", publicName: "firstDayOfWeek", isSignal: true, isRequired: false, transformFunction: null }, hoveredDate: { classPropertyName: "hoveredDate", publicName: "hoveredDate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dateSelected: "dateSelected", dateHovered: "dateHovered", monthChanged: "monthChanged" }, host: { attributes: { "tabindex": "0", "role": "application" }, properties: { "attr.aria-label": "intl.rootAriaLabel" }, classAttribute: "fui-calendar" }, ngImport: i0, template: "<!-- Calendar Header -->\r\n<div class=\"fui-calendar__header\">\r\n <button type=\"button\" class=\"fui-calendar__nav-btn\" (click)=\"onPrev()\" [attr.aria-label]=\"prevButtonLabel()\">\r\n <fui-icon name=\"caret-left\" size=\"sm\" />\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"fui-calendar__header-label\"\r\n (click)=\"onHeaderLabelClick()\"\r\n [attr.aria-label]=\"headerButtonLabel()\"\r\n >\r\n @switch (currentView()) {\r\n @case ('days') {\r\n {{ monthYearLabel() }}\r\n }\r\n @case ('months') {\r\n {{ yearLabel() }}\r\n }\r\n @case ('years') {\r\n {{ decadeLabel() }}\r\n }\r\n }\r\n </button>\r\n\r\n <button type=\"button\" class=\"fui-calendar__nav-btn\" (click)=\"onNext()\" [attr.aria-label]=\"nextButtonLabel()\">\r\n <fui-icon name=\"caret-right\" size=\"sm\" />\r\n </button>\r\n</div>\r\n\r\n<!-- Day View -->\r\n@if (currentView() === 'days') {\r\n <table class=\"fui-calendar__grid\" role=\"grid\" [attr.aria-label]=\"monthYearLabel()\" (keydown)=\"onKeydown($event)\">\r\n <thead>\r\n <tr>\r\n @for (header of weekDayHeaders(); track $index) {\r\n <th class=\"fui-calendar__weekday\" scope=\"col\">{{ header }}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (week of weeks(); track trackByWeek($index, week)) {\r\n <tr>\r\n @for (day of week; track trackByDay($index, day)) {\r\n <td\r\n class=\"fui-calendar__cell\"\r\n [class.--today]=\"day.isToday\"\r\n [class.--selected]=\"day.isSelected\"\r\n [class.--outside]=\"!day.isCurrentMonth\"\r\n [class.--disabled]=\"day.isDisabled\"\r\n [class.--range-start]=\"day.isRangeStart\"\r\n [class.--range-end]=\"day.isRangeEnd\"\r\n [class.--in-range]=\"day.isInRange\"\r\n [class.--range-preview]=\"day.isRangePreview\"\r\n role=\"gridcell\"\r\n [attr.aria-selected]=\"day.isSelected\"\r\n [attr.aria-disabled]=\"day.isDisabled\"\r\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\r\n [attr.tabindex]=\"day.isCurrentMonth && !day.isDisabled ? 0 : -1\"\r\n (click)=\"onDayClick(day)\"\r\n (mouseenter)=\"onDayMouseEnter(day)\"\r\n (mouseleave)=\"onDayMouseLeave()\"\r\n >\r\n <span class=\"fui-calendar__day\">{{ day.day }}</span>\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n}\r\n\r\n<!-- Month View -->\r\n@if (currentView() === 'months') {\r\n <div class=\"fui-calendar__months\" role=\"grid\" [attr.aria-label]=\"yearLabel()\" (keydown)=\"onKeydown($event)\">\r\n @for (row of monthsGrid(); track trackByRow($index)) {\r\n <div class=\"fui-calendar__months-row\" role=\"row\">\r\n @for (month of row; track trackByMonth($index, month)) {\r\n <button\r\n type=\"button\"\r\n class=\"fui-calendar__month-cell\"\r\n [class.--current]=\"month.isCurrentMonth\"\r\n [class.--selected]=\"month.isSelected\"\r\n [class.--disabled]=\"month.isDisabled\"\r\n role=\"gridcell\"\r\n [attr.aria-selected]=\"month.isSelected\"\r\n [attr.aria-disabled]=\"month.isDisabled\"\r\n [disabled]=\"month.isDisabled\"\r\n (click)=\"onMonthClick(month)\"\r\n >\r\n {{ month.label }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n}\r\n\r\n<!-- Year View -->\r\n@if (currentView() === 'years') {\r\n <div class=\"fui-calendar__years\" role=\"grid\" [attr.aria-label]=\"decadeLabel()\" (keydown)=\"onKeydown($event)\">\r\n @for (row of yearsGrid(); track trackByRow($index)) {\r\n <div class=\"fui-calendar__years-row\" role=\"row\">\r\n @for (year of row; track trackByYear($index, year)) {\r\n <button\r\n type=\"button\"\r\n class=\"fui-calendar__year-cell\"\r\n [class.--current]=\"year.isCurrentYear\"\r\n [class.--selected]=\"year.isSelected\"\r\n [class.--disabled]=\"year.isDisabled\"\r\n role=\"gridcell\"\r\n [attr.aria-selected]=\"year.isSelected\"\r\n [attr.aria-disabled]=\"year.isDisabled\"\r\n [disabled]=\"year.isDisabled\"\r\n (click)=\"onYearClick(year)\"\r\n >\r\n {{ year.year }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n}\r\n\r\n<!-- Live region for screen readers -->\r\n<div class=\"fui-calendar__announcer\" aria-live=\"polite\" aria-atomic=\"true\">\r\n @switch (currentView()) {\r\n @case ('days') {\r\n {{ monthYearLabel() }}\r\n }\r\n @case ('months') {\r\n {{ yearLabel() }}\r\n }\r\n @case ('years') {\r\n {{ decadeLabel() }}\r\n }\r\n }\r\n</div>\r\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition-property:opacity;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-out);transition-delay:0ms}.fui-motion-fade-out{transition-property:opacity;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-in);transition-delay:0ms}.fui-motion-slide-in-bottom{transition-property:transform;transition-duration:var(--fui-duration-base);transition-timing-function:var(--fui-ease-out);transition-delay:0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition-property:transform;transition-duration:var(--fui-duration-base);transition-timing-function:var(--fui-ease-out);transition-delay:0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition-property:transform,opacity;transition-duration:var(--fui-duration-base);transition-timing-function:var(--fui-ease-out);transition-delay:0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-base) var(--fui-ease-out)}@keyframes fui-popover-enter{0%{opacity:0;transform:translateY(-14px)}60%{opacity:1}to{opacity:1;transform:translateY(0)}}.fui-calendar{display:block;width:280px;-webkit-user-select:none;user-select:none}.fui-calendar__header{display:flex;align-items:center;justify-content:space-between;padding:var(--fui-spacing-2) var(--fui-spacing-4)}.fui-calendar__nav-btn{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-calendar__nav-btn{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:var(--fui-radius-sm);color:var(--fui-text-secondary);transition-property:background-color;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-in-out);transition-delay:0ms}.fui-calendar__nav-btn:hover{background-color:var(--fui-bg-subtle);color:var(--fui-text-primary)}.fui-calendar__nav-btn:focus-visible{outline:2px solid var(--fui-primary-10)}.fui-calendar__header-label{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-calendar__header-label{font-size:var(--fui-text-base);font-weight:var(--fui-weight-semibold);color:var(--fui-text-primary);padding:var(--fui-spacing-1) var(--fui-spacing-2);border-radius:var(--fui-radius-sm);transition-property:background-color;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-in-out);transition-delay:0ms}.fui-calendar__header-label:hover{background-color:var(--fui-bg-subtle)}.fui-calendar__header-label:focus-visible{outline:2px solid var(--fui-primary-10)}.fui-calendar__grid{width:100%;border-collapse:collapse;border-spacing:0;table-layout:fixed;padding:0 var(--fui-spacing-2)}.fui-calendar__weekday{font-size:var(--fui-text-sm);font-weight:var(--fui-weight-semibold);color:var(--fui-text-secondary);text-align:center;padding-bottom:var(--fui-spacing-1);height:2rem;vertical-align:middle}.fui-calendar__cell{text-align:center;padding:1px 0;cursor:pointer;position:relative;outline:none}.fui-calendar__cell:focus-visible .fui-calendar__day{outline:2px solid var(--fui-primary-10)}.fui-calendar__cell.--disabled{cursor:not-allowed}.fui-calendar__cell.--disabled .fui-calendar__day{color:var(--fui-text-disabled);cursor:not-allowed}.fui-calendar__cell.--disabled .fui-calendar__day:hover{background-color:transparent}.fui-calendar__cell.--outside .fui-calendar__day{color:var(--fui-text-disabled);opacity:.4}.fui-calendar__cell.--today .fui-calendar__day{position:relative;font-weight:var(--fui-weight-semibold)}.fui-calendar__cell.--today .fui-calendar__day:after{content:\"\";position:absolute;bottom:2px;left:50%;transform:translate(-50%);width:4px;height:4px;border-radius:50%;background-color:var(--fui-primary-bg)}.fui-calendar__cell.--selected .fui-calendar__day{background-color:var(--fui-primary-bg);color:var(--fui-text-on-fill);font-weight:var(--fui-weight-semibold)}.fui-calendar__cell.--selected .fui-calendar__day:after{display:none}.fui-calendar__cell.--range-start .fui-calendar__day,.fui-calendar__cell.--range-end .fui-calendar__day{background-color:var(--fui-primary-bg);color:var(--fui-text-on-fill);font-weight:var(--fui-weight-semibold)}.fui-calendar__cell.--range-start{background:linear-gradient(to right,transparent 50%,var(--fui-primary-bg-disabled) 50%)}.fui-calendar__cell.--range-end{background:linear-gradient(to left,transparent 50%,var(--fui-primary-bg-disabled) 50%)}.fui-calendar__cell.--range-start.--range-end{background:transparent}.fui-calendar__cell.--in-range{background-color:var(--fui-primary-bg-disabled)}.fui-calendar__cell.--in-range .fui-calendar__day{color:var(--fui-brand-fg);font-weight:var(--fui-weight-medium)}.fui-calendar__cell.--range-preview{background-color:var(--fui-primary-bg-disabled);opacity:.5}.fui-calendar__cell.--range-preview .fui-calendar__day{color:var(--fui-brand-fg)}.fui-calendar__day{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:50%;font-size:var(--fui-text-sm);color:var(--fui-text-primary);margin:0 auto;transition-property:background-color;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-in-out);transition-delay:0ms}.fui-calendar__day:hover{background-color:var(--fui-bg-subtle)}.fui-calendar__months,.fui-calendar__years{padding:var(--fui-spacing-4)}.fui-calendar__months-row,.fui-calendar__years-row{display:flex;justify-content:space-around;margin-bottom:var(--fui-spacing-2)}.fui-calendar__months-row:last-child,.fui-calendar__years-row:last-child{margin-bottom:0}.fui-calendar__month-cell,.fui-calendar__year-cell{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-calendar__month-cell,.fui-calendar__year-cell{display:flex;align-items:center;justify-content:center;width:5rem;height:2.5rem;border-radius:var(--fui-radius-md);font-size:var(--fui-text-sm);color:var(--fui-text-primary);transition-property:background-color;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-in-out);transition-delay:0ms}.fui-calendar__month-cell:hover:not(:disabled),.fui-calendar__year-cell:hover:not(:disabled){background-color:var(--fui-bg-subtle)}.fui-calendar__month-cell:focus-visible,.fui-calendar__year-cell:focus-visible{outline:2px solid var(--fui-primary-10)}.fui-calendar__month-cell.--current,.fui-calendar__year-cell.--current{font-weight:var(--fui-weight-semibold);color:var(--fui-brand-fg)}.fui-calendar__month-cell.--selected,.fui-calendar__year-cell.--selected{background-color:var(--fui-primary-bg);color:var(--fui-text-on-fill);font-weight:var(--fui-weight-semibold)}.fui-calendar__month-cell.--disabled,.fui-calendar__year-cell.--disabled{color:var(--fui-text-disabled);cursor:not-allowed}.fui-calendar__announcer{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}@media(prefers-contrast:high){.fui-calendar__cell.--selected .fui-calendar__day,.fui-calendar__cell.--range-start .fui-calendar__day,.fui-calendar__cell.--range-end .fui-calendar__day{outline:2px solid}}@media(prefers-reduced-motion:reduce){.fui-calendar__day,.fui-calendar__nav-btn,.fui-calendar__header-label,.fui-calendar__month-cell,.fui-calendar__year-cell{transition:none}}\n"], dependencies: [{ kind: "component", type: FuiIconComponent, selector: "fui-icon", inputs: ["name", "size", "weight", "color", "ariaLabel", "spin", "pulse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
713
797
  }
714
798
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiCalendarComponent, decorators: [{
715
799
  type: Component,
@@ -718,13 +802,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
718
802
  tabindex: '0',
719
803
  role: 'application',
720
804
  '[attr.aria-label]': 'intl.rootAriaLabel',
721
- }, template: "<!-- Calendar Header -->\r\n<div class=\"fui-calendar__header\">\r\n <button type=\"button\" class=\"fui-calendar__nav-btn\" (click)=\"onPrev()\" [attr.aria-label]=\"prevButtonLabel()\">\r\n <fui-icon name=\"caret-left\" size=\"sm\" />\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"fui-calendar__header-label\"\r\n (click)=\"onHeaderLabelClick()\"\r\n [attr.aria-label]=\"headerButtonLabel()\"\r\n >\r\n @switch (currentView()) {\r\n @case ('days') {\r\n {{ monthYearLabel() }}\r\n }\r\n @case ('months') {\r\n {{ yearLabel() }}\r\n }\r\n @case ('years') {\r\n {{ decadeLabel() }}\r\n }\r\n }\r\n </button>\r\n\r\n <button type=\"button\" class=\"fui-calendar__nav-btn\" (click)=\"onNext()\" [attr.aria-label]=\"nextButtonLabel()\">\r\n <fui-icon name=\"caret-right\" size=\"sm\" />\r\n </button>\r\n</div>\r\n\r\n<!-- Day View -->\r\n@if (currentView() === 'days') {\r\n <table class=\"fui-calendar__grid\" role=\"grid\" [attr.aria-label]=\"monthYearLabel()\" (keydown)=\"onKeydown($event)\">\r\n <thead>\r\n <tr>\r\n @for (header of weekDayHeaders(); track header) {\r\n <th class=\"fui-calendar__weekday\" scope=\"col\">{{ header }}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (week of weeks(); track trackByWeek($index, week)) {\r\n <tr>\r\n @for (day of week; track trackByDay($index, day)) {\r\n <td\r\n class=\"fui-calendar__cell\"\r\n [class.--today]=\"day.isToday\"\r\n [class.--selected]=\"day.isSelected\"\r\n [class.--outside]=\"!day.isCurrentMonth\"\r\n [class.--disabled]=\"day.isDisabled\"\r\n [class.--range-start]=\"day.isRangeStart\"\r\n [class.--range-end]=\"day.isRangeEnd\"\r\n [class.--in-range]=\"day.isInRange\"\r\n [class.--range-preview]=\"day.isRangePreview\"\r\n role=\"gridcell\"\r\n [attr.aria-selected]=\"day.isSelected\"\r\n [attr.aria-disabled]=\"day.isDisabled\"\r\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\r\n [attr.tabindex]=\"day.isCurrentMonth && !day.isDisabled ? 0 : -1\"\r\n (click)=\"onDayClick(day)\"\r\n (mouseenter)=\"onDayMouseEnter(day)\"\r\n (mouseleave)=\"onDayMouseLeave()\"\r\n >\r\n <span class=\"fui-calendar__day\">{{ day.day }}</span>\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n}\r\n\r\n<!-- Month View -->\r\n@if (currentView() === 'months') {\r\n <div class=\"fui-calendar__months\" role=\"grid\" [attr.aria-label]=\"yearLabel()\" (keydown)=\"onKeydown($event)\">\r\n @for (row of monthsGrid(); track trackByRow($index)) {\r\n <div class=\"fui-calendar__months-row\" role=\"row\">\r\n @for (month of row; track trackByMonth($index, month)) {\r\n <button\r\n type=\"button\"\r\n class=\"fui-calendar__month-cell\"\r\n [class.--current]=\"month.isCurrentMonth\"\r\n [class.--selected]=\"month.isSelected\"\r\n [class.--disabled]=\"month.isDisabled\"\r\n role=\"gridcell\"\r\n [attr.aria-selected]=\"month.isSelected\"\r\n [attr.aria-disabled]=\"month.isDisabled\"\r\n [disabled]=\"month.isDisabled\"\r\n (click)=\"onMonthClick(month)\"\r\n >\r\n {{ month.label }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n}\r\n\r\n<!-- Year View -->\r\n@if (currentView() === 'years') {\r\n <div class=\"fui-calendar__years\" role=\"grid\" [attr.aria-label]=\"decadeLabel()\" (keydown)=\"onKeydown($event)\">\r\n @for (row of yearsGrid(); track trackByRow($index)) {\r\n <div class=\"fui-calendar__years-row\" role=\"row\">\r\n @for (year of row; track trackByYear($index, year)) {\r\n <button\r\n type=\"button\"\r\n class=\"fui-calendar__year-cell\"\r\n [class.--current]=\"year.isCurrentYear\"\r\n [class.--selected]=\"year.isSelected\"\r\n [class.--disabled]=\"year.isDisabled\"\r\n role=\"gridcell\"\r\n [attr.aria-selected]=\"year.isSelected\"\r\n [attr.aria-disabled]=\"year.isDisabled\"\r\n [disabled]=\"year.isDisabled\"\r\n (click)=\"onYearClick(year)\"\r\n >\r\n {{ year.year }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n}\r\n\r\n<!-- Live region for screen readers -->\r\n<div class=\"fui-calendar__announcer\" aria-live=\"polite\" aria-atomic=\"true\">\r\n @switch (currentView()) {\r\n @case ('days') {\r\n {{ monthYearLabel() }}\r\n }\r\n @case ('months') {\r\n {{ yearLabel() }}\r\n }\r\n @case ('years') {\r\n {{ decadeLabel() }}\r\n }\r\n }\r\n</div>\r\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-motion-fade-out{transition:opacity var(--fui-duration-fast-01) var(--fui-ease-exit) 0ms}.fui-motion-slide-in-bottom{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition:transform,opacity var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-moderate-01) var(--fui-ease-entrance)}@keyframes fui-popover-enter{0%{opacity:0;transform:translateY(-14px)}60%{opacity:1}to{opacity:1;transform:translateY(0)}}.fui-calendar{display:block;width:280px;-webkit-user-select:none;user-select:none}.fui-calendar__header{display:flex;align-items:center;justify-content:space-between;padding:var(--fui-spacing-02) var(--fui-spacing-03)}.fui-calendar__nav-btn{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-calendar__nav-btn:focus-visible{outline:2px solid var(--fui-primary);outline-offset:2px}.fui-calendar__nav-btn{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:var(--fui-border-radius-sm);color:var(--fui-text-secondary);transition:background-color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-calendar__nav-btn:hover{background-color:var(--fui-surface-02);color:var(--fui-text-primary)}.fui-calendar__nav-btn:focus-visible{outline:2px solid var(--fui-primary);outline-offset:0}.fui-calendar__header-label{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-calendar__header-label:focus-visible{outline:2px solid var(--fui-primary);outline-offset:2px}.fui-calendar__header-label{font-size:var(--fui-font-size-02);font-weight:var(--fui-font-weight-semibold);color:var(--fui-text-primary);padding:var(--fui-spacing-01) var(--fui-spacing-02);border-radius:var(--fui-border-radius-sm);transition:background-color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-calendar__header-label:hover{background-color:var(--fui-surface-02)}.fui-calendar__header-label:focus-visible{outline:2px solid var(--fui-primary);outline-offset:0}.fui-calendar__grid{width:100%;border-collapse:collapse;border-spacing:0;table-layout:fixed;padding:0 var(--fui-spacing-02)}.fui-calendar__weekday{font-size:var(--fui-font-size-01);font-weight:var(--fui-font-weight-semibold);color:var(--fui-text-secondary);text-align:center;padding-bottom:var(--fui-spacing-01);height:2rem;vertical-align:middle}.fui-calendar__cell{text-align:center;padding:1px;cursor:pointer;position:relative;outline:none}.fui-calendar__cell:focus-visible .fui-calendar__day{outline:2px solid var(--fui-primary);outline-offset:0}.fui-calendar__cell.--disabled{cursor:not-allowed}.fui-calendar__cell.--disabled .fui-calendar__day{color:var(--fui-text-disabled);cursor:not-allowed}.fui-calendar__cell.--disabled .fui-calendar__day:hover{background-color:transparent}.fui-calendar__cell.--outside .fui-calendar__day{color:var(--fui-text-disabled);opacity:.4}.fui-calendar__cell.--today .fui-calendar__day{position:relative;font-weight:var(--fui-font-weight-semibold)}.fui-calendar__cell.--today .fui-calendar__day:after{content:\"\";position:absolute;bottom:2px;left:50%;transform:translate(-50%);width:4px;height:4px;border-radius:50%;background-color:var(--fui-primary)}.fui-calendar__cell.--selected .fui-calendar__day{background-color:var(--fui-primary);color:var(--fui-text-on-primary);font-weight:var(--fui-font-weight-semibold)}.fui-calendar__cell.--selected .fui-calendar__day:after{display:none}.fui-calendar__cell.--range-start .fui-calendar__day,.fui-calendar__cell.--range-end .fui-calendar__day{background-color:var(--fui-primary);color:var(--fui-text-on-primary);font-weight:var(--fui-font-weight-semibold)}.fui-calendar__cell.--range-start{background:linear-gradient(to right,transparent 50%,var(--fui-primary-10) 50%)}.fui-calendar__cell.--range-end{background:linear-gradient(to left,transparent 50%,var(--fui-primary-10) 50%)}.fui-calendar__cell.--range-start.--range-end{background:transparent}.fui-calendar__cell.--in-range{background-color:var(--fui-primary-10)}.fui-calendar__cell.--in-range .fui-calendar__day{color:var(--fui-primary);font-weight:var(--fui-font-weight-medium)}.fui-calendar__cell.--range-preview{background-color:var(--fui-primary-10);opacity:.5}.fui-calendar__cell.--range-preview .fui-calendar__day{color:var(--fui-primary)}.fui-calendar__day{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:50%;font-size:var(--fui-font-size-01);color:var(--fui-text-primary);margin:0 auto;transition:background-color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-calendar__day:hover{background-color:var(--fui-surface-02)}.fui-calendar__months,.fui-calendar__years{padding:var(--fui-spacing-03)}.fui-calendar__months-row,.fui-calendar__years-row{display:flex;justify-content:space-around;margin-bottom:var(--fui-spacing-02)}.fui-calendar__months-row:last-child,.fui-calendar__years-row:last-child{margin-bottom:0}.fui-calendar__month-cell,.fui-calendar__year-cell{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-calendar__month-cell:focus-visible,.fui-calendar__year-cell:focus-visible{outline:2px solid var(--fui-primary);outline-offset:2px}.fui-calendar__month-cell,.fui-calendar__year-cell{display:flex;align-items:center;justify-content:center;width:5rem;height:2.5rem;border-radius:var(--fui-border-radius-md);font-size:var(--fui-font-size-01);color:var(--fui-text-primary);transition:background-color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-calendar__month-cell:hover:not(:disabled),.fui-calendar__year-cell:hover:not(:disabled){background-color:var(--fui-surface-02)}.fui-calendar__month-cell:focus-visible,.fui-calendar__year-cell:focus-visible{outline:2px solid var(--fui-primary);outline-offset:0}.fui-calendar__month-cell.--current,.fui-calendar__year-cell.--current{font-weight:var(--fui-font-weight-semibold);color:var(--fui-primary)}.fui-calendar__month-cell.--selected,.fui-calendar__year-cell.--selected{background-color:var(--fui-primary);color:var(--fui-text-on-primary);font-weight:var(--fui-font-weight-semibold)}.fui-calendar__month-cell.--disabled,.fui-calendar__year-cell.--disabled{color:var(--fui-text-disabled);cursor:not-allowed}.fui-calendar__announcer{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}@media(prefers-contrast:high){.fui-calendar__cell.--selected .fui-calendar__day,.fui-calendar__cell.--range-start .fui-calendar__day,.fui-calendar__cell.--range-end .fui-calendar__day{outline:2px solid}}@media(prefers-reduced-motion:reduce){.fui-calendar__day,.fui-calendar__nav-btn,.fui-calendar__header-label,.fui-calendar__month-cell,.fui-calendar__year-cell{transition:none}}\n"] }]
805
+ }, template: "<!-- Calendar Header -->\r\n<div class=\"fui-calendar__header\">\r\n <button type=\"button\" class=\"fui-calendar__nav-btn\" (click)=\"onPrev()\" [attr.aria-label]=\"prevButtonLabel()\">\r\n <fui-icon name=\"caret-left\" size=\"sm\" />\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"fui-calendar__header-label\"\r\n (click)=\"onHeaderLabelClick()\"\r\n [attr.aria-label]=\"headerButtonLabel()\"\r\n >\r\n @switch (currentView()) {\r\n @case ('days') {\r\n {{ monthYearLabel() }}\r\n }\r\n @case ('months') {\r\n {{ yearLabel() }}\r\n }\r\n @case ('years') {\r\n {{ decadeLabel() }}\r\n }\r\n }\r\n </button>\r\n\r\n <button type=\"button\" class=\"fui-calendar__nav-btn\" (click)=\"onNext()\" [attr.aria-label]=\"nextButtonLabel()\">\r\n <fui-icon name=\"caret-right\" size=\"sm\" />\r\n </button>\r\n</div>\r\n\r\n<!-- Day View -->\r\n@if (currentView() === 'days') {\r\n <table class=\"fui-calendar__grid\" role=\"grid\" [attr.aria-label]=\"monthYearLabel()\" (keydown)=\"onKeydown($event)\">\r\n <thead>\r\n <tr>\r\n @for (header of weekDayHeaders(); track $index) {\r\n <th class=\"fui-calendar__weekday\" scope=\"col\">{{ header }}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (week of weeks(); track trackByWeek($index, week)) {\r\n <tr>\r\n @for (day of week; track trackByDay($index, day)) {\r\n <td\r\n class=\"fui-calendar__cell\"\r\n [class.--today]=\"day.isToday\"\r\n [class.--selected]=\"day.isSelected\"\r\n [class.--outside]=\"!day.isCurrentMonth\"\r\n [class.--disabled]=\"day.isDisabled\"\r\n [class.--range-start]=\"day.isRangeStart\"\r\n [class.--range-end]=\"day.isRangeEnd\"\r\n [class.--in-range]=\"day.isInRange\"\r\n [class.--range-preview]=\"day.isRangePreview\"\r\n role=\"gridcell\"\r\n [attr.aria-selected]=\"day.isSelected\"\r\n [attr.aria-disabled]=\"day.isDisabled\"\r\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\r\n [attr.tabindex]=\"day.isCurrentMonth && !day.isDisabled ? 0 : -1\"\r\n (click)=\"onDayClick(day)\"\r\n (mouseenter)=\"onDayMouseEnter(day)\"\r\n (mouseleave)=\"onDayMouseLeave()\"\r\n >\r\n <span class=\"fui-calendar__day\">{{ day.day }}</span>\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n}\r\n\r\n<!-- Month View -->\r\n@if (currentView() === 'months') {\r\n <div class=\"fui-calendar__months\" role=\"grid\" [attr.aria-label]=\"yearLabel()\" (keydown)=\"onKeydown($event)\">\r\n @for (row of monthsGrid(); track trackByRow($index)) {\r\n <div class=\"fui-calendar__months-row\" role=\"row\">\r\n @for (month of row; track trackByMonth($index, month)) {\r\n <button\r\n type=\"button\"\r\n class=\"fui-calendar__month-cell\"\r\n [class.--current]=\"month.isCurrentMonth\"\r\n [class.--selected]=\"month.isSelected\"\r\n [class.--disabled]=\"month.isDisabled\"\r\n role=\"gridcell\"\r\n [attr.aria-selected]=\"month.isSelected\"\r\n [attr.aria-disabled]=\"month.isDisabled\"\r\n [disabled]=\"month.isDisabled\"\r\n (click)=\"onMonthClick(month)\"\r\n >\r\n {{ month.label }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n}\r\n\r\n<!-- Year View -->\r\n@if (currentView() === 'years') {\r\n <div class=\"fui-calendar__years\" role=\"grid\" [attr.aria-label]=\"decadeLabel()\" (keydown)=\"onKeydown($event)\">\r\n @for (row of yearsGrid(); track trackByRow($index)) {\r\n <div class=\"fui-calendar__years-row\" role=\"row\">\r\n @for (year of row; track trackByYear($index, year)) {\r\n <button\r\n type=\"button\"\r\n class=\"fui-calendar__year-cell\"\r\n [class.--current]=\"year.isCurrentYear\"\r\n [class.--selected]=\"year.isSelected\"\r\n [class.--disabled]=\"year.isDisabled\"\r\n role=\"gridcell\"\r\n [attr.aria-selected]=\"year.isSelected\"\r\n [attr.aria-disabled]=\"year.isDisabled\"\r\n [disabled]=\"year.isDisabled\"\r\n (click)=\"onYearClick(year)\"\r\n >\r\n {{ year.year }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n}\r\n\r\n<!-- Live region for screen readers -->\r\n<div class=\"fui-calendar__announcer\" aria-live=\"polite\" aria-atomic=\"true\">\r\n @switch (currentView()) {\r\n @case ('days') {\r\n {{ monthYearLabel() }}\r\n }\r\n @case ('months') {\r\n {{ yearLabel() }}\r\n }\r\n @case ('years') {\r\n {{ decadeLabel() }}\r\n }\r\n }\r\n</div>\r\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition-property:opacity;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-out);transition-delay:0ms}.fui-motion-fade-out{transition-property:opacity;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-in);transition-delay:0ms}.fui-motion-slide-in-bottom{transition-property:transform;transition-duration:var(--fui-duration-base);transition-timing-function:var(--fui-ease-out);transition-delay:0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition-property:transform;transition-duration:var(--fui-duration-base);transition-timing-function:var(--fui-ease-out);transition-delay:0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition-property:transform,opacity;transition-duration:var(--fui-duration-base);transition-timing-function:var(--fui-ease-out);transition-delay:0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-base) var(--fui-ease-out)}@keyframes fui-popover-enter{0%{opacity:0;transform:translateY(-14px)}60%{opacity:1}to{opacity:1;transform:translateY(0)}}.fui-calendar{display:block;width:280px;-webkit-user-select:none;user-select:none}.fui-calendar__header{display:flex;align-items:center;justify-content:space-between;padding:var(--fui-spacing-2) var(--fui-spacing-4)}.fui-calendar__nav-btn{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-calendar__nav-btn{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:var(--fui-radius-sm);color:var(--fui-text-secondary);transition-property:background-color;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-in-out);transition-delay:0ms}.fui-calendar__nav-btn:hover{background-color:var(--fui-bg-subtle);color:var(--fui-text-primary)}.fui-calendar__nav-btn:focus-visible{outline:2px solid var(--fui-primary-10)}.fui-calendar__header-label{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-calendar__header-label{font-size:var(--fui-text-base);font-weight:var(--fui-weight-semibold);color:var(--fui-text-primary);padding:var(--fui-spacing-1) var(--fui-spacing-2);border-radius:var(--fui-radius-sm);transition-property:background-color;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-in-out);transition-delay:0ms}.fui-calendar__header-label:hover{background-color:var(--fui-bg-subtle)}.fui-calendar__header-label:focus-visible{outline:2px solid var(--fui-primary-10)}.fui-calendar__grid{width:100%;border-collapse:collapse;border-spacing:0;table-layout:fixed;padding:0 var(--fui-spacing-2)}.fui-calendar__weekday{font-size:var(--fui-text-sm);font-weight:var(--fui-weight-semibold);color:var(--fui-text-secondary);text-align:center;padding-bottom:var(--fui-spacing-1);height:2rem;vertical-align:middle}.fui-calendar__cell{text-align:center;padding:1px 0;cursor:pointer;position:relative;outline:none}.fui-calendar__cell:focus-visible .fui-calendar__day{outline:2px solid var(--fui-primary-10)}.fui-calendar__cell.--disabled{cursor:not-allowed}.fui-calendar__cell.--disabled .fui-calendar__day{color:var(--fui-text-disabled);cursor:not-allowed}.fui-calendar__cell.--disabled .fui-calendar__day:hover{background-color:transparent}.fui-calendar__cell.--outside .fui-calendar__day{color:var(--fui-text-disabled);opacity:.4}.fui-calendar__cell.--today .fui-calendar__day{position:relative;font-weight:var(--fui-weight-semibold)}.fui-calendar__cell.--today .fui-calendar__day:after{content:\"\";position:absolute;bottom:2px;left:50%;transform:translate(-50%);width:4px;height:4px;border-radius:50%;background-color:var(--fui-primary-bg)}.fui-calendar__cell.--selected .fui-calendar__day{background-color:var(--fui-primary-bg);color:var(--fui-text-on-fill);font-weight:var(--fui-weight-semibold)}.fui-calendar__cell.--selected .fui-calendar__day:after{display:none}.fui-calendar__cell.--range-start .fui-calendar__day,.fui-calendar__cell.--range-end .fui-calendar__day{background-color:var(--fui-primary-bg);color:var(--fui-text-on-fill);font-weight:var(--fui-weight-semibold)}.fui-calendar__cell.--range-start{background:linear-gradient(to right,transparent 50%,var(--fui-primary-bg-disabled) 50%)}.fui-calendar__cell.--range-end{background:linear-gradient(to left,transparent 50%,var(--fui-primary-bg-disabled) 50%)}.fui-calendar__cell.--range-start.--range-end{background:transparent}.fui-calendar__cell.--in-range{background-color:var(--fui-primary-bg-disabled)}.fui-calendar__cell.--in-range .fui-calendar__day{color:var(--fui-brand-fg);font-weight:var(--fui-weight-medium)}.fui-calendar__cell.--range-preview{background-color:var(--fui-primary-bg-disabled);opacity:.5}.fui-calendar__cell.--range-preview .fui-calendar__day{color:var(--fui-brand-fg)}.fui-calendar__day{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:50%;font-size:var(--fui-text-sm);color:var(--fui-text-primary);margin:0 auto;transition-property:background-color;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-in-out);transition-delay:0ms}.fui-calendar__day:hover{background-color:var(--fui-bg-subtle)}.fui-calendar__months,.fui-calendar__years{padding:var(--fui-spacing-4)}.fui-calendar__months-row,.fui-calendar__years-row{display:flex;justify-content:space-around;margin-bottom:var(--fui-spacing-2)}.fui-calendar__months-row:last-child,.fui-calendar__years-row:last-child{margin-bottom:0}.fui-calendar__month-cell,.fui-calendar__year-cell{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-calendar__month-cell,.fui-calendar__year-cell{display:flex;align-items:center;justify-content:center;width:5rem;height:2.5rem;border-radius:var(--fui-radius-md);font-size:var(--fui-text-sm);color:var(--fui-text-primary);transition-property:background-color;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-in-out);transition-delay:0ms}.fui-calendar__month-cell:hover:not(:disabled),.fui-calendar__year-cell:hover:not(:disabled){background-color:var(--fui-bg-subtle)}.fui-calendar__month-cell:focus-visible,.fui-calendar__year-cell:focus-visible{outline:2px solid var(--fui-primary-10)}.fui-calendar__month-cell.--current,.fui-calendar__year-cell.--current{font-weight:var(--fui-weight-semibold);color:var(--fui-brand-fg)}.fui-calendar__month-cell.--selected,.fui-calendar__year-cell.--selected{background-color:var(--fui-primary-bg);color:var(--fui-text-on-fill);font-weight:var(--fui-weight-semibold)}.fui-calendar__month-cell.--disabled,.fui-calendar__year-cell.--disabled{color:var(--fui-text-disabled);cursor:not-allowed}.fui-calendar__announcer{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}@media(prefers-contrast:high){.fui-calendar__cell.--selected .fui-calendar__day,.fui-calendar__cell.--range-start .fui-calendar__day,.fui-calendar__cell.--range-end .fui-calendar__day{outline:2px solid}}@media(prefers-reduced-motion:reduce){.fui-calendar__day,.fui-calendar__nav-btn,.fui-calendar__header-label,.fui-calendar__month-cell,.fui-calendar__year-cell{transition:none}}\n"] }]
722
806
  }], ctorParameters: () => [], propDecorators: { selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }], rangeStart: [{ type: i0.Input, args: [{ isSignal: true, alias: "rangeStart", required: false }] }], rangeEnd: [{ type: i0.Input, args: [{ isSignal: true, alias: "rangeEnd", required: false }] }], range: [{ type: i0.Input, args: [{ isSignal: true, alias: "range", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], startAt: [{ type: i0.Input, args: [{ isSignal: true, alias: "startAt", required: false }] }], firstDayOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstDayOfWeek", required: false }] }], hoveredDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "hoveredDate", required: false }] }], dateSelected: [{ type: i0.Output, args: ["dateSelected"] }], dateHovered: [{ type: i0.Output, args: ["dateHovered"] }], monthChanged: [{ type: i0.Output, args: ["monthChanged"] }] } });
723
807
 
724
808
  class FuiDatePickerIntl extends FuiIntlBase {
725
809
  endDateAriaLabel = 'End date';
726
810
  openCalendarAriaLabel = 'Open calendar';
727
811
  calendarDialogAriaLabel = 'Calendar';
812
+ presetsAriaLabel = 'Date presets';
728
813
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiDatePickerIntl, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
729
814
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiDatePickerIntl, providedIn: 'root' });
730
815
  }
@@ -785,10 +870,12 @@ class FuiDatePickerComponent {
785
870
  controlType = 'fui-date-picker';
786
871
  intl = inject(FuiDatePickerIntl);
787
872
  _cdr = inject(ChangeDetectorRef);
873
+ _popup = inject(FuiPopupOverlayDirective);
874
+ _formSync = inject(FuiFormControlSyncDirective);
788
875
  // Inputs
789
876
  placeholderInput = input('', { ...(ngDevMode ? { debugName: "placeholderInput" } : /* istanbul ignore next */ {}), alias: 'placeholder' });
790
877
  disabledInput = input(false, { ...(ngDevMode ? { debugName: "disabledInput" } : /* istanbul ignore next */ {}), alias: 'disabled' });
791
- readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
878
+ readonlyInput = input(false, { ...(ngDevMode ? { debugName: "readonlyInput" } : /* istanbul ignore next */ {}), alias: 'readonly' });
792
879
  range = input(false, ...(ngDevMode ? [{ debugName: "range" }] : /* istanbul ignore next */ []));
793
880
  format = input(DEFAULT_DATE_FORMAT, ...(ngDevMode ? [{ debugName: "format" }] : /* istanbul ignore next */ []));
794
881
  min = input(null, ...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
@@ -798,6 +885,7 @@ class FuiDatePickerComponent {
798
885
  firstDayOfWeek = input(1, ...(ngDevMode ? [{ debugName: "firstDayOfWeek" }] : /* istanbul ignore next */ []));
799
886
  rangeSeparator = input(RANGE_SEPARATOR, ...(ngDevMode ? [{ debugName: "rangeSeparator" }] : /* istanbul ignore next */ []));
800
887
  errorStateMatcher = input(null, ...(ngDevMode ? [{ debugName: "errorStateMatcher" }] : /* istanbul ignore next */ []));
888
+ presets = input([], ...(ngDevMode ? [{ debugName: "presets" }] : /* istanbul ignore next */ []));
801
889
  // Outputs
802
890
  valueChange = output();
803
891
  dateChange = output();
@@ -809,8 +897,8 @@ class FuiDatePickerComponent {
809
897
  _ngControlDisabled = signal(false, ...(ngDevMode ? [{ debugName: "_ngControlDisabled" }] : /* istanbul ignore next */ []));
810
898
  _required = signal(false, ...(ngDevMode ? [{ debugName: "_required" }] : /* istanbul ignore next */ []));
811
899
  _errorState = signal(false, ...(ngDevMode ? [{ debugName: "_errorState" }] : /* istanbul ignore next */ []));
812
- _readOnly = signal(false, ...(ngDevMode ? [{ debugName: "_readOnly" }] : /* istanbul ignore next */ []));
813
- panelOpen = signal(false, ...(ngDevMode ? [{ debugName: "panelOpen" }] : /* istanbul ignore next */ []));
900
+ /** Whether the calendar panel is open projected from FuiPopupOverlayDirective. */
901
+ panelOpen = computed(() => this._popup.panelOpen(), ...(ngDevMode ? [{ debugName: "panelOpen" }] : /* istanbul ignore next */ []));
814
902
  // Range hover
815
903
  hoveredDate = signal(null, ...(ngDevMode ? [{ debugName: "hoveredDate" }] : /* istanbul ignore next */ []));
816
904
  // FuiFormFieldControl
@@ -818,9 +906,6 @@ class FuiDatePickerComponent {
818
906
  _uid = `fui-date-picker-${FuiDatePickerComponent.nextId++}`;
819
907
  _ariaDescribedby = null;
820
908
  // Form references
821
- _parentForm = inject(NgForm, { optional: true });
822
- _parentFormGroup = inject(FormGroupDirective, { optional: true });
823
- _defaultErrorStateMatcher = inject(DefaultErrorStateMatcher);
824
909
  _ngControlRef = injectNgControl();
825
910
  get ngControl() {
826
911
  return this._ngControlRef.ngControl;
@@ -831,6 +916,7 @@ class FuiDatePickerComponent {
831
916
  value = this._value;
832
917
  focused = this._focused;
833
918
  disabled = computed(() => this._disabled() || this.disabledInput() || this._ngControlDisabled(), ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
919
+ readonly = computed(() => this.readonlyInput(), ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
834
920
  errorState = this._errorState;
835
921
  id = this._uid;
836
922
  empty = computed(() => {
@@ -866,15 +952,10 @@ class FuiDatePickerComponent {
866
952
  calendarPanel;
867
953
  startInputEl;
868
954
  endInputEl;
955
+ // ViewChild for fuiInput directives — delegates readonly/disabled/aria/state
956
+ _fuiStartInput;
957
+ _fuiEndInput;
869
958
  calendarComponent;
870
- // Overlay
871
- _overlayRef = null;
872
- _overlaySubscriptions = new Subscription();
873
- _overlayService = inject(FuiOverlayService);
874
- _elementRef = inject(ElementRef);
875
- _document = inject(DOCUMENT);
876
- _ngZone = inject(NgZone);
877
- _outsideClickSub;
878
959
  // CVA callbacks
879
960
  _onChange = () => {
880
961
  /* noop */
@@ -908,59 +989,84 @@ class FuiDatePickerComponent {
908
989
  this._ngControlRef.ngControl.valueAccessor = this;
909
990
  }
910
991
  });
911
- // Effect to emit state changes
992
+ // Effect A: sync display text then emit state changes
993
+ // Combines former "display-value" and "state-sync" effects; both depend on
994
+ // _value / format / range, so merging avoids a redundant second reaction on
995
+ // those signals. Display text is refreshed first so stateChanges listeners
996
+ // always observe the up-to-date text.
912
997
  effect(() => {
998
+ const val = this._value();
999
+ const fmt = this.format();
1000
+ if (this.range() && this._isDateRange(val)) {
1001
+ this.startInputText.set(formatDate(val.start, fmt));
1002
+ this.endInputText.set(formatDate(val.end, fmt));
1003
+ }
1004
+ else if (val instanceof Date) {
1005
+ this.startInputText.set(formatDate(val, fmt));
1006
+ }
1007
+ else {
1008
+ this.startInputText.set('');
1009
+ this.endInputText.set('');
1010
+ }
913
1011
  this.placeholderInput();
914
1012
  this.readonly();
915
1013
  this.disabledInput();
916
- this.range();
917
- this.format();
918
1014
  this.errorStateMatcher();
919
1015
  this._focused();
920
1016
  this._disabled();
921
- this._value();
922
1017
  this._ngControlDisabled();
923
1018
  this._required();
924
1019
  this._errorState();
925
1020
  this.stateChanges.next();
926
1021
  });
927
- // Re-trigger validation when min/max/dateFilter change
1022
+ // Effect B: re-trigger validation when validator-influencing inputs change
928
1023
  effect(() => {
929
1024
  this.min();
930
1025
  this.max();
931
1026
  this.dateFilter();
932
1027
  this._onValidatorChange();
933
1028
  });
934
- // Sync display text when value changes
1029
+ // Effect C: shift focus after panel open/close via queueMicrotask so that
1030
+ // Angular's change-detection has already flushed the [hidden] binding before
1031
+ // .focus() is called. Calling .focus() synchronously inside open()/close()
1032
+ // fails silently because the calendar element still has a [hidden] ancestor
1033
+ // at that point (CD has not run yet), so the browser refuses to focus it.
1034
+ // _panelOpenInitialized skips the very first synchronous run (panelOpen=false
1035
+ // at construction time) to avoid spuriously moving focus to the input on init.
1036
+ let _panelOpenInitialized = false;
935
1037
  effect(() => {
936
- const val = this._value();
937
- const fmt = this.format();
938
- if (this.range() && this._isDateRange(val)) {
939
- this.startInputText.set(formatDate(val.start, fmt));
940
- this.endInputText.set(formatDate(val.end, fmt));
1038
+ const isOpen = this._popup.panelOpen();
1039
+ if (!_panelOpenInitialized) {
1040
+ _panelOpenInitialized = true;
1041
+ return;
941
1042
  }
942
- else if (val instanceof Date) {
943
- this.startInputText.set(formatDate(val, fmt));
1043
+ if (isOpen) {
1044
+ queueMicrotask(() => this.calendarComponent?.focus());
944
1045
  }
945
1046
  else {
946
- this.startInputText.set('');
947
- this.endInputText.set('');
1047
+ queueMicrotask(() => this.startInputEl?.nativeElement.focus());
948
1048
  }
949
1049
  });
950
1050
  }
951
- ngDoCheck() {
952
- if (this.ngControl) {
953
- updateErrorState(this.ngControl, this._errorState, this.errorStateMatcher(), this._defaultErrorStateMatcher, this._parentForm, this._parentFormGroup, this.stateChanges);
954
- syncRequiredState(this.ngControl, this._required, this.stateChanges);
955
- syncNgControlDisabled(this.ngControl, this._ngControlDisabled, this.stateChanges);
956
- }
1051
+ ngAfterViewInit() {
1052
+ // Wire popup-overlay directive. Both triggerEl and calendarPanel use static:true so refs
1053
+ // are resolved here regardless of panel open state (panel is always rendered via [hidden]).
1054
+ this._popup.setTrigger(this.triggerEl ?? null);
1055
+ this._popup.setPanel(this.calendarPanel ?? null);
1056
+ this._popup.panelClass.set(['fui-date-picker-overlay-panel']);
1057
+ this._popup.backdropClass.set('fui-date-picker-backdrop');
1058
+ // Wire form-control-sync directive signals
1059
+ this._formSync.errorState.set(this._errorState);
1060
+ this._formSync.errorStateMatcher.set(this.errorStateMatcher());
1061
+ this._formSync.required.set(this._required);
1062
+ this._formSync.ngControlDisabled.set(this._ngControlDisabled);
1063
+ this._formSync.stateChanges.set(this.stateChanges);
957
1064
  }
958
1065
  ngOnDestroy() {
959
1066
  this.stateChanges.complete();
960
- this._outsideClickSub?.unsubscribe();
961
- this._disposeOverlay();
962
1067
  }
963
1068
  // --- CVA ---
1069
+ /** Sets the picker value from the form model. Accepts Date, DateRange, ISO string, or null. */
964
1070
  writeValue(value) {
965
1071
  if (typeof value === 'string') {
966
1072
  const parsed = parseDate(value, this.format());
@@ -981,17 +1087,21 @@ class FuiDatePickerComponent {
981
1087
  }
982
1088
  this.stateChanges.next();
983
1089
  }
1090
+ /** Registers the callback Angular calls when the value should propagate to the model. */
984
1091
  registerOnChange(fn) {
985
1092
  this._onChange = fn;
986
1093
  }
1094
+ /** Registers the callback Angular calls when the control should be marked as touched. */
987
1095
  registerOnTouched(fn) {
988
1096
  this._onTouched = fn;
989
1097
  }
1098
+ /** Enables or disables the control programmatically; mirrors the `disabled` form-control state. */
990
1099
  setDisabledState(isDisabled) {
991
1100
  this._disabled.set(isDisabled);
992
1101
  this.stateChanges.next();
993
1102
  }
994
1103
  // --- Validator ---
1104
+ /** Validates the current date value against min, max, and dateFilter constraints. Returns null when valid. */
995
1105
  validate(_control) {
996
1106
  const value = this._value();
997
1107
  if (value === null)
@@ -1018,6 +1128,7 @@ class FuiDatePickerComponent {
1018
1128
  }
1019
1129
  return null;
1020
1130
  }
1131
+ /** Stores the callback Angular calls when validator inputs (min/max/filter) change so the form re-validates. */
1021
1132
  registerOnValidatorChange(fn) {
1022
1133
  this._onValidatorChange = fn;
1023
1134
  }
@@ -1034,6 +1145,7 @@ class FuiDatePickerComponent {
1034
1145
  return null;
1035
1146
  }
1036
1147
  // --- FuiFormFieldControl ---
1148
+ /** Focuses the start input and opens the calendar panel when the form-field container is clicked, unless disabled. */
1037
1149
  onContainerClick(_event) {
1038
1150
  if (!this.disabled()) {
1039
1151
  this.startInputEl?.nativeElement.focus();
@@ -1042,43 +1154,34 @@ class FuiDatePickerComponent {
1042
1154
  }
1043
1155
  }
1044
1156
  }
1157
+ /** Stores the space-separated list of IDs for the aria-describedby attribute. */
1045
1158
  setDescribedByIds(ids) {
1046
1159
  this._ariaDescribedby = ids.length ? ids.join(' ') : null;
1047
- }
1048
- setReadOnly(readOnly) {
1049
- this._readOnly.set(readOnly);
1160
+ this._fuiStartInput?.setDescribedByIds(ids);
1161
+ this._fuiEndInput?.setDescribedByIds(ids);
1050
1162
  }
1051
1163
  // --- Panel open/close ---
1164
+ /** Opens the calendar panel. No-op if disabled, readonly, or already open. */
1052
1165
  open() {
1053
- if (this.disabled() || this.readonly() || this.panelOpen())
1166
+ if (this.disabled() || this.readonly() || this._popup.panelOpen())
1054
1167
  return;
1055
- requestAnimationFrame(() => {
1056
- this.panelOpen.set(true);
1057
- this._focused.set(true);
1058
- this.openedChange.emit(true);
1059
- setTimeout(() => {
1060
- this._createOverlay();
1061
- this._listenForOutsideClicks();
1062
- this.calendarComponent?.focus();
1063
- });
1064
- });
1168
+ this._focused.set(true);
1169
+ this.openedChange.emit(true);
1170
+ this._popup.open();
1065
1171
  }
1172
+ /** Closes the calendar panel and restores focus to the start input. No-op if already closed. */
1066
1173
  close() {
1067
- if (!this.panelOpen())
1174
+ if (!this._popup.panelOpen())
1068
1175
  return;
1069
- this._outsideClickSub?.unsubscribe();
1070
- this.panelOpen.set(false);
1071
1176
  this._focused.set(false);
1072
1177
  this.hoveredDate.set(null);
1073
- this._disposeOverlay();
1074
- this.openedChange.emit(false);
1075
1178
  this._onTouched();
1076
- setTimeout(() => {
1077
- this.startInputEl?.nativeElement.focus();
1078
- }, 0);
1179
+ this._popup.close();
1180
+ this.openedChange.emit(false);
1079
1181
  }
1182
+ /** Toggles the calendar panel between open and closed. */
1080
1183
  toggle() {
1081
- if (this.panelOpen()) {
1184
+ if (this._popup.panelOpen()) {
1082
1185
  this.close();
1083
1186
  }
1084
1187
  else {
@@ -1144,6 +1247,7 @@ class FuiDatePickerComponent {
1144
1247
  onKeydown(event) {
1145
1248
  if (event.key === 'Escape' && this.panelOpen()) {
1146
1249
  event.preventDefault();
1250
+ event.stopPropagation();
1147
1251
  this.close();
1148
1252
  }
1149
1253
  else if ((event.key === 'ArrowDown' || event.key === 'Enter') && !this.panelOpen()) {
@@ -1185,6 +1289,7 @@ class FuiDatePickerComponent {
1185
1289
  onEndKeydown(event) {
1186
1290
  if (event.key === 'Escape' && this.panelOpen()) {
1187
1291
  event.preventDefault();
1292
+ event.stopPropagation();
1188
1293
  this.close();
1189
1294
  }
1190
1295
  }
@@ -1204,25 +1309,29 @@ class FuiDatePickerComponent {
1204
1309
  onDateHovered(date) {
1205
1310
  this.hoveredDate.set(date);
1206
1311
  }
1207
- // Start listening for outside clicks when panel opens
1208
- _listenForOutsideClicks() {
1209
- this._outsideClickSub?.unsubscribe();
1210
- this._ngZone.runOutsideAngular(() => {
1211
- setTimeout(() => {
1212
- this._outsideClickSub = fromEvent(this._document, 'click')
1213
- .pipe(filter(() => this.panelOpen()), filter((event) => {
1214
- const target = event.target;
1215
- const hostElement = this._elementRef.nativeElement;
1216
- const overlayElement = this._overlayRef?.overlayElement;
1217
- return !hostElement.contains(target) && !overlayElement?.contains(target);
1218
- }))
1219
- .subscribe(() => {
1220
- this._ngZone.run(() => {
1221
- this.close();
1222
- });
1223
- });
1224
- });
1225
- });
1312
+ /** @internal Handle a preset click apply the preset value and close the panel. */
1313
+ _onPresetClick(preset) {
1314
+ const value = preset.value();
1315
+ if (value === null) {
1316
+ this._setValue(null);
1317
+ this.close();
1318
+ return;
1319
+ }
1320
+ if (this.range()) {
1321
+ if (value instanceof Date) {
1322
+ this._setValue({ start: value, end: value });
1323
+ }
1324
+ else {
1325
+ const start = value.start ? normalizeDate(value.start) : null;
1326
+ const end = value.end ? normalizeDate(value.end) : null;
1327
+ this._setValue({ start, end });
1328
+ }
1329
+ }
1330
+ else {
1331
+ const single = value instanceof Date ? normalizeDate(value) : value.start;
1332
+ this._setValue(single ? normalizeDate(single) : null);
1333
+ }
1334
+ this.close();
1226
1335
  }
1227
1336
  // --- Private helpers ---
1228
1337
  _handleRangeSelection(date) {
@@ -1251,65 +1360,22 @@ class FuiDatePickerComponent {
1251
1360
  this.dateChange.emit(value);
1252
1361
  this.stateChanges.next();
1253
1362
  }
1254
- _createOverlay() {
1255
- if (this._overlayRef || !this.calendarPanel || !this.triggerEl)
1256
- return;
1257
- const triggerElement = this.triggerEl.nativeElement;
1258
- const triggerWidth = triggerElement.getBoundingClientRect().width;
1259
- const positions = [
1260
- { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },
1261
- { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },
1262
- ];
1263
- const positionStrategy = this._overlayService
1264
- .position()
1265
- .connectedTo(triggerElement, positions)
1266
- .withPush(true)
1267
- .withViewportMargin(8);
1268
- this._overlayRef = this._overlayService.create({
1269
- positionStrategy,
1270
- scrollStrategy: this._overlayService.scrollStrategies.reposition(),
1271
- hasBackdrop: true,
1272
- backdropClass: 'fui-date-picker-backdrop',
1273
- backdropClickBehavior: 'close',
1274
- panelClass: ['fui-date-picker-overlay-panel'],
1275
- minWidth: Math.max(triggerWidth, 280),
1276
- });
1277
- // Track overlay subscriptions for proper cleanup
1278
- this._overlaySubscriptions.unsubscribe();
1279
- this._overlaySubscriptions = new Subscription();
1280
- this._overlaySubscriptions.add(this._overlayRef.backdropClick.subscribe(() => {
1281
- this.close();
1282
- }));
1283
- this._overlaySubscriptions.add(this._overlayRef.keydownEvents.subscribe((event) => {
1284
- if (event.key === 'Escape') {
1285
- this.close();
1286
- }
1287
- }));
1288
- const panelElement = this.calendarPanel.nativeElement;
1289
- this._overlayRef.attach(panelElement);
1290
- }
1291
- _disposeOverlay() {
1292
- this._overlaySubscriptions.unsubscribe();
1293
- if (this._overlayRef) {
1294
- this._overlayRef.dispose();
1295
- this._overlayRef = null;
1296
- }
1297
- }
1298
1363
  _isDateRange(val) {
1299
1364
  return val !== null && !(val instanceof Date) && typeof val === 'object' && 'start' in val;
1300
1365
  }
1301
- // Public: get the computed placeholder for the start input
1366
+ /** Returns the placeholder for the start input: uses the `placeholder` input if set, otherwise the format string. */
1302
1367
  getStartPlaceholder() {
1303
1368
  const p = this.placeholderInput();
1304
1369
  if (p)
1305
1370
  return p;
1306
1371
  return this.format().toLowerCase();
1307
1372
  }
1373
+ /** Returns the placeholder for the end input in range mode: the format string lowercased. */
1308
1374
  getEndPlaceholder() {
1309
1375
  return this.format().toLowerCase();
1310
1376
  }
1311
1377
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiDatePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1312
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiDatePickerComponent, isStandalone: true, selector: "fui-date-picker", inputs: { placeholderInput: { classPropertyName: "placeholderInput", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, range: { classPropertyName: "range", publicName: "range", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, startAt: { classPropertyName: "startAt", publicName: "startAt", isSignal: true, isRequired: false, transformFunction: null }, firstDayOfWeek: { classPropertyName: "firstDayOfWeek", publicName: "firstDayOfWeek", isSignal: true, isRequired: false, transformFunction: null }, rangeSeparator: { classPropertyName: "rangeSeparator", publicName: "rangeSeparator", isSignal: true, isRequired: false, transformFunction: null }, errorStateMatcher: { classPropertyName: "errorStateMatcher", publicName: "errorStateMatcher", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", dateChange: "dateChange", openedChange: "openedChange" }, host: { properties: { "attr.id": "id", "class.fui-date-picker--open": "panelOpen()", "class.fui-date-picker--disabled": "disabled()", "class.fui-date-picker--range": "range()", "class.fui-date-picker--focused": "focused()", "class.fui-date-picker--error": "errorState()", "class.fui-date-picker--readonly": "_readOnly()" }, classAttribute: "fui-date-picker" }, providers: [
1378
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiDatePickerComponent, isStandalone: true, selector: "fui-date-picker", inputs: { placeholderInput: { classPropertyName: "placeholderInput", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonlyInput: { classPropertyName: "readonlyInput", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, range: { classPropertyName: "range", publicName: "range", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, startAt: { classPropertyName: "startAt", publicName: "startAt", isSignal: true, isRequired: false, transformFunction: null }, firstDayOfWeek: { classPropertyName: "firstDayOfWeek", publicName: "firstDayOfWeek", isSignal: true, isRequired: false, transformFunction: null }, rangeSeparator: { classPropertyName: "rangeSeparator", publicName: "rangeSeparator", isSignal: true, isRequired: false, transformFunction: null }, errorStateMatcher: { classPropertyName: "errorStateMatcher", publicName: "errorStateMatcher", isSignal: true, isRequired: false, transformFunction: null }, presets: { classPropertyName: "presets", publicName: "presets", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", dateChange: "dateChange", openedChange: "openedChange" }, host: { properties: { "attr.id": "id", "class.fui-date-picker--open": "panelOpen()", "class.fui-date-picker--disabled": "disabled()", "class.fui-date-picker--range": "range()", "class.fui-date-picker--focused": "focused()", "class.fui-date-picker--error": "errorState()", "class.fui-date-picker--readonly": "readonly()" }, classAttribute: "fui-date-picker" }, providers: [
1313
1379
  {
1314
1380
  provide: NG_VALUE_ACCESSOR,
1315
1381
  useExisting: FuiDatePickerComponent,
@@ -1324,11 +1390,18 @@ class FuiDatePickerComponent {
1324
1390
  provide: FUI_FORM_FIELD_CONTROL,
1325
1391
  useExisting: FuiDatePickerComponent,
1326
1392
  },
1327
- ], viewQueries: [{ propertyName: "triggerEl", first: true, predicate: ["triggerEl"], descendants: true }, { propertyName: "calendarPanel", first: true, predicate: ["calendarPanel"], descendants: true }, { propertyName: "startInputEl", first: true, predicate: ["startInput"], descendants: true }, { propertyName: "endInputEl", first: true, predicate: ["endInput"], descendants: true }, { propertyName: "calendarComponent", first: true, predicate: ["calendar"], descendants: true }], ngImport: i0, template: "<!-- Trigger area -->\r\n<div #triggerEl class=\"fui-date-picker__trigger\" (click)=\"onTriggerClick()\">\r\n <!-- Start input -->\r\n <input\r\n #startInput\r\n class=\"fui-date-picker__input\"\r\n [id]=\"id\"\r\n [value]=\"startInputText()\"\r\n [placeholder]=\"getStartPlaceholder()\"\r\n [disabled]=\"disabled()\"\r\n [readonly]=\"readonly()\"\r\n [attr.aria-describedby]=\"_ariaDescribedby\"\r\n [attr.aria-required]=\"required()\"\r\n [attr.aria-invalid]=\"errorState()\"\r\n [attr.aria-expanded]=\"panelOpen()\"\r\n aria-haspopup=\"dialog\"\r\n aria-autocomplete=\"none\"\r\n role=\"combobox\"\r\n inputmode=\"numeric\"\r\n autocomplete=\"off\"\r\n (input)=\"onInput($event)\"\r\n (blur)=\"onBlur()\"\r\n (focus)=\"onInputFocus()\"\r\n (keydown)=\"onKeydown($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n\r\n <!-- Range separator + end input -->\r\n @if (range()) {\r\n <span class=\"fui-date-picker__range-separator\" aria-hidden=\"true\">{{ rangeSeparator() }}</span>\r\n <input\r\n #endInput\r\n class=\"fui-date-picker__input fui-date-picker__input--end\"\r\n [value]=\"endInputText()\"\r\n [placeholder]=\"getEndPlaceholder()\"\r\n [disabled]=\"disabled()\"\r\n [readonly]=\"readonly()\"\r\n [attr.aria-label]=\"intl.endDateAriaLabel\"\r\n [attr.aria-invalid]=\"errorState()\"\r\n inputmode=\"numeric\"\r\n autocomplete=\"off\"\r\n (input)=\"onEndInput($event)\"\r\n (blur)=\"onEndBlur()\"\r\n (focus)=\"onInputFocus()\"\r\n (keydown)=\"onEndKeydown($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n }\r\n\r\n <!-- Calendar toggle button \u2014 hidden in readOnly mode -->\r\n @if (!_readOnly()) {\r\n <button\r\n type=\"button\"\r\n class=\"fui-date-picker__toggle\"\r\n tabindex=\"-1\"\r\n [attr.aria-expanded]=\"panelOpen()\"\r\n [disabled]=\"disabled()\"\r\n aria-haspopup=\"dialog\"\r\n [attr.aria-label]=\"intl.openCalendarAriaLabel\"\r\n (click)=\"onToggleClick($event)\"\r\n >\r\n <fui-icon name=\"calendar-blank\" size=\"sm\" />\r\n </button>\r\n }\r\n</div>\r\n\r\n<!-- Calendar panel -->\r\n@if (panelOpen()) {\r\n <div\r\n #calendarPanel\r\n class=\"fui-date-picker__panel\"\r\n role=\"dialog\"\r\n aria-modal=\"true\"\r\n [attr.aria-label]=\"intl.calendarDialogAriaLabel\"\r\n >\r\n <fui-calendar\r\n #calendar\r\n [selected]=\"selectedDate()\"\r\n [rangeStart]=\"rangeStartDate()\"\r\n [rangeEnd]=\"rangeEndDate()\"\r\n [range]=\"range()\"\r\n [min]=\"min()\"\r\n [max]=\"max()\"\r\n [dateFilter]=\"dateFilter()\"\r\n [startAt]=\"startAt()\"\r\n [firstDayOfWeek]=\"firstDayOfWeek()\"\r\n [hoveredDate]=\"hoveredDate()\"\r\n (dateSelected)=\"onDateSelected($event)\"\r\n (dateHovered)=\"onDateHovered($event)\"\r\n />\r\n </div>\r\n}\r\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-motion-fade-out{transition:opacity var(--fui-duration-fast-01) var(--fui-ease-exit) 0ms}.fui-motion-slide-in-bottom{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition:transform,opacity var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-moderate-01) var(--fui-ease-entrance)}@keyframes fui-popover-enter{0%{opacity:0;transform:translateY(-14px)}60%{opacity:1}to{opacity:1;transform:translateY(0)}}.fui-date-picker{--fui-date-picker-font-size: var(--fui-font-size-02);--fui-date-picker-toggle-size: 1.5rem;display:inline-block;width:100%;position:relative}.fui-date-picker__trigger{width:100%;min-height:100%;display:flex;align-items:center;gap:var(--fui-spacing-01);cursor:pointer;background:transparent;border:none}.fui-date-picker__input{flex:1;min-width:0;border:none;outline:none;background:transparent;font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-02);font-weight:var(--fui-font-weight-regular);line-height:var(--fui-line-height-02);letter-spacing:var(--fui-letter-spacing-normal);color:var(--fui-text-primary);padding:0;cursor:text}.fui-date-picker__input::placeholder{color:var(--fui-text-disabled)}.fui-date-picker__input:disabled{cursor:not-allowed;opacity:.5}.fui-date-picker__range-separator{flex-shrink:0;color:var(--fui-text-secondary);font-size:var(--fui-font-size-02);-webkit-user-select:none;user-select:none}.fui-date-picker__toggle{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-date-picker__toggle:focus-visible{outline:2px solid var(--fui-primary);outline-offset:2px}.fui-date-picker__toggle{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:1.5rem;height:1.5rem;color:var(--fui-text-secondary);border-radius:var(--fui-border-radius-sm);transition:color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-date-picker__toggle:hover:not(:disabled){color:var(--fui-text-primary)}.fui-date-picker__toggle:disabled{color:var(--fui-text-disabled);cursor:not-allowed}.fui-date-picker--disabled{pointer-events:none}.fui-date-picker--disabled .fui-date-picker__trigger{cursor:not-allowed;opacity:.5}.fui-date-picker--readonly{pointer-events:none}.fui-date-picker--readonly .fui-date-picker__trigger{cursor:default;opacity:1}.fui-date-picker--readonly .fui-date-picker__input{color:var(--fui-text-primary)!important;-webkit-text-fill-color:var(--fui-text-primary)!important;cursor:default;opacity:1}.fui-date-picker--readonly .fui-date-picker__input:disabled{opacity:1;cursor:default}.fui-date-picker__panel{--fui-date-picker-panel-border-radius: var(--fui-border-radius-md);--fui-date-picker-panel-shadow: var(--fui-shadow-04);--fui-date-picker-panel-bg: var(--fui-surface-00);--fui-date-picker-panel-border-color: var(--fui-border-color);background:var(--fui-date-picker-panel-bg);border:1px solid var(--fui-date-picker-panel-border-color);border-radius:var(--fui-date-picker-panel-border-radius);box-shadow:var(--fui-date-picker-panel-shadow);padding:var(--fui-spacing-02);transform-origin:top center;animation:fui-popover-enter var(--fui-duration-moderate-01) var(--fui-ease-entrance) both;will-change:transform,opacity}.fui-date-picker-backdrop{background:transparent}.fui-date-picker-overlay-panel{z-index:var(--fui-z-popover, 1060)}@media(prefers-contrast:high){.fui-date-picker__panel{border-width:2px}}@media(prefers-reduced-motion:reduce){.fui-date-picker__panel{animation:none}}\n"], dependencies: [{ kind: "component", type: FuiIconComponent, selector: "fui-icon", inputs: ["name", "size", "weight", "color", "ariaLabel", "spin", "pulse"] }, { kind: "component", type: FuiCalendarComponent, selector: "fui-calendar", inputs: ["selected", "rangeStart", "rangeEnd", "range", "min", "max", "dateFilter", "startAt", "firstDayOfWeek", "hoveredDate"], outputs: ["dateSelected", "dateHovered", "monthChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1393
+ ], viewQueries: [{ propertyName: "triggerEl", first: true, predicate: ["triggerEl"], descendants: true, static: true }, { propertyName: "calendarPanel", first: true, predicate: ["calendarPanel"], descendants: true, static: true }, { propertyName: "startInputEl", first: true, predicate: ["startInput"], descendants: true, static: true }, { propertyName: "endInputEl", first: true, predicate: ["endInput"], descendants: true }, { propertyName: "_fuiStartInput", first: true, predicate: ["startInput"], descendants: true, read: FuiInputDirective, static: true }, { propertyName: "_fuiEndInput", first: true, predicate: ["endInput"], descendants: true, read: FuiInputDirective }, { propertyName: "calendarComponent", first: true, predicate: ["calendar"], descendants: true }], hostDirectives: [{ directive: i1.FuiPopupOverlayDirective, inputs: ["positions", "positions", "panelClass", "panelClass", "backdropClass", "backdropClass", "scrollStrategy", "scrollStrategy", "minWidthFromTrigger", "minWidthFromTrigger"], outputs: ["openedChange", "openedChange", "escapeKey", "escapeKey"] }, { directive: i1.FuiFormControlSyncDirective }], ngImport: i0, template: "<!-- Trigger area -->\r\n<div #triggerEl class=\"fui-date-picker__trigger\" (click)=\"onTriggerClick()\">\r\n <!-- Start input -->\r\n <input\r\n #startInput\r\n fuiInput\r\n class=\"fui-date-picker__input\"\r\n [id]=\"id\"\r\n [value]=\"startInputText()\"\r\n [placeholder]=\"getStartPlaceholder()\"\r\n [disabled]=\"disabled()\"\r\n [readonly]=\"readonly()\"\r\n [attr.aria-expanded]=\"panelOpen()\"\r\n aria-haspopup=\"dialog\"\r\n aria-autocomplete=\"none\"\r\n role=\"combobox\"\r\n inputmode=\"numeric\"\r\n autocomplete=\"off\"\r\n (input)=\"onInput($event)\"\r\n (blur)=\"onBlur()\"\r\n (focus)=\"onInputFocus()\"\r\n (keydown)=\"onKeydown($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n\r\n <!-- Range separator + end input -->\r\n @if (range()) {\r\n <span class=\"fui-date-picker__range-separator\" aria-hidden=\"true\">{{ rangeSeparator() }}</span>\r\n <input\r\n #endInput\r\n fuiInput\r\n class=\"fui-date-picker__input fui-date-picker__input--end\"\r\n [value]=\"endInputText()\"\r\n [placeholder]=\"getEndPlaceholder()\"\r\n [disabled]=\"disabled()\"\r\n [readonly]=\"readonly()\"\r\n [attr.aria-label]=\"intl.endDateAriaLabel\"\r\n inputmode=\"numeric\"\r\n autocomplete=\"off\"\r\n (input)=\"onEndInput($event)\"\r\n (blur)=\"onEndBlur()\"\r\n (focus)=\"onInputFocus()\"\r\n (keydown)=\"onEndKeydown($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n }\r\n\r\n <!-- Calendar toggle button \u2014 hidden when disabled or readOnly -->\r\n @if (!disabled() && !readonly()) {\r\n <button\r\n type=\"button\"\r\n class=\"fui-date-picker__toggle\"\r\n tabindex=\"-1\"\r\n [attr.aria-expanded]=\"panelOpen()\"\r\n aria-haspopup=\"dialog\"\r\n [attr.aria-label]=\"intl.openCalendarAriaLabel\"\r\n (click)=\"onToggleClick($event)\"\r\n >\r\n <fui-icon name=\"calendar-blank\" size=\"sm\" />\r\n </button>\r\n }\r\n</div>\r\n\r\n<!-- Calendar panel (always rendered; hidden when closed so #calendarPanel ViewChild is always available) -->\r\n<div\r\n #calendarPanel\r\n [hidden]=\"!panelOpen()\"\r\n class=\"fui-date-picker__panel\"\r\n [class.fui-date-picker__panel--with-presets]=\"presets().length > 0\"\r\n role=\"dialog\"\r\n aria-modal=\"true\"\r\n [attr.aria-label]=\"intl.calendarDialogAriaLabel\"\r\n>\r\n @if (presets().length > 0) {\r\n <ul class=\"fui-date-picker__presets\" role=\"listbox\" [attr.aria-label]=\"intl.presetsAriaLabel\">\r\n @for (preset of presets(); track preset.label) {\r\n <li role=\"option\" class=\"fui-date-picker__preset-item\">\r\n <button type=\"button\" class=\"fui-date-picker__preset-btn\" (click)=\"_onPresetClick(preset)\">\r\n {{ preset.label }}\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n }\r\n <fui-calendar\r\n #calendar\r\n [selected]=\"selectedDate()\"\r\n [rangeStart]=\"rangeStartDate()\"\r\n [rangeEnd]=\"rangeEndDate()\"\r\n [range]=\"range()\"\r\n [min]=\"min()\"\r\n [max]=\"max()\"\r\n [dateFilter]=\"dateFilter()\"\r\n [startAt]=\"startAt()\"\r\n [firstDayOfWeek]=\"firstDayOfWeek()\"\r\n [hoveredDate]=\"hoveredDate()\"\r\n (dateSelected)=\"onDateSelected($event)\"\r\n (dateHovered)=\"onDateHovered($event)\"\r\n />\r\n</div>\r\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition-property:opacity;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-out);transition-delay:0ms}.fui-motion-fade-out{transition-property:opacity;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-in);transition-delay:0ms}.fui-motion-slide-in-bottom{transition-property:transform;transition-duration:var(--fui-duration-base);transition-timing-function:var(--fui-ease-out);transition-delay:0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition-property:transform;transition-duration:var(--fui-duration-base);transition-timing-function:var(--fui-ease-out);transition-delay:0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition-property:transform,opacity;transition-duration:var(--fui-duration-base);transition-timing-function:var(--fui-ease-out);transition-delay:0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-base) var(--fui-ease-out)}@keyframes fui-popover-enter{0%{opacity:0;transform:translateY(-14px)}60%{opacity:1}to{opacity:1;transform:translateY(0)}}.fui-date-picker{--fui-date-picker-font-size: var(--fui-text-base);--fui-date-picker-toggle-size: 1.5rem;display:inline-block;width:100%;position:relative}.fui-date-picker__trigger{width:100%;min-height:100%;display:flex;align-items:center;gap:var(--fui-spacing-1);cursor:pointer;background:transparent;border:none}.fui-date-picker__input{flex:1;min-width:0;border:none;outline:none;background:transparent;font-family:var(--fui-font-sans);font-size:var(--fui-text-base);font-weight:var(--fui-weight-regular);line-height:var(--fui-leading-normal);letter-spacing:var(--fui-tracking-normal);color:var(--fui-text-primary);padding:0;cursor:text}.fui-date-picker__input::placeholder{color:var(--fui-text-disabled)}.fui-date-picker__input:disabled{cursor:not-allowed;opacity:.5}.fui-date-picker__range-separator{flex-shrink:0;color:var(--fui-text-secondary);font-size:var(--fui-text-base);-webkit-user-select:none;user-select:none}.fui-date-picker__toggle{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-date-picker__toggle:focus-visible{outline:2px solid var(--fui-primary-10)}.fui-date-picker__toggle{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:1.5rem;height:1.5rem;color:var(--fui-text-secondary);border-radius:var(--fui-radius-sm);transition-property:color;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-in-out);transition-delay:0ms}.fui-date-picker__toggle:hover:not(:disabled){color:var(--fui-text-primary)}.fui-date-picker__toggle:disabled{color:var(--fui-text-disabled);cursor:not-allowed}.fui-date-picker--disabled{pointer-events:none}.fui-date-picker--disabled .fui-date-picker__trigger{cursor:not-allowed;opacity:.5}.fui-date-picker .fui-date-picker__panel{display:none}.fui-date-picker--readonly{pointer-events:none}.fui-date-picker--readonly .fui-date-picker__trigger{cursor:default;opacity:1}.fui-date-picker--readonly .fui-date-picker__input{color:var(--fui-text-primary)!important;-webkit-text-fill-color:var(--fui-text-primary)!important;cursor:default;opacity:1}.fui-date-picker--readonly .fui-date-picker__input:disabled{opacity:1;cursor:default}.fui-date-picker__panel{--fui-date-picker-panel-border-radius: var(--fui-radius-md);--fui-date-picker-panel-shadow: var(--fui-shadow-lg);--fui-date-picker-panel-bg: var(--fui-bg-default);--fui-date-picker-panel-border-color: var(--fui-border-default);background:var(--fui-date-picker-panel-bg);border:1px solid var(--fui-date-picker-panel-border-color);border-radius:var(--fui-date-picker-panel-border-radius);box-shadow:var(--fui-date-picker-panel-shadow);padding:var(--fui-spacing-2);transform-origin:top center;animation:fui-popover-enter var(--fui-duration-base) var(--fui-ease-out) both;will-change:transform,opacity}.fui-date-picker__panel--with-presets{display:flex;align-items:stretch;gap:var(--fui-spacing-2)}.fui-date-picker__presets{list-style:none;margin:0;padding:var(--fui-spacing-1);display:flex;flex-direction:column;gap:2px;border-right:1px solid var(--fui-border-default);padding-right:var(--fui-spacing-2);min-width:9rem}.fui-date-picker__preset-item{margin:0;padding:0}.fui-date-picker__preset-btn{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-date-picker__preset-btn{width:100%;text-align:left;padding:var(--fui-spacing-2) var(--fui-spacing-4);border-radius:var(--fui-radius-sm);font-family:var(--fui-font-sans);font-size:var(--fui-text-base);color:var(--fui-text-primary);cursor:pointer;transition-property:background-color;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-in-out);transition-delay:0ms}.fui-date-picker__preset-btn:hover{background-color:var(--fui-bg-subtle)}.fui-date-picker__preset-btn:focus-visible{outline:2px solid var(--fui-primary-10)}.fui-date-picker-backdrop{background:transparent}@media(prefers-contrast:high){.fui-date-picker__panel{border-width:2px}}@media(prefers-reduced-motion:reduce){.fui-date-picker__panel{animation:none}}\n"], dependencies: [{ kind: "directive", type: FuiInputDirective, selector: "input[fuiInput], textarea[fuiInput], select[fuiInput]", inputs: ["type", "placeholder", "readonly", "maxlength", "minlength", "pattern", "errorStateMatcher", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: FuiIconComponent, selector: "fui-icon", inputs: ["name", "size", "weight", "color", "ariaLabel", "spin", "pulse"] }, { kind: "component", type: FuiCalendarComponent, selector: "fui-calendar", inputs: ["selected", "rangeStart", "rangeEnd", "range", "min", "max", "dateFilter", "startAt", "firstDayOfWeek", "hoveredDate"], outputs: ["dateSelected", "dateHovered", "monthChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1328
1394
  }
1329
1395
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiDatePickerComponent, decorators: [{
1330
1396
  type: Component,
1331
- args: [{ selector: 'fui-date-picker', standalone: true, imports: [FuiIconComponent, FuiCalendarComponent], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
1397
+ args: [{ selector: 'fui-date-picker', standalone: true, imports: [FuiInputDirective, FuiIconComponent, FuiCalendarComponent], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, hostDirectives: [
1398
+ {
1399
+ directive: FuiPopupOverlayDirective,
1400
+ inputs: ['positions', 'panelClass', 'backdropClass', 'scrollStrategy', 'minWidthFromTrigger'],
1401
+ outputs: ['openedChange', 'escapeKey'],
1402
+ },
1403
+ FuiFormControlSyncDirective,
1404
+ ], host: {
1332
1405
  class: 'fui-date-picker',
1333
1406
  '[attr.id]': 'id',
1334
1407
  '[class.fui-date-picker--open]': 'panelOpen()',
@@ -1336,7 +1409,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
1336
1409
  '[class.fui-date-picker--range]': 'range()',
1337
1410
  '[class.fui-date-picker--focused]': 'focused()',
1338
1411
  '[class.fui-date-picker--error]': 'errorState()',
1339
- '[class.fui-date-picker--readonly]': '_readOnly()',
1412
+ '[class.fui-date-picker--readonly]': 'readonly()',
1340
1413
  }, providers: [
1341
1414
  {
1342
1415
  provide: NG_VALUE_ACCESSOR,
@@ -1352,19 +1425,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
1352
1425
  provide: FUI_FORM_FIELD_CONTROL,
1353
1426
  useExisting: FuiDatePickerComponent,
1354
1427
  },
1355
- ], template: "<!-- Trigger area -->\r\n<div #triggerEl class=\"fui-date-picker__trigger\" (click)=\"onTriggerClick()\">\r\n <!-- Start input -->\r\n <input\r\n #startInput\r\n class=\"fui-date-picker__input\"\r\n [id]=\"id\"\r\n [value]=\"startInputText()\"\r\n [placeholder]=\"getStartPlaceholder()\"\r\n [disabled]=\"disabled()\"\r\n [readonly]=\"readonly()\"\r\n [attr.aria-describedby]=\"_ariaDescribedby\"\r\n [attr.aria-required]=\"required()\"\r\n [attr.aria-invalid]=\"errorState()\"\r\n [attr.aria-expanded]=\"panelOpen()\"\r\n aria-haspopup=\"dialog\"\r\n aria-autocomplete=\"none\"\r\n role=\"combobox\"\r\n inputmode=\"numeric\"\r\n autocomplete=\"off\"\r\n (input)=\"onInput($event)\"\r\n (blur)=\"onBlur()\"\r\n (focus)=\"onInputFocus()\"\r\n (keydown)=\"onKeydown($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n\r\n <!-- Range separator + end input -->\r\n @if (range()) {\r\n <span class=\"fui-date-picker__range-separator\" aria-hidden=\"true\">{{ rangeSeparator() }}</span>\r\n <input\r\n #endInput\r\n class=\"fui-date-picker__input fui-date-picker__input--end\"\r\n [value]=\"endInputText()\"\r\n [placeholder]=\"getEndPlaceholder()\"\r\n [disabled]=\"disabled()\"\r\n [readonly]=\"readonly()\"\r\n [attr.aria-label]=\"intl.endDateAriaLabel\"\r\n [attr.aria-invalid]=\"errorState()\"\r\n inputmode=\"numeric\"\r\n autocomplete=\"off\"\r\n (input)=\"onEndInput($event)\"\r\n (blur)=\"onEndBlur()\"\r\n (focus)=\"onInputFocus()\"\r\n (keydown)=\"onEndKeydown($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n }\r\n\r\n <!-- Calendar toggle button \u2014 hidden in readOnly mode -->\r\n @if (!_readOnly()) {\r\n <button\r\n type=\"button\"\r\n class=\"fui-date-picker__toggle\"\r\n tabindex=\"-1\"\r\n [attr.aria-expanded]=\"panelOpen()\"\r\n [disabled]=\"disabled()\"\r\n aria-haspopup=\"dialog\"\r\n [attr.aria-label]=\"intl.openCalendarAriaLabel\"\r\n (click)=\"onToggleClick($event)\"\r\n >\r\n <fui-icon name=\"calendar-blank\" size=\"sm\" />\r\n </button>\r\n }\r\n</div>\r\n\r\n<!-- Calendar panel -->\r\n@if (panelOpen()) {\r\n <div\r\n #calendarPanel\r\n class=\"fui-date-picker__panel\"\r\n role=\"dialog\"\r\n aria-modal=\"true\"\r\n [attr.aria-label]=\"intl.calendarDialogAriaLabel\"\r\n >\r\n <fui-calendar\r\n #calendar\r\n [selected]=\"selectedDate()\"\r\n [rangeStart]=\"rangeStartDate()\"\r\n [rangeEnd]=\"rangeEndDate()\"\r\n [range]=\"range()\"\r\n [min]=\"min()\"\r\n [max]=\"max()\"\r\n [dateFilter]=\"dateFilter()\"\r\n [startAt]=\"startAt()\"\r\n [firstDayOfWeek]=\"firstDayOfWeek()\"\r\n [hoveredDate]=\"hoveredDate()\"\r\n (dateSelected)=\"onDateSelected($event)\"\r\n (dateHovered)=\"onDateHovered($event)\"\r\n />\r\n </div>\r\n}\r\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-motion-fade-out{transition:opacity var(--fui-duration-fast-01) var(--fui-ease-exit) 0ms}.fui-motion-slide-in-bottom{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition:transform,opacity var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-moderate-01) var(--fui-ease-entrance)}@keyframes fui-popover-enter{0%{opacity:0;transform:translateY(-14px)}60%{opacity:1}to{opacity:1;transform:translateY(0)}}.fui-date-picker{--fui-date-picker-font-size: var(--fui-font-size-02);--fui-date-picker-toggle-size: 1.5rem;display:inline-block;width:100%;position:relative}.fui-date-picker__trigger{width:100%;min-height:100%;display:flex;align-items:center;gap:var(--fui-spacing-01);cursor:pointer;background:transparent;border:none}.fui-date-picker__input{flex:1;min-width:0;border:none;outline:none;background:transparent;font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-02);font-weight:var(--fui-font-weight-regular);line-height:var(--fui-line-height-02);letter-spacing:var(--fui-letter-spacing-normal);color:var(--fui-text-primary);padding:0;cursor:text}.fui-date-picker__input::placeholder{color:var(--fui-text-disabled)}.fui-date-picker__input:disabled{cursor:not-allowed;opacity:.5}.fui-date-picker__range-separator{flex-shrink:0;color:var(--fui-text-secondary);font-size:var(--fui-font-size-02);-webkit-user-select:none;user-select:none}.fui-date-picker__toggle{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-date-picker__toggle:focus-visible{outline:2px solid var(--fui-primary);outline-offset:2px}.fui-date-picker__toggle{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:1.5rem;height:1.5rem;color:var(--fui-text-secondary);border-radius:var(--fui-border-radius-sm);transition:color var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}.fui-date-picker__toggle:hover:not(:disabled){color:var(--fui-text-primary)}.fui-date-picker__toggle:disabled{color:var(--fui-text-disabled);cursor:not-allowed}.fui-date-picker--disabled{pointer-events:none}.fui-date-picker--disabled .fui-date-picker__trigger{cursor:not-allowed;opacity:.5}.fui-date-picker--readonly{pointer-events:none}.fui-date-picker--readonly .fui-date-picker__trigger{cursor:default;opacity:1}.fui-date-picker--readonly .fui-date-picker__input{color:var(--fui-text-primary)!important;-webkit-text-fill-color:var(--fui-text-primary)!important;cursor:default;opacity:1}.fui-date-picker--readonly .fui-date-picker__input:disabled{opacity:1;cursor:default}.fui-date-picker__panel{--fui-date-picker-panel-border-radius: var(--fui-border-radius-md);--fui-date-picker-panel-shadow: var(--fui-shadow-04);--fui-date-picker-panel-bg: var(--fui-surface-00);--fui-date-picker-panel-border-color: var(--fui-border-color);background:var(--fui-date-picker-panel-bg);border:1px solid var(--fui-date-picker-panel-border-color);border-radius:var(--fui-date-picker-panel-border-radius);box-shadow:var(--fui-date-picker-panel-shadow);padding:var(--fui-spacing-02);transform-origin:top center;animation:fui-popover-enter var(--fui-duration-moderate-01) var(--fui-ease-entrance) both;will-change:transform,opacity}.fui-date-picker-backdrop{background:transparent}.fui-date-picker-overlay-panel{z-index:var(--fui-z-popover, 1060)}@media(prefers-contrast:high){.fui-date-picker__panel{border-width:2px}}@media(prefers-reduced-motion:reduce){.fui-date-picker__panel{animation:none}}\n"] }]
1356
- }], ctorParameters: () => [], propDecorators: { placeholderInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], range: [{ type: i0.Input, args: [{ isSignal: true, alias: "range", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], startAt: [{ type: i0.Input, args: [{ isSignal: true, alias: "startAt", required: false }] }], firstDayOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstDayOfWeek", required: false }] }], rangeSeparator: [{ type: i0.Input, args: [{ isSignal: true, alias: "rangeSeparator", required: false }] }], errorStateMatcher: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorStateMatcher", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], dateChange: [{ type: i0.Output, args: ["dateChange"] }], openedChange: [{ type: i0.Output, args: ["openedChange"] }], triggerEl: [{
1428
+ ], template: "<!-- Trigger area -->\r\n<div #triggerEl class=\"fui-date-picker__trigger\" (click)=\"onTriggerClick()\">\r\n <!-- Start input -->\r\n <input\r\n #startInput\r\n fuiInput\r\n class=\"fui-date-picker__input\"\r\n [id]=\"id\"\r\n [value]=\"startInputText()\"\r\n [placeholder]=\"getStartPlaceholder()\"\r\n [disabled]=\"disabled()\"\r\n [readonly]=\"readonly()\"\r\n [attr.aria-expanded]=\"panelOpen()\"\r\n aria-haspopup=\"dialog\"\r\n aria-autocomplete=\"none\"\r\n role=\"combobox\"\r\n inputmode=\"numeric\"\r\n autocomplete=\"off\"\r\n (input)=\"onInput($event)\"\r\n (blur)=\"onBlur()\"\r\n (focus)=\"onInputFocus()\"\r\n (keydown)=\"onKeydown($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n\r\n <!-- Range separator + end input -->\r\n @if (range()) {\r\n <span class=\"fui-date-picker__range-separator\" aria-hidden=\"true\">{{ rangeSeparator() }}</span>\r\n <input\r\n #endInput\r\n fuiInput\r\n class=\"fui-date-picker__input fui-date-picker__input--end\"\r\n [value]=\"endInputText()\"\r\n [placeholder]=\"getEndPlaceholder()\"\r\n [disabled]=\"disabled()\"\r\n [readonly]=\"readonly()\"\r\n [attr.aria-label]=\"intl.endDateAriaLabel\"\r\n inputmode=\"numeric\"\r\n autocomplete=\"off\"\r\n (input)=\"onEndInput($event)\"\r\n (blur)=\"onEndBlur()\"\r\n (focus)=\"onInputFocus()\"\r\n (keydown)=\"onEndKeydown($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n }\r\n\r\n <!-- Calendar toggle button \u2014 hidden when disabled or readOnly -->\r\n @if (!disabled() && !readonly()) {\r\n <button\r\n type=\"button\"\r\n class=\"fui-date-picker__toggle\"\r\n tabindex=\"-1\"\r\n [attr.aria-expanded]=\"panelOpen()\"\r\n aria-haspopup=\"dialog\"\r\n [attr.aria-label]=\"intl.openCalendarAriaLabel\"\r\n (click)=\"onToggleClick($event)\"\r\n >\r\n <fui-icon name=\"calendar-blank\" size=\"sm\" />\r\n </button>\r\n }\r\n</div>\r\n\r\n<!-- Calendar panel (always rendered; hidden when closed so #calendarPanel ViewChild is always available) -->\r\n<div\r\n #calendarPanel\r\n [hidden]=\"!panelOpen()\"\r\n class=\"fui-date-picker__panel\"\r\n [class.fui-date-picker__panel--with-presets]=\"presets().length > 0\"\r\n role=\"dialog\"\r\n aria-modal=\"true\"\r\n [attr.aria-label]=\"intl.calendarDialogAriaLabel\"\r\n>\r\n @if (presets().length > 0) {\r\n <ul class=\"fui-date-picker__presets\" role=\"listbox\" [attr.aria-label]=\"intl.presetsAriaLabel\">\r\n @for (preset of presets(); track preset.label) {\r\n <li role=\"option\" class=\"fui-date-picker__preset-item\">\r\n <button type=\"button\" class=\"fui-date-picker__preset-btn\" (click)=\"_onPresetClick(preset)\">\r\n {{ preset.label }}\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n }\r\n <fui-calendar\r\n #calendar\r\n [selected]=\"selectedDate()\"\r\n [rangeStart]=\"rangeStartDate()\"\r\n [rangeEnd]=\"rangeEndDate()\"\r\n [range]=\"range()\"\r\n [min]=\"min()\"\r\n [max]=\"max()\"\r\n [dateFilter]=\"dateFilter()\"\r\n [startAt]=\"startAt()\"\r\n [firstDayOfWeek]=\"firstDayOfWeek()\"\r\n [hoveredDate]=\"hoveredDate()\"\r\n (dateSelected)=\"onDateSelected($event)\"\r\n (dateHovered)=\"onDateHovered($event)\"\r\n />\r\n</div>\r\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition-property:opacity;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-out);transition-delay:0ms}.fui-motion-fade-out{transition-property:opacity;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-in);transition-delay:0ms}.fui-motion-slide-in-bottom{transition-property:transform;transition-duration:var(--fui-duration-base);transition-timing-function:var(--fui-ease-out);transition-delay:0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition-property:transform;transition-duration:var(--fui-duration-base);transition-timing-function:var(--fui-ease-out);transition-delay:0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition-property:transform,opacity;transition-duration:var(--fui-duration-base);transition-timing-function:var(--fui-ease-out);transition-delay:0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-base) var(--fui-ease-out)}@keyframes fui-popover-enter{0%{opacity:0;transform:translateY(-14px)}60%{opacity:1}to{opacity:1;transform:translateY(0)}}.fui-date-picker{--fui-date-picker-font-size: var(--fui-text-base);--fui-date-picker-toggle-size: 1.5rem;display:inline-block;width:100%;position:relative}.fui-date-picker__trigger{width:100%;min-height:100%;display:flex;align-items:center;gap:var(--fui-spacing-1);cursor:pointer;background:transparent;border:none}.fui-date-picker__input{flex:1;min-width:0;border:none;outline:none;background:transparent;font-family:var(--fui-font-sans);font-size:var(--fui-text-base);font-weight:var(--fui-weight-regular);line-height:var(--fui-leading-normal);letter-spacing:var(--fui-tracking-normal);color:var(--fui-text-primary);padding:0;cursor:text}.fui-date-picker__input::placeholder{color:var(--fui-text-disabled)}.fui-date-picker__input:disabled{cursor:not-allowed;opacity:.5}.fui-date-picker__range-separator{flex-shrink:0;color:var(--fui-text-secondary);font-size:var(--fui-text-base);-webkit-user-select:none;user-select:none}.fui-date-picker__toggle{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-date-picker__toggle:focus-visible{outline:2px solid var(--fui-primary-10)}.fui-date-picker__toggle{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:1.5rem;height:1.5rem;color:var(--fui-text-secondary);border-radius:var(--fui-radius-sm);transition-property:color;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-in-out);transition-delay:0ms}.fui-date-picker__toggle:hover:not(:disabled){color:var(--fui-text-primary)}.fui-date-picker__toggle:disabled{color:var(--fui-text-disabled);cursor:not-allowed}.fui-date-picker--disabled{pointer-events:none}.fui-date-picker--disabled .fui-date-picker__trigger{cursor:not-allowed;opacity:.5}.fui-date-picker .fui-date-picker__panel{display:none}.fui-date-picker--readonly{pointer-events:none}.fui-date-picker--readonly .fui-date-picker__trigger{cursor:default;opacity:1}.fui-date-picker--readonly .fui-date-picker__input{color:var(--fui-text-primary)!important;-webkit-text-fill-color:var(--fui-text-primary)!important;cursor:default;opacity:1}.fui-date-picker--readonly .fui-date-picker__input:disabled{opacity:1;cursor:default}.fui-date-picker__panel{--fui-date-picker-panel-border-radius: var(--fui-radius-md);--fui-date-picker-panel-shadow: var(--fui-shadow-lg);--fui-date-picker-panel-bg: var(--fui-bg-default);--fui-date-picker-panel-border-color: var(--fui-border-default);background:var(--fui-date-picker-panel-bg);border:1px solid var(--fui-date-picker-panel-border-color);border-radius:var(--fui-date-picker-panel-border-radius);box-shadow:var(--fui-date-picker-panel-shadow);padding:var(--fui-spacing-2);transform-origin:top center;animation:fui-popover-enter var(--fui-duration-base) var(--fui-ease-out) both;will-change:transform,opacity}.fui-date-picker__panel--with-presets{display:flex;align-items:stretch;gap:var(--fui-spacing-2)}.fui-date-picker__presets{list-style:none;margin:0;padding:var(--fui-spacing-1);display:flex;flex-direction:column;gap:2px;border-right:1px solid var(--fui-border-default);padding-right:var(--fui-spacing-2);min-width:9rem}.fui-date-picker__preset-item{margin:0;padding:0}.fui-date-picker__preset-btn{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;outline:none}.fui-date-picker__preset-btn{width:100%;text-align:left;padding:var(--fui-spacing-2) var(--fui-spacing-4);border-radius:var(--fui-radius-sm);font-family:var(--fui-font-sans);font-size:var(--fui-text-base);color:var(--fui-text-primary);cursor:pointer;transition-property:background-color;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-in-out);transition-delay:0ms}.fui-date-picker__preset-btn:hover{background-color:var(--fui-bg-subtle)}.fui-date-picker__preset-btn:focus-visible{outline:2px solid var(--fui-primary-10)}.fui-date-picker-backdrop{background:transparent}@media(prefers-contrast:high){.fui-date-picker__panel{border-width:2px}}@media(prefers-reduced-motion:reduce){.fui-date-picker__panel{animation:none}}\n"] }]
1429
+ }], ctorParameters: () => [], propDecorators: { placeholderInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonlyInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], range: [{ type: i0.Input, args: [{ isSignal: true, alias: "range", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], startAt: [{ type: i0.Input, args: [{ isSignal: true, alias: "startAt", required: false }] }], firstDayOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstDayOfWeek", required: false }] }], rangeSeparator: [{ type: i0.Input, args: [{ isSignal: true, alias: "rangeSeparator", required: false }] }], errorStateMatcher: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorStateMatcher", required: false }] }], presets: [{ type: i0.Input, args: [{ isSignal: true, alias: "presets", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], dateChange: [{ type: i0.Output, args: ["dateChange"] }], openedChange: [{ type: i0.Output, args: ["openedChange"] }], triggerEl: [{
1357
1430
  type: ViewChild,
1358
- args: ['triggerEl', { static: false }]
1431
+ args: ['triggerEl', { static: true }]
1359
1432
  }], calendarPanel: [{
1360
1433
  type: ViewChild,
1361
- args: ['calendarPanel', { static: false }]
1434
+ args: ['calendarPanel', { static: true }]
1362
1435
  }], startInputEl: [{
1363
1436
  type: ViewChild,
1364
- args: ['startInput', { static: false }]
1437
+ args: ['startInput', { static: true }]
1365
1438
  }], endInputEl: [{
1366
1439
  type: ViewChild,
1367
1440
  args: ['endInput', { static: false }]
1441
+ }], _fuiStartInput: [{
1442
+ type: ViewChild,
1443
+ args: ['startInput', { static: true, read: FuiInputDirective }]
1444
+ }], _fuiEndInput: [{
1445
+ type: ViewChild,
1446
+ args: ['endInput', { static: false, read: FuiInputDirective }]
1368
1447
  }], calendarComponent: [{
1369
1448
  type: ViewChild,
1370
1449
  args: ['calendar', { static: false }]
@@ -1374,5 +1453,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
1374
1453
  * Generated bundle index. Do not edit.
1375
1454
  */
1376
1455
 
1377
- export { DEFAULT_DATE_FORMAT, FuiCalendarComponent, FuiCalendarIntl, FuiDatePickerComponent, FuiDatePickerIntl, RANGE_SEPARATOR, applyDateMask, buildCalendarGrid, formatDate, getDaysInMonth, getMonthLabel, getShortMonthName, getWeekdayLabels, isAfter, isBefore, isBetween, isDateInRange, isSameDay, normalizeDate, parseDate };
1456
+ export { DEFAULT_DATE_FORMAT, FuiCalendarComponent, FuiCalendarIntl, FuiDatePickerComponent, FuiDatePickerIntl, RANGE_SEPARATOR, applyDateMask, buildCalendarGrid, buildDefaultDateRangePresets, formatDate, getDaysInMonth, getMonthLabel, getShortMonthName, getWeekdayLabels, isAfter, isBefore, isBetween, isDateInRange, isSameDay, normalizeDate, parseDate };
1378
1457
  //# sourceMappingURL=raintonic-formaui-components-date-picker.mjs.map