@siemens/element-ng 47.2.0 → 47.4.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 (339) hide show
  1. package/README.md +18 -6
  2. package/autocomplete/index.d.ts +8 -0
  3. package/autocomplete/package.json +3 -0
  4. package/autocomplete/si-autocomplete-listbox.directive.d.ts +31 -0
  5. package/autocomplete/si-autocomplete-option.directive.d.ts +31 -0
  6. package/autocomplete/si-autocomplete.directive.d.ts +14 -0
  7. package/autocomplete/si-autocomplete.model.d.ts +7 -0
  8. package/autocomplete/si-autocomplete.module.d.ts +9 -0
  9. package/badge/index.d.ts +5 -0
  10. package/badge/package.json +3 -0
  11. package/badge/si-badge.component.d.ts +17 -0
  12. package/breadcrumb/breadcrumb-item.model.d.ts +36 -0
  13. package/breadcrumb/index.d.ts +7 -0
  14. package/breadcrumb/package.json +3 -0
  15. package/breadcrumb/si-breadcrumb-item-template.directive.d.ts +10 -0
  16. package/breadcrumb/si-breadcrumb.component.d.ts +46 -0
  17. package/breadcrumb/si-breadcrumb.module.d.ts +7 -0
  18. package/card/index.d.ts +6 -0
  19. package/card/package.json +3 -0
  20. package/card/si-card.component.d.ts +79 -0
  21. package/card/si-card.module.d.ts +7 -0
  22. package/circle-status/index.d.ts +6 -0
  23. package/circle-status/package.json +3 -0
  24. package/circle-status/si-circle-status.component.d.ts +66 -0
  25. package/circle-status/si-circle-status.module.d.ts +7 -0
  26. package/column-selection-dialog/column-selection-editor/si-column-selection-editor.component.d.ts +23 -0
  27. package/column-selection-dialog/index.d.ts +6 -0
  28. package/column-selection-dialog/package.json +3 -0
  29. package/column-selection-dialog/si-column-selection-dialog.component.d.ts +114 -0
  30. package/column-selection-dialog/si-column-selection-dialog.service.d.ts +20 -0
  31. package/column-selection-dialog/si-column-selection-dialog.types.d.ts +68 -0
  32. package/common/models/status-type.model.d.ts +2 -2
  33. package/content-action-bar/index.d.ts +7 -0
  34. package/content-action-bar/package.json +3 -0
  35. package/content-action-bar/si-content-action-bar-toggle.component.d.ts +6 -0
  36. package/content-action-bar/si-content-action-bar.component.d.ts +72 -0
  37. package/content-action-bar/si-content-action-bar.model.d.ts +9 -0
  38. package/content-action-bar/si-content-action-bar.module.d.ts +7 -0
  39. package/date-range-filter/index.d.ts +8 -0
  40. package/date-range-filter/package.json +3 -0
  41. package/date-range-filter/si-date-range-calculation.service.d.ts +33 -0
  42. package/date-range-filter/si-date-range-filter.component.d.ts +248 -0
  43. package/date-range-filter/si-date-range-filter.module.d.ts +7 -0
  44. package/date-range-filter/si-date-range-filter.types.d.ts +40 -0
  45. package/date-range-filter/si-relative-date.component.d.ts +31 -0
  46. package/datepicker/components/si-calendar-body.component.d.ts +137 -0
  47. package/datepicker/components/si-calendar-date-cell.directive.d.ts +16 -0
  48. package/datepicker/components/si-calendar-direction-button.component.d.ts +18 -0
  49. package/datepicker/components/si-compare-adapter.d.ts +37 -0
  50. package/datepicker/components/si-day-selection.component.d.ts +76 -0
  51. package/datepicker/components/si-initial-focus.component.d.ts +74 -0
  52. package/datepicker/components/si-month-selection.component.d.ts +62 -0
  53. package/datepicker/components/si-year-selection.component.d.ts +65 -0
  54. package/datepicker/date-time-helper.d.ts +302 -0
  55. package/datepicker/index.d.ts +15 -0
  56. package/datepicker/package.json +3 -0
  57. package/datepicker/si-calendar-button.component.d.ts +49 -0
  58. package/datepicker/si-date-input.directive.d.ts +114 -0
  59. package/datepicker/si-date-range.component.d.ts +150 -0
  60. package/datepicker/si-datepicker-overlay.component.d.ts +82 -0
  61. package/datepicker/si-datepicker-overlay.directive.d.ts +104 -0
  62. package/datepicker/si-datepicker.component.d.ts +228 -0
  63. package/datepicker/si-datepicker.directive.d.ts +62 -0
  64. package/datepicker/si-datepicker.model.d.ts +129 -0
  65. package/datepicker/si-datepicker.module.d.ts +12 -0
  66. package/datepicker/si-timepicker.component.d.ts +214 -0
  67. package/electron-titlebar/electron.helpers.d.ts +5 -0
  68. package/electron-titlebar/index.d.ts +7 -0
  69. package/electron-titlebar/package.json +3 -0
  70. package/electron-titlebar/si-electron-titlebar.component.d.ts +72 -0
  71. package/electron-titlebar/si-electron-titlebar.module.d.ts +7 -0
  72. package/fesm2022/siemens-element-ng-application-header.mjs +2 -2
  73. package/fesm2022/siemens-element-ng-application-header.mjs.map +1 -1
  74. package/fesm2022/siemens-element-ng-autocomplete.mjs +235 -0
  75. package/fesm2022/siemens-element-ng-autocomplete.mjs.map +1 -0
  76. package/fesm2022/siemens-element-ng-badge.mjs +59 -0
  77. package/fesm2022/siemens-element-ng-badge.mjs.map +1 -0
  78. package/fesm2022/siemens-element-ng-breadcrumb.mjs +302 -0
  79. package/fesm2022/siemens-element-ng-breadcrumb.mjs.map +1 -0
  80. package/fesm2022/siemens-element-ng-card.mjs +122 -0
  81. package/fesm2022/siemens-element-ng-card.mjs.map +1 -0
  82. package/fesm2022/siemens-element-ng-circle-status.mjs +146 -0
  83. package/fesm2022/siemens-element-ng-circle-status.mjs.map +1 -0
  84. package/fesm2022/siemens-element-ng-column-selection-dialog.mjs +369 -0
  85. package/fesm2022/siemens-element-ng-column-selection-dialog.mjs.map +1 -0
  86. package/fesm2022/siemens-element-ng-common.mjs +1 -1
  87. package/fesm2022/siemens-element-ng-common.mjs.map +1 -1
  88. package/fesm2022/siemens-element-ng-content-action-bar.mjs +200 -0
  89. package/fesm2022/siemens-element-ng-content-action-bar.mjs.map +1 -0
  90. package/fesm2022/siemens-element-ng-date-range-filter.mjs +649 -0
  91. package/fesm2022/siemens-element-ng-date-range-filter.mjs.map +1 -0
  92. package/fesm2022/siemens-element-ng-datepicker.mjs +4231 -0
  93. package/fesm2022/siemens-element-ng-datepicker.mjs.map +1 -0
  94. package/fesm2022/siemens-element-ng-electron-titlebar.mjs +142 -0
  95. package/fesm2022/siemens-element-ng-electron-titlebar.mjs.map +1 -0
  96. package/fesm2022/siemens-element-ng-file-uploader.mjs +751 -0
  97. package/fesm2022/siemens-element-ng-file-uploader.mjs.map +1 -0
  98. package/fesm2022/siemens-element-ng-filter-bar.mjs +153 -0
  99. package/fesm2022/siemens-element-ng-filter-bar.mjs.map +1 -0
  100. package/fesm2022/siemens-element-ng-form.mjs +827 -0
  101. package/fesm2022/siemens-element-ng-form.mjs.map +1 -0
  102. package/fesm2022/siemens-element-ng-icon-status.mjs +65 -0
  103. package/fesm2022/siemens-element-ng-icon-status.mjs.map +1 -0
  104. package/fesm2022/siemens-element-ng-icon.mjs +22 -2
  105. package/fesm2022/siemens-element-ng-icon.mjs.map +1 -1
  106. package/fesm2022/siemens-element-ng-info-page.mjs +63 -0
  107. package/fesm2022/siemens-element-ng-info-page.mjs.map +1 -0
  108. package/fesm2022/siemens-element-ng-inline-notification.mjs +4 -6
  109. package/fesm2022/siemens-element-ng-inline-notification.mjs.map +1 -1
  110. package/fesm2022/siemens-element-ng-ip-input.mjs +451 -0
  111. package/fesm2022/siemens-element-ng-ip-input.mjs.map +1 -0
  112. package/fesm2022/siemens-element-ng-language-switcher.mjs +90 -0
  113. package/fesm2022/siemens-element-ng-language-switcher.mjs.map +1 -0
  114. package/fesm2022/siemens-element-ng-localization.mjs +306 -0
  115. package/fesm2022/siemens-element-ng-localization.mjs.map +1 -0
  116. package/fesm2022/siemens-element-ng-number-input.mjs +267 -0
  117. package/fesm2022/siemens-element-ng-number-input.mjs.map +1 -0
  118. package/fesm2022/siemens-element-ng-password-strength.mjs +177 -0
  119. package/fesm2022/siemens-element-ng-password-strength.mjs.map +1 -0
  120. package/fesm2022/siemens-element-ng-photo-upload.mjs +480 -0
  121. package/fesm2022/siemens-element-ng-photo-upload.mjs.map +1 -0
  122. package/fesm2022/siemens-element-ng-pills-input.mjs +397 -0
  123. package/fesm2022/siemens-element-ng-pills-input.mjs.map +1 -0
  124. package/fesm2022/siemens-element-ng-popover-next.mjs +259 -0
  125. package/fesm2022/siemens-element-ng-popover-next.mjs.map +1 -0
  126. package/fesm2022/siemens-element-ng-popover.mjs +256 -0
  127. package/fesm2022/siemens-element-ng-popover.mjs.map +1 -0
  128. package/fesm2022/siemens-element-ng-progressbar.mjs +83 -0
  129. package/fesm2022/siemens-element-ng-progressbar.mjs.map +1 -0
  130. package/fesm2022/siemens-element-ng-search-bar.mjs +193 -0
  131. package/fesm2022/siemens-element-ng-search-bar.mjs.map +1 -0
  132. package/fesm2022/siemens-element-ng-select.mjs +1166 -0
  133. package/fesm2022/siemens-element-ng-select.mjs.map +1 -0
  134. package/fesm2022/siemens-element-ng-skip-links.mjs +117 -0
  135. package/fesm2022/siemens-element-ng-skip-links.mjs.map +1 -0
  136. package/fesm2022/siemens-element-ng-slider.mjs +313 -0
  137. package/fesm2022/siemens-element-ng-slider.mjs.map +1 -0
  138. package/fesm2022/siemens-element-ng-sort-bar.mjs +89 -0
  139. package/fesm2022/siemens-element-ng-sort-bar.mjs.map +1 -0
  140. package/fesm2022/siemens-element-ng-split.mjs +575 -0
  141. package/fesm2022/siemens-element-ng-split.mjs.map +1 -0
  142. package/fesm2022/siemens-element-ng-status-toggle.mjs +196 -0
  143. package/fesm2022/siemens-element-ng-status-toggle.mjs.map +1 -0
  144. package/fesm2022/siemens-element-ng-summary-widget.mjs +77 -0
  145. package/fesm2022/siemens-element-ng-summary-widget.mjs.map +1 -0
  146. package/fesm2022/siemens-element-ng-system-banner.mjs +47 -0
  147. package/fesm2022/siemens-element-ng-system-banner.mjs.map +1 -0
  148. package/fesm2022/siemens-element-ng-tabs.mjs +395 -0
  149. package/fesm2022/siemens-element-ng-tabs.mjs.map +1 -0
  150. package/fesm2022/siemens-element-ng-toast-notification.mjs +227 -0
  151. package/fesm2022/siemens-element-ng-toast-notification.mjs.map +1 -0
  152. package/fesm2022/siemens-element-ng-translate.mjs.map +1 -1
  153. package/fesm2022/siemens-element-ng-typeahead.mjs +746 -0
  154. package/fesm2022/siemens-element-ng-typeahead.mjs.map +1 -0
  155. package/fesm2022/siemens-element-ng-unauthorized-page.mjs +76 -0
  156. package/fesm2022/siemens-element-ng-unauthorized-page.mjs.map +1 -0
  157. package/fesm2022/siemens-element-ng-wizard.mjs +465 -0
  158. package/fesm2022/siemens-element-ng-wizard.mjs.map +1 -0
  159. package/file-uploader/index.d.ts +8 -0
  160. package/file-uploader/package.json +3 -0
  161. package/file-uploader/si-file-dropzone.component.d.ts +106 -0
  162. package/file-uploader/si-file-uploader.component.d.ts +296 -0
  163. package/file-uploader/si-file-uploader.model.d.ts +12 -0
  164. package/file-uploader/si-file-uploader.module.d.ts +8 -0
  165. package/filter-bar/filter.d.ts +26 -0
  166. package/filter-bar/index.d.ts +8 -0
  167. package/filter-bar/package.json +3 -0
  168. package/filter-bar/si-filter-bar.component.d.ts +65 -0
  169. package/filter-bar/si-filter-bar.module.d.ts +7 -0
  170. package/filter-bar/si-filter-pill.component.d.ts +20 -0
  171. package/form/form-fieldset/si-form-fieldset.component.d.ts +40 -0
  172. package/form/index.d.ts +14 -0
  173. package/form/package.json +3 -0
  174. package/form/si-form-container/si-form-container.component.d.ts +155 -0
  175. package/form/si-form-item/si-form-field-native.control.d.ts +22 -0
  176. package/form/si-form-item/si-form-item.component.d.ts +90 -0
  177. package/form/si-form-item-control-input.directive.d.ts +18 -0
  178. package/form/si-form-item.control.d.ts +35 -0
  179. package/form/si-form-validation-error.model.d.ts +55 -0
  180. package/form/si-form-validation-error.provider.d.ts +11 -0
  181. package/form/si-form-validation-error.service.d.ts +42 -0
  182. package/form/si-form-validation-tooltip/si-form-validation-tooltip.component.d.ts +13 -0
  183. package/form/si-form-validation-tooltip/si-form-validation-tooltip.directive.d.ts +42 -0
  184. package/form/si-form.module.d.ts +25 -0
  185. package/icon/element-icons.d.ts +20 -0
  186. package/icon-status/index.d.ts +6 -0
  187. package/icon-status/package.json +3 -0
  188. package/icon-status/si-icon-status.component.d.ts +24 -0
  189. package/icon-status/si-icon-status.module.d.ts +7 -0
  190. package/info-page/index.d.ts +5 -0
  191. package/info-page/package.json +3 -0
  192. package/info-page/si-info-page.component.d.ts +38 -0
  193. package/inline-notification/si-inline-notification.component.d.ts +0 -2
  194. package/ip-input/address-utils.d.ts +28 -0
  195. package/ip-input/address-validators.d.ts +21 -0
  196. package/ip-input/index.d.ts +7 -0
  197. package/ip-input/package.json +3 -0
  198. package/ip-input/si-ip-input.directive.d.ts +53 -0
  199. package/ip-input/si-ip4-input.directive.d.ts +9 -0
  200. package/ip-input/si-ip6-input.directive.d.ts +10 -0
  201. package/language-switcher/index.d.ts +7 -0
  202. package/language-switcher/iso-language-value.d.ts +14 -0
  203. package/language-switcher/package.json +3 -0
  204. package/language-switcher/si-language-switcher.component.d.ts +32 -0
  205. package/language-switcher/si-language-switcher.module.d.ts +7 -0
  206. package/localization/index.d.ts +8 -0
  207. package/localization/package.json +3 -0
  208. package/localization/si-directionality.d.ts +41 -0
  209. package/localization/si-locale-id.d.ts +22 -0
  210. package/localization/si-locale-store.d.ts +16 -0
  211. package/localization/si-locale.service.d.ts +73 -0
  212. package/number-input/index.d.ts +6 -0
  213. package/number-input/package.json +3 -0
  214. package/number-input/si-number-input.component.d.ts +106 -0
  215. package/number-input/si-number-input.module.d.ts +7 -0
  216. package/package.json +163 -3
  217. package/password-strength/index.d.ts +7 -0
  218. package/password-strength/package.json +3 -0
  219. package/password-strength/si-password-strength.component.d.ts +25 -0
  220. package/password-strength/si-password-strength.directive.d.ts +54 -0
  221. package/password-strength/si-password-strength.module.d.ts +8 -0
  222. package/photo-upload/index.d.ts +6 -0
  223. package/photo-upload/package.json +3 -0
  224. package/photo-upload/si-image-cropper-style.component.d.ts +5 -0
  225. package/photo-upload/si-photo-upload.component.d.ts +298 -0
  226. package/pills-input/index.d.ts +9 -0
  227. package/pills-input/package.json +3 -0
  228. package/pills-input/si-input-pill.component.d.ts +9 -0
  229. package/pills-input/si-pills-input-csv.directive.d.ts +8 -0
  230. package/pills-input/si-pills-input-email.directive.d.ts +10 -0
  231. package/pills-input/si-pills-input-pattern-base.d.ts +19 -0
  232. package/pills-input/si-pills-input-value-handler.d.ts +12 -0
  233. package/pills-input/si-pills-input.component.d.ts +87 -0
  234. package/pills-input/si-pills-input.module.d.ts +9 -0
  235. package/popover/index.d.ts +6 -0
  236. package/popover/package.json +3 -0
  237. package/popover/si-popover.component.d.ts +26 -0
  238. package/popover/si-popover.directive.d.ts +89 -0
  239. package/popover/si-popover.module.d.ts +7 -0
  240. package/popover-next/index.d.ts +7 -0
  241. package/popover-next/package.json +3 -0
  242. package/popover-next/si-popover-description.directive.d.ts +7 -0
  243. package/popover-next/si-popover-next.directive.d.ts +61 -0
  244. package/popover-next/si-popover-title.directive.d.ts +7 -0
  245. package/popover-next/si-popover.component.d.ts +27 -0
  246. package/progressbar/index.d.ts +6 -0
  247. package/progressbar/package.json +3 -0
  248. package/progressbar/si-progressbar.component.d.ts +43 -0
  249. package/progressbar/si-progressbar.module.d.ts +7 -0
  250. package/search-bar/index.d.ts +6 -0
  251. package/search-bar/package.json +3 -0
  252. package/search-bar/si-search-bar.component.d.ts +87 -0
  253. package/search-bar/si-search-bar.module.d.ts +7 -0
  254. package/select/index.d.ts +18 -0
  255. package/select/options/si-select-complex-options.directive.d.ts +69 -0
  256. package/select/options/si-select-lazy-options.directive.d.ts +38 -0
  257. package/select/options/si-select-option.source.d.ts +49 -0
  258. package/select/options/si-select-options-strategy.base.d.ts +35 -0
  259. package/select/options/si-select-options-strategy.d.ts +37 -0
  260. package/select/options/si-select-simple-options.directive.d.ts +34 -0
  261. package/select/package.json +3 -0
  262. package/select/select-input/si-select-input.component.d.ts +43 -0
  263. package/select/select-list/si-select-list-has-filter.component.d.ts +20 -0
  264. package/select/select-list/si-select-list.base.d.ts +37 -0
  265. package/select/select-list/si-select-list.component.d.ts +15 -0
  266. package/select/select-option/si-select-option-row.component.d.ts +16 -0
  267. package/select/select-option/si-select-option.component.d.ts +9 -0
  268. package/select/selection/si-select-multi-value.directive.d.ts +26 -0
  269. package/select/selection/si-select-selection-strategy.d.ts +58 -0
  270. package/select/selection/si-select-single-value.directive.d.ts +26 -0
  271. package/select/si-select-action.directive.d.ts +12 -0
  272. package/select/si-select-actions.directive.d.ts +5 -0
  273. package/select/si-select-group-template.directive.d.ts +20 -0
  274. package/select/si-select-option-row-template.directive.d.ts +9 -0
  275. package/select/si-select-option-template.directive.d.ts +21 -0
  276. package/select/si-select.component.d.ts +96 -0
  277. package/select/si-select.module.d.ts +15 -0
  278. package/select/si-select.types.d.ts +65 -0
  279. package/skip-links/index.d.ts +5 -0
  280. package/skip-links/package.json +3 -0
  281. package/skip-links/si-skip-link-target.directive.d.ts +27 -0
  282. package/skip-links/si-skip-links.component.d.ts +9 -0
  283. package/skip-links/skip-link.service.d.ts +14 -0
  284. package/slider/index.d.ts +6 -0
  285. package/slider/package.json +3 -0
  286. package/slider/si-slider.component.d.ts +129 -0
  287. package/slider/si-slider.module.d.ts +7 -0
  288. package/sort-bar/index.d.ts +6 -0
  289. package/sort-bar/package.json +3 -0
  290. package/sort-bar/si-sort-bar.component.d.ts +42 -0
  291. package/sort-bar/si-sort-bar.module.d.ts +7 -0
  292. package/split/index.d.ts +8 -0
  293. package/split/package.json +3 -0
  294. package/split/si-split-part.component.d.ts +154 -0
  295. package/split/si-split.component.d.ts +48 -0
  296. package/split/si-split.interfaces.d.ts +17 -0
  297. package/split/si-split.module.d.ts +8 -0
  298. package/status-toggle/index.d.ts +6 -0
  299. package/status-toggle/package.json +3 -0
  300. package/status-toggle/si-status-toggle.component.d.ts +54 -0
  301. package/status-toggle/status-toggle.model.d.ts +26 -0
  302. package/summary-widget/index.d.ts +5 -0
  303. package/summary-widget/package.json +3 -0
  304. package/summary-widget/si-summary-widget.component.d.ts +44 -0
  305. package/system-banner/index.d.ts +5 -0
  306. package/system-banner/package.json +3 -0
  307. package/system-banner/system-banner.component.d.ts +23 -0
  308. package/tabs/index.d.ts +7 -0
  309. package/tabs/package.json +3 -0
  310. package/tabs/si-tab/index.d.ts +5 -0
  311. package/tabs/si-tab/si-tab.component.d.ts +58 -0
  312. package/tabs/si-tabs.module.d.ts +8 -0
  313. package/tabs/si-tabset/index.d.ts +5 -0
  314. package/tabs/si-tabset/si-tabset.component.d.ts +100 -0
  315. package/template-i18n.json +111 -1
  316. package/toast-notification/index.d.ts +6 -0
  317. package/toast-notification/package.json +3 -0
  318. package/toast-notification/si-toast-notification/si-toast-notification.component.d.ts +17 -0
  319. package/toast-notification/si-toast-notification-drawer/si-toast-notification-drawer.component.d.ts +9 -0
  320. package/toast-notification/si-toast-notification.service.d.ts +41 -0
  321. package/toast-notification/si-toast.model.d.ts +25 -0
  322. package/translate/si-translatable-keys.interface.d.ts +110 -0
  323. package/typeahead/index.d.ts +8 -0
  324. package/typeahead/package.json +3 -0
  325. package/typeahead/si-typeahead-item-template.directive.d.ts +7 -0
  326. package/typeahead/si-typeahead.component.d.ts +22 -0
  327. package/typeahead/si-typeahead.directive.d.ts +196 -0
  328. package/typeahead/si-typeahead.model.d.ts +60 -0
  329. package/typeahead/si-typeahead.module.d.ts +8 -0
  330. package/typeahead/si-typeahead.sorting.d.ts +10 -0
  331. package/unauthorized-page/index.d.ts +6 -0
  332. package/unauthorized-page/package.json +3 -0
  333. package/unauthorized-page/si-unauthorized-page.component.d.ts +35 -0
  334. package/unauthorized-page/si-unauthorized-page.module.d.ts +7 -0
  335. package/wizard/index.d.ts +7 -0
  336. package/wizard/package.json +3 -0
  337. package/wizard/si-wizard-step.component.d.ts +21 -0
  338. package/wizard/si-wizard.component.d.ts +196 -0
  339. package/wizard/si-wizard.module.d.ts +8 -0
@@ -0,0 +1,4231 @@
1
+ import { getLocaleDayPeriods, FormStyle, TranslationWidth, getLocaleId, getLocaleDateTimeFormat, FormatWidth, getLocaleTimeFormat, getLocaleDateFormat, formatDate, NgClass, DatePipe, NgTemplateOutlet, getLocaleFirstDayOfWeek, WeekDay, DOCUMENT } from '@angular/common';
2
+ import * as i0 from '@angular/core';
3
+ import { input, model, output, booleanAttribute, computed, signal, inject, LOCALE_ID, HostListener, Directive, ElementRef, viewChildren, Component, ChangeDetectionStrategy, viewChild, HostAttributeToken, ChangeDetectorRef, SimpleChange, DestroyRef, contentChild, NgModule } from '@angular/core';
4
+ import * as i1 from '@angular/forms';
5
+ import { Validators, NG_VALUE_ACCESSOR, NG_VALIDATORS, FormsModule, NgControl } from '@angular/forms';
6
+ import { SI_FORM_ITEM_CONTROL } from '@siemens/element-ng/form';
7
+ import { MediaMatcher, BreakpointObserver } from '@angular/cdk/layout';
8
+ import { Overlay } from '@angular/cdk/overlay';
9
+ import { ComponentPortal } from '@angular/cdk/portal';
10
+ import { takeUntilDestroyed, outputToObservable } from '@angular/core/rxjs-interop';
11
+ import { isRTL, getOverlayPositions, positionBottomCenter, positionBottomStart, positionBottomEnd, positionTopCenter, positionTopStart, positionTopEnd } from '@siemens/element-ng/common';
12
+ import { BOOTSTRAP_BREAKPOINTS } from '@siemens/element-ng/resize-observer';
13
+ import { Subject, merge } from 'rxjs';
14
+ import { takeUntil, skip, map, filter, tap } from 'rxjs/operators';
15
+ import * as i3 from '@angular/cdk/a11y';
16
+ import { A11yModule, FocusMonitor, ConfigurableFocusTrapFactory } from '@angular/cdk/a11y';
17
+ import * as i2 from '@siemens/element-translate-ng/translate';
18
+ import { SiTranslateModule } from '@siemens/element-translate-ng/translate';
19
+ import { addIcons, elementRight2, elementLeft2, SiIconNextComponent, elementCalendar } from '@siemens/element-ng/icon';
20
+
21
+ /**
22
+ * Copyright Siemens 2016 - 2025.
23
+ * SPDX-License-Identifier: MIT
24
+ */
25
+ const WEEK_ISO = [
26
+ { id: 'monday', index: 1, offset: 0, isWeekend: false },
27
+ { id: 'tuesday', index: 2, offset: 1, isWeekend: false },
28
+ { id: 'wednesday', index: 3, offset: 2, isWeekend: false },
29
+ { id: 'thursday', index: 4, offset: 3, isWeekend: false },
30
+ { id: 'friday', index: 5, offset: 4, isWeekend: false },
31
+ { id: 'saturday', index: 6, offset: 5, isWeekend: true },
32
+ { id: 'sunday', index: 7, offset: 6, isWeekend: true }
33
+ ];
34
+ const WEEK_START_OFFSET = {
35
+ 'monday': 0,
36
+ 'saturday': 5,
37
+ 'sunday': 6
38
+ };
39
+ const UNITS = {
40
+ millisecondsPerDay: 86400000,
41
+ daysPerWeek: 7,
42
+ thursday: 4
43
+ };
44
+ const dayOfWeekMap = {};
45
+ const getDaysOfWeek = (weekStart) => {
46
+ weekStart = weekStart ?? 'monday';
47
+ let weekdays = dayOfWeekMap[weekStart];
48
+ if (!weekdays) {
49
+ dayOfWeekMap[weekStart] = weekdays = [];
50
+ const offset = WEEK_START_OFFSET[weekStart];
51
+ for (let i = 0; i < 7; i++) {
52
+ weekdays.push({ ...WEEK_ISO[(i + offset) % 7], offset: i });
53
+ }
54
+ }
55
+ return weekdays;
56
+ };
57
+ /**
58
+ * Get local specific months using DateTimeFormat.
59
+ * @param locale - current locale
60
+ */
61
+ const getLocaleMonthNames = (locale) => {
62
+ const format = new Intl.DateTimeFormat(locale, { month: 'long', timeZone: 'UTC' }).format;
63
+ return Array(12)
64
+ .fill(0)
65
+ .map((v, m) => format(new Date(Date.UTC(0, m))));
66
+ };
67
+ /**
68
+ * Get local specific weekdays as string using DateTimeFormat.
69
+ * @param locale - current local
70
+ * @param weekStart - start of the week
71
+ * @param format - display format
72
+ * @returns array of week days.
73
+ */
74
+ const getDayStrings = (locale, weekStart = 'monday', format = 'short') => {
75
+ const dateFormatter = new Intl.DateTimeFormat(locale, { weekday: format, timeZone: 'utc' });
76
+ const days = [];
77
+ // Get local specific day strings from sunday (0) .. saturady (6)
78
+ for (let index = 1; index <= 7; index++) {
79
+ const day = new Date(Date.UTC(2023, 0, index));
80
+ days.push(dateFormatter.format(day));
81
+ }
82
+ const map = { 'sunday': 0, 'monday': 1, 'saturday': 6 };
83
+ const index = map[weekStart];
84
+ return days.slice(index).concat(days.slice(0, index));
85
+ };
86
+ /**
87
+ * Gets the first day in the specified month.
88
+ * Expects the month as a value between 1 and 12.
89
+ * The year is required to handle leap years.
90
+ *
91
+ * @returns The first day of the month as a Date.
92
+ */
93
+ const getFirstDayInMonth = (year, month) => new Date(year, month - 1, 1);
94
+ /**
95
+ * Gets the week number of the specified date.
96
+ * Week number according to the ISO-8601 standard, weeks starting on Monday.
97
+ * The first week of a year is the week that contains the first Thursday of the year (='First 4-day week').
98
+ * The highest week number in a year is either 52 or 53.
99
+ *
100
+ * @param date -The JavaScript date object.
101
+ * @param weekStart -Name of the first day of the week
102
+ * @returns The number of the Week
103
+ */
104
+ const getWeekOfYear = (date, weekStart) => {
105
+ // Algorithm rewritten from C# example given at http://en.wikipedia.org/wiki/Talk:ISO_week_date
106
+ const dayOfWeek = getWeekDayOffset(date, weekStart) + 1;
107
+ const nearestThu = new Date(date);
108
+ nearestThu.setDate(date.getDate() + (UNITS.thursday - dayOfWeek)); // get nearest Thursday (-3..+3 days)
109
+ const year = nearestThu.getFullYear();
110
+ const janfirst = getFirstDayInMonth(year, 1);
111
+ const days = Math.floor((nearestThu - janfirst) / UNITS.millisecondsPerDay);
112
+ const week = 1 + Math.floor(days / UNITS.daysPerWeek); // Count of Thursdays
113
+ return week;
114
+ };
115
+ const getWeekDayOffset = (date, weekStart) => {
116
+ const offset = WEEK_START_OFFSET[weekStart ?? 'monday'];
117
+ return (date.getDay() + 6 - offset) % 7;
118
+ };
119
+ /** returns the date string in format YYYY-MM-DD for given date */
120
+ const getStringforDate = (date) => {
121
+ let month = '' + (date.getMonth() + 1);
122
+ let day = '' + date.getDate();
123
+ const year = date.getFullYear();
124
+ if (month.length < 2) {
125
+ month = '0' + month;
126
+ }
127
+ if (day.length < 2) {
128
+ day = '0' + day;
129
+ }
130
+ return `${year}-${month}-${day}`;
131
+ };
132
+ /**
133
+ * Creates a new date object on from a date with or without time.
134
+ * @param value - The date from with the year, month and day is taken.
135
+ * @param hours - Optional numeric value of the hours, otherwise 0.
136
+ * @param minutes - Optional numeric value of the minutes, otherwise 0.
137
+ * @param seconds - Optional numeric value of the seconds, otherwise 0.
138
+ * @param milliseconds - Optional numeric value of the milliseconds, otherwise 0.
139
+ * @returns
140
+ */
141
+ const createDate = (value, hours = 0, minutes = 0, seconds = 0, milliseconds = 0) => {
142
+ const newDate = new Date(value.getFullYear(), value.getMonth(), value.getDate(), hours, minutes, seconds, milliseconds);
143
+ // Seems redundant, but makes sure that increasing
144
+ // the hours does no change the date when switching
145
+ // from 11pm up.
146
+ newDate.setFullYear(value.getFullYear());
147
+ newDate.setMonth(value.getMonth());
148
+ newDate.setDate(value.getDate());
149
+ return newDate;
150
+ };
151
+ /** Creates a date but allows the month and date to overflow. */
152
+ const createDateInternal = (year, month, date) => {
153
+ const d = new Date();
154
+ d.setFullYear(year, month, date);
155
+ d.setHours(0, 0, 0, 0);
156
+ return d;
157
+ };
158
+ const NAMED_FORMATS = {};
159
+ const INVALID_DATE = new Date(NaN);
160
+ /**
161
+ * @param input - String containing a date or dateTime value (Ex. "05/15/2020"
162
+ * @param format - Format of the input value (Ex. "M/d/YYYY")
163
+ * @param locale - Locale of the input value
164
+ * @returns A JS Date in accordance of the three parameters
165
+ */
166
+ const parseDate = (input, format, locale) => {
167
+ if (!input) {
168
+ return undefined;
169
+ }
170
+ const splitFormat = format.split(/[^MydhHmsSa]+/);
171
+ const splitDate = input.toUpperCase().match(/\d+|\w+/g);
172
+ if (!splitDate) {
173
+ return INVALID_DATE;
174
+ }
175
+ // in case of some locales where meridian is with special chars
176
+ const dateAndMeridian = input.split(/ +/);
177
+ if (splitDate.length > 0 && dateAndMeridian.length > 0) {
178
+ const parsedMeridian = dateAndMeridian[dateAndMeridian.length - 1].toUpperCase();
179
+ if (splitDate[splitDate.length - 1] !== parsedMeridian &&
180
+ getMeridian(parsedMeridian, locale)) {
181
+ splitDate?.push(parsedMeridian);
182
+ }
183
+ }
184
+ let year = 0;
185
+ let month = 0;
186
+ /*
187
+ date as in the numeric day of the month to be provided for the Date() constructor.
188
+ default value is 1 since 0 refers to the last date of previous month.
189
+ */
190
+ let date = 1;
191
+ let hour = 0;
192
+ let minute = 0;
193
+ let second = 0;
194
+ let milliseconds = 0;
195
+ // check if date is invalid and return if it is invalid
196
+ for (let i = 0; i < splitDate.length; i++) {
197
+ if (i === splitDate.length - 1) {
198
+ const parsedMeridian = splitDate[splitDate.length - 1];
199
+ // skip if its meridian
200
+ if (getMeridian(parsedMeridian, locale)) {
201
+ continue;
202
+ }
203
+ }
204
+ const parsedDateVal = parseInt(splitDate[i], 10);
205
+ if (isNaN(parsedDateVal)) {
206
+ return INVALID_DATE;
207
+ }
208
+ }
209
+ for (let i = 0; i < splitFormat.length; i++) {
210
+ const f = splitFormat[i];
211
+ let parsedNumber = parseInt(splitDate[i], 10);
212
+ if (f !== 'a' && isNaN(parsedNumber)) {
213
+ // auto fill seconds and milliseconds if not passed by user
214
+ if (f === 'ss' || f === 'SSS') {
215
+ parsedNumber = 0;
216
+ }
217
+ else {
218
+ return INVALID_DATE;
219
+ }
220
+ }
221
+ if (f === 'M' || f === 'MM') {
222
+ month = parsedNumber;
223
+ }
224
+ else if (f === 'd' || f === 'dd') {
225
+ date = parsedNumber;
226
+ }
227
+ else if (f === 'y' || f === 'yy' || f === 'yyyy') {
228
+ // JS adds 1900 for numbers between 0 and 99. Adjust to be more user-friendly
229
+ year =
230
+ parsedNumber < 50
231
+ ? parsedNumber + 2000
232
+ : parsedNumber < 100
233
+ ? parsedNumber + 1900
234
+ : parsedNumber;
235
+ }
236
+ else if (f === 'h' || f === 'HH') {
237
+ hour = parsedNumber;
238
+ }
239
+ else if (f === 'mm') {
240
+ minute = parsedNumber;
241
+ }
242
+ else if (f === 'ss') {
243
+ second = parsedNumber;
244
+ }
245
+ else if (f === 'SSS') {
246
+ milliseconds = parsedNumber;
247
+ }
248
+ else if (f === 'a') {
249
+ if (!isNaN(parseInt(splitDate[splitDate.length - 1], 10))) {
250
+ continue;
251
+ }
252
+ const parsedMeridian = splitDate[splitDate.length - 1];
253
+ const meridian = getMeridian(parsedMeridian, locale);
254
+ if (hour === 12 && meridian === 'AM') {
255
+ hour = 0;
256
+ }
257
+ else if (meridian === 'PM') {
258
+ hour = (hour % 12) + 12;
259
+ }
260
+ else if (!meridian) {
261
+ return INVALID_DATE;
262
+ }
263
+ }
264
+ }
265
+ if (month > 12 || date > 31 || date > new Date(year, month, 0).getDate()) {
266
+ return INVALID_DATE;
267
+ }
268
+ return new Date(year, month - 1, date, hour, minute, second, milliseconds);
269
+ };
270
+ const getMeridian = (parsedMeridian, locale) => {
271
+ const meridian = getLocaleDayPeriods(locale, FormStyle.Format, TranslationWidth.Short);
272
+ const usingAM = parsedMeridian === meridian[0].toUpperCase();
273
+ if (usingAM) {
274
+ return 'AM';
275
+ }
276
+ else {
277
+ const usingPM = parsedMeridian === meridian[1].toUpperCase();
278
+ return usingPM ? 'PM' : undefined;
279
+ }
280
+ };
281
+ // Adapted from: https://github.com/angular/angular/blob/91954cf20e17a386d71cc8ea25d1d17b9ae1e31c/packages/common/src/i18n/format_date.ts
282
+ // unfortunately it is not exported there
283
+ const getNamedFormat = (locale, format) => {
284
+ const localeId = getLocaleId(locale);
285
+ NAMED_FORMATS[localeId] = NAMED_FORMATS[localeId] || {};
286
+ if (NAMED_FORMATS[localeId][format]) {
287
+ return NAMED_FORMATS[localeId][format];
288
+ }
289
+ let formatValue = '';
290
+ switch (format) {
291
+ case 'shortDate':
292
+ formatValue = getLocaleDateFormat(locale, FormatWidth.Short);
293
+ break;
294
+ case 'shortTime':
295
+ formatValue = getLocaleTimeFormat(locale, FormatWidth.Short);
296
+ break;
297
+ case 'mediumTime':
298
+ formatValue = getLocaleTimeFormat(locale, FormatWidth.Medium);
299
+ break;
300
+ case 'longTime':
301
+ formatValue = getLocaleTimeFormat(locale, FormatWidth.Long);
302
+ break;
303
+ case 'fullTime':
304
+ formatValue = getLocaleTimeFormat(locale, FormatWidth.Full);
305
+ break;
306
+ case 'short':
307
+ case 'medium':
308
+ {
309
+ const shortTime = getNamedFormat(locale, format === 'short' ? 'shortTime' : 'mediumTime');
310
+ const shortDate = getNamedFormat(locale, 'shortDate');
311
+ formatValue = formatDateTime(getLocaleDateTimeFormat(locale, FormatWidth.Short), [
312
+ shortTime,
313
+ shortDate
314
+ ]);
315
+ }
316
+ break;
317
+ }
318
+ if (formatValue) {
319
+ NAMED_FORMATS[localeId][format] = formatValue;
320
+ }
321
+ return formatValue;
322
+ };
323
+ const formatDateTime = (str, optVals) => {
324
+ if (optVals) {
325
+ str = str.replace(/\{([^}]+)}/g, (match, key) => optVals != null && key in optVals ? optVals[key] : match);
326
+ }
327
+ return str;
328
+ };
329
+ const getDateWithoutTime = (date) => createDate(date, 0, 0, 0, 0);
330
+ /**
331
+ * Get today
332
+ * @returns date of today
333
+ */
334
+ const today = () => new Date();
335
+ /**
336
+ * Calculate a new date based on the offset while considering the min and max date.
337
+ * @param current - input date.
338
+ * @param daysOffset - numeric offset of days.
339
+ * @returns new date if the range is valid or original date
340
+ */
341
+ const addDaysInRange = (current, daysOffset, minDate, maxDate) => {
342
+ const newDate = addDays(current, daysOffset);
343
+ // Make sure the new date is within the specified limits
344
+ // MinDate < new data < MaxDate
345
+ if (isSameOrBetween(newDate, minDate, maxDate)) {
346
+ return newDate;
347
+ }
348
+ return getDateSameOrBetween(newDate, minDate, maxDate);
349
+ };
350
+ /**
351
+ * Get date delta based on the offset.
352
+ * @param date - source date object.
353
+ * @param days - numeric offset of days.
354
+ * @returns new date.
355
+ */
356
+ const addDays = (date, days) => {
357
+ const d = createDate(date);
358
+ d.setDate(d.getDate() + days);
359
+ return d;
360
+ };
361
+ /**
362
+ * Update date/day of give date without changing the month.
363
+ * In case the day exceed the number of days in the current month the last day in month will be assigned.
364
+ * @param date - the date object to update the day.
365
+ * @param day - the day which shall be set.
366
+ * @returns the updated date object.
367
+ */
368
+ const changeDay = (date, day) => {
369
+ const lastDay = daysInMonth(date.getMonth(), date.getFullYear());
370
+ date.setDate(lastDay <= day ? lastDay : day);
371
+ return date;
372
+ };
373
+ /**
374
+ * Get date delta specifically for months based on the offset.
375
+ * @param current - starting date.
376
+ * @param monthsOffset - numeric offset of months.
377
+ * @param minDate - optional minimum allowed date.
378
+ * @param maxDate - optional maximum allowed date.
379
+ * @returns a new date object with the updated month.
380
+ */
381
+ const addMonthsInRange = (current, monthsOffset, minDate, maxDate) => {
382
+ let newDate = createDateInternal(current.getFullYear(), current.getMonth() + monthsOffset, 1);
383
+ newDate = changeDay(newDate, current.getDate());
384
+ if (isSameOrBetween(newDate, minDate, maxDate)) {
385
+ return newDate;
386
+ }
387
+ return getDateSameOrBetween(newDate, minDate, maxDate);
388
+ };
389
+ /**
390
+ * Get date delta specifically for years based on the offset.
391
+ * @param current - starting date.
392
+ * @param yearsOffset - numeric offset of years.
393
+ * @param minDate - optional minimum allowed date.
394
+ * @param maxDate - optional maximum allowed date.
395
+ * @returns a new date object with the updated year.
396
+ */
397
+ const addYearsInRange = (current, yearsOffset, minDate, maxDate) => {
398
+ const newDate = createDateInternal(current.getFullYear() + yearsOffset, current.getMonth(), current.getDate());
399
+ if (isSameOrBetween(newDate, minDate, maxDate)) {
400
+ return newDate;
401
+ }
402
+ return getDateSameOrBetween(newDate, minDate, maxDate);
403
+ };
404
+ /**
405
+ * Get number of days for the given month and year.
406
+ * @param month - month as number (0..11).
407
+ * @param year - year as number.
408
+ * @returns the number of days for the given month.
409
+ */
410
+ const daysInMonth = (month, year) =>
411
+ // By using 0 as the day it will give us the last day of the prior
412
+ // month. So passing in 1 as the month number will return the last day
413
+ new Date(year, month + 1, 0).getDate();
414
+ /**
415
+ * Get the first date of the week based on the input date.
416
+ * @param current - a date object from where the last date of a week is derived.
417
+ * @param weekStartDay - optional when a week shall start.
418
+ * @returns a new date object which is the start of the current week.
419
+ */
420
+ const getWeekStartDate = (current, weekStartDay = 'monday') => {
421
+ const weekStartDate = createDate(current);
422
+ const diff = current.getDate() - getWeekDayOffset(current, weekStartDay);
423
+ weekStartDate.setDate(diff);
424
+ return weekStartDate;
425
+ };
426
+ /**
427
+ * Get the last date of the week based on the input date.
428
+ * @param current - a date object from where the last date of a week is derived.
429
+ * @param weekStartDay - optional when a week shall start.
430
+ * @returns the last date within the week.
431
+ */
432
+ const getWeekEndDate = (current, weekStartDay = 'monday') => {
433
+ const weekStartDate = createDate(current);
434
+ weekStartDate.setDate(current.getDate() + 6 - getWeekDayOffset(current, weekStartDay));
435
+ return weekStartDate;
436
+ };
437
+ /**
438
+ * Get the beginning of the month.
439
+ * @param current - a date object from where the first date in a month is derived.
440
+ * @returns a new date object which starts a the first.
441
+ */
442
+ const getFirstDateInMonth = (current) => new Date(current.getFullYear(), current.getMonth(), 1);
443
+ /**
444
+ * Get the last date of the month.
445
+ * @param current - a date object from where we derive the last date in a month.
446
+ * @returns a new date object which is the last day in the current month.
447
+ */
448
+ const getLastDateInMonth = (current) => new Date(current.getFullYear(), current.getMonth() + 1, 0);
449
+ /**
450
+ * Get the beginning of the year.
451
+ * @param current - a date object from where the first date in a year is derived.
452
+ * @returns a new date object which starts a the first.
453
+ */
454
+ const getFirstDateInYear = (current) => new Date(current.getFullYear(), 0, 1);
455
+ /**
456
+ * Are the two dates identical without considering time.
457
+ */
458
+ const isSameDate = (current, compareTo) => {
459
+ if (!compareTo) {
460
+ return false;
461
+ }
462
+ return (current.getFullYear() === compareTo.getFullYear() &&
463
+ current.getMonth() === compareTo.getMonth() &&
464
+ current.getDate() === compareTo.getDate());
465
+ };
466
+ /**
467
+ * Are the two months identical without considering time.
468
+ */
469
+ const isSameMonth = (current, compareTo) => {
470
+ if (!compareTo) {
471
+ return false;
472
+ }
473
+ return isSameYear(current, compareTo) && current.getMonth() === compareTo.getMonth();
474
+ };
475
+ /**
476
+ * Are the two years identical.
477
+ */
478
+ const isSameYear = (current, compareTo) => {
479
+ if (!compareTo) {
480
+ return false;
481
+ }
482
+ return current.getFullYear() === compareTo.getFullYear();
483
+ };
484
+ /**
485
+ * Compares two dates.
486
+ * @param first - The first date to compare.
487
+ * @param second - The second date to compare.
488
+ * @returns 0 if the dates are equal, a number less than 0 if the first date is earlier,
489
+ * a number greater than 0 if the first date is later.
490
+ */
491
+ const compareDate = (first, second) => compareMonth(first, second) || first.getDate() - second.getDate();
492
+ /**
493
+ * Compares two months.
494
+ * @param first - The first month to compare.
495
+ * @param second - The second month to compare.
496
+ * @returns 0 if the months are equal, a number less than 0 if the first month is earlier,
497
+ * a number greater than 0 if the first month is later.
498
+ */
499
+ const compareMonth = (first, second) => compareYear(first, second) || first.getMonth() - second.getMonth();
500
+ /**
501
+ * Compares two years.
502
+ * @param first - The first year to compare.
503
+ * @param second - The second year to compare.
504
+ * @returns 0 if the years are equal, a number less than 0 if the first year is earlier,
505
+ * a number greater than 0 if the first year is later.
506
+ */
507
+ const compareYear = (first, second) => first.getFullYear() - second.getFullYear();
508
+ /**
509
+ * Compare the current date is the same date or between start and end date.
510
+ * @param current - the date object.
511
+ * @param from - optional min date, if no value is provided we assume true for the min value.
512
+ * @param to - optional max date, if no value is provided we assume true for the max value.
513
+ * @returns true if the date is in the provided range.
514
+ */
515
+ const isSameOrBetween = (current, from, to) => {
516
+ // from <= d
517
+ const isInMinRange = from ? compareDate(from, current) <= 0 : true;
518
+ // d <= to
519
+ const isInMaxRange = to ? compareDate(current, to) <= 0 : true;
520
+ return isInMinRange && isInMaxRange;
521
+ };
522
+ /**
523
+ * Compare the current month is the same month or between start and end month.
524
+ * @param current - the month object.
525
+ * @param from - optional min month, if no value is provided we assume true for the min value.
526
+ * @param to - optional max month, if no value is provided we assume true for the max value.
527
+ * @returns true if the date is in the provided range.
528
+ */
529
+ const isSameOrBetweenMonth = (current, from, to) => {
530
+ // from <= d
531
+ const isInMinRange = from ? compareMonth(from, current) <= 0 : true;
532
+ // d <= to
533
+ const isInMaxRange = to ? compareMonth(current, to) <= 0 : true;
534
+ return isInMinRange && isInMaxRange;
535
+ };
536
+ /**
537
+ * Compare the current year is the same year or between start and end year.
538
+ * @param current - the year object.
539
+ * @param from - optional min year, if no value is provided we assume true for the min value.
540
+ * @param to - optional max year, if no value is provided we assume true for the max value.
541
+ * @returns true if the date is in the provided range.
542
+ */
543
+ const isSameOrBetweenYears = (current, from, to) => {
544
+ // from <= d
545
+ const isInMinRange = from ? compareYear(from, current) <= 0 : true;
546
+ // d <= to
547
+ const isInMaxRange = to ? compareYear(current, to) <= 0 : true;
548
+ return isInMinRange && isInMaxRange;
549
+ };
550
+ /**
551
+ * Compare the current date is between start and end date.
552
+ * from \< current \< to
553
+ */
554
+ const isBetween = (current, from, to) => {
555
+ const isInMinRange = from ? compareDate(current, from) > 0 : true;
556
+ const isInMaxRange = to ? compareDate(current, to) < 0 : true;
557
+ return isInMinRange && isInMaxRange;
558
+ };
559
+ /**
560
+ * Compare the current month is between start and end month.
561
+ * from \< current \< to
562
+ */
563
+ const isBetweenMonth = (current, from, to) => {
564
+ const isInMinRange = from ? compareMonth(current, from) > 0 : true;
565
+ const isInMaxRange = to ? compareMonth(current, to) < 0 : true;
566
+ return isInMinRange && isInMaxRange;
567
+ };
568
+ /**
569
+ * Compare the current year is between start and end year.
570
+ * from \< current \< to
571
+ */
572
+ const isBetweenYears = (current, from, to) => {
573
+ const isInMinRange = from ? compareYear(current, from) > 0 : true;
574
+ const isInMaxRange = to ? compareYear(current, to) < 0 : true;
575
+ return isInMinRange && isInMaxRange;
576
+ };
577
+ /**
578
+ * Is first date after the second date (without considering the time).
579
+ * current \> compareTo
580
+ */
581
+ const isAfter = (current, compareTo) => compareDate(current, compareTo) > 0;
582
+ /**
583
+ * Is first month after the second month (without considering the time).
584
+ * current \> compareTo
585
+ */
586
+ const isAfterMonth = (current, compareTo) => compareMonth(current, compareTo) > 0;
587
+ /**
588
+ * Is first year after the second year.
589
+ * current \> compareTo
590
+ */
591
+ const isAfterYear = (current, compareTo) => compareYear(current, compareTo) > 0;
592
+ /**
593
+ * Is first date equal or before the second date (without considering the time).
594
+ * current \>= compareTo
595
+ */
596
+ const isSameOrBefore = (current, compareTo) => compareDate(current, compareTo) <= 0;
597
+ /**
598
+ * Is first month equal or before the second month.
599
+ * current \>= compareTo
600
+ */
601
+ const isSameOrBeforeMonth = (current, compareTo) => compareMonth(current, compareTo) <= 0;
602
+ /**
603
+ * Is first year equal or before the second year.
604
+ * current \>= compareTo
605
+ */
606
+ const isSameOrBeforeYear = (current, compareTo) => compareMonth(current, compareTo) <= 0;
607
+ /**
608
+ * Are the two dates in different months.
609
+ */
610
+ const isAnotherMonth = (current, compareTo) => current.getMonth() !== compareTo.getMonth();
611
+ /**
612
+ * Are the two dates in different years.
613
+ */
614
+ const isAnotherYear = (current, compareTo) => current.getFullYear() !== compareTo.getFullYear();
615
+ /**
616
+ * Are the two dates either in different months or years.
617
+ */
618
+ const isAnotherMonthOrYear = (current, compareTo) => isAnotherMonth(current, compareTo) || isAnotherYear(current, compareTo);
619
+ /**
620
+ * Get a date which is in within the range and the close to current.
621
+ */
622
+ const getDateSameOrBetween = (current, minDate, maxDate) => {
623
+ if (isSameOrBetween(current, minDate, maxDate)) {
624
+ return current;
625
+ }
626
+ const minDistance = minDate
627
+ ? Math.ceil(Math.abs(current.getTime() - minDate.getTime()))
628
+ : Number.MAX_VALUE;
629
+ const maxDistance = maxDate
630
+ ? Math.ceil(Math.abs(current.getTime() - maxDate.getTime()))
631
+ : Number.MAX_VALUE;
632
+ return minDistance < maxDistance ? createDate(minDate) : createDate(maxDate);
633
+ };
634
+ /**
635
+ * Get date or absolute min date.
636
+ * @param date - input date.
637
+ * @returns date or date of 1.1.1900
638
+ */
639
+ const getMinDate = (date) => date && !isNaN(date.getTime()) ? date : new Date(Date.UTC(1900, 0, 1));
640
+ /**
641
+ * Get date or absolute max date.
642
+ * @param date - input date.
643
+ * @returns date or date of 31.12.2154
644
+ */
645
+ const getMaxDate = (date) => date && !isNaN(date.getTime()) ? date : new Date(Date.UTC(2154, 11, 31));
646
+ /**
647
+ * Is valid date object.
648
+ */
649
+ const isValid = (date) => !!date && !isNaN(date.getTime());
650
+ /**
651
+ * Returns the next months of the given date.
652
+ * @param date - The date for which the next month is returned.
653
+ * @returns A date of the first day of the following month of the given day.
654
+ */
655
+ const nextMonth = (date) => {
656
+ if (date.getMonth() === 11) {
657
+ return new Date(date.getFullYear() + 1, 0, 1);
658
+ }
659
+ else {
660
+ return new Date(date.getFullYear(), date.getMonth() + 1, 1);
661
+ }
662
+ };
663
+ /**
664
+ * Returns the last day of the previous month of the given date object.
665
+ * @param date - The date for which the previous month is returned.
666
+ * @returns A date of the last day of the previous month of the given day.
667
+ */
668
+ const previousMonth = (date) => {
669
+ if (date.getMonth() === 0) {
670
+ return new Date(date.getFullYear() - 1, 12, 0);
671
+ }
672
+ else {
673
+ return new Date(date.getFullYear(), date.getMonth(), 0);
674
+ }
675
+ };
676
+ const minDate = (first, second) => {
677
+ return !!first && !!second ? (first < second ? first : second) : (first ?? second);
678
+ };
679
+ const maxDate = (first, second) => {
680
+ return !!first && !!second ? (first > second ? first : second) : (first ?? second);
681
+ };
682
+
683
+ /**
684
+ * Returns date / datetime format to be used for rendering a date object as text
685
+ * to an Html input element, which has the `SiDatepickerDirective`.
686
+ *
687
+ * @see https://angular.dev/api/common/DatePipe?tab=usage-notes
688
+ * @param locale - The locale for which the format is returned.
689
+ * @param config - The config object of the datepicker.
690
+ * @param timeWhenDisabled - If `true`, a format with time (medium or short) is returned, even if the `disabledTime` config is `true`.
691
+ * @returns Either
692
+ * - a custom format provided by the config,
693
+ * - the localized `medium` format when time and seconds included
694
+ * - the localized `short` format when time and no seconds included
695
+ */
696
+ const getDatepickerFormat = (locale, config, timeWhenDisabled = false) => {
697
+ // try format from consumer
698
+ let dateFormat = config?.showTime && !config.disabledTime ? config.dateTimeFormat : config?.dateFormat;
699
+ if (!dateFormat) {
700
+ // no format from consumer - use default depending on configuration
701
+ let named;
702
+ if (config?.showTime && (!config.disabledTime || timeWhenDisabled)) {
703
+ named = config.showSeconds ? 'medium' : 'short';
704
+ }
705
+ else {
706
+ named = 'shortDate';
707
+ }
708
+ dateFormat = getNamedFormat(locale, named);
709
+ }
710
+ // patch 2-digit year to 4-digit year
711
+ if (!dateFormat.includes('yyyy')) {
712
+ dateFormat = dateFormat.replace('yy', 'yyyy');
713
+ }
714
+ if (config?.onlyMonthSelection && dateFormat.includes('d')) {
715
+ dateFormat = dateFormat
716
+ .replace(/\sd/, '')
717
+ .replace(/\/d/, '')
718
+ .replace(/d/g, '')
719
+ .replace(/^\./, '');
720
+ }
721
+ return dateFormat;
722
+ };
723
+
724
+ /**
725
+ * Copyright Siemens 2016 - 2025.
726
+ * SPDX-License-Identifier: MIT
727
+ */
728
+ /**
729
+ * Base directive for date input fields.
730
+ */
731
+ class SiDateInputDirective {
732
+ static idCounter = 0;
733
+ /**
734
+ * @defaultValue
735
+ * ```
736
+ * `si-date-input-${SiDateInputDirective.idCounter++}`
737
+ * ```
738
+ */
739
+ id = input(`si-date-input-${SiDateInputDirective.idCounter++}`);
740
+ /**
741
+ * Configuration object for the datepicker.
742
+ *
743
+ * @defaultValue
744
+ * ```
745
+ * {}
746
+ * ```
747
+ */
748
+ siDatepickerConfig = model({});
749
+ /**
750
+ * @deprecated Property has no effect and will be removed without a replacement.
751
+ *
752
+ * @defaultValue 200
753
+ */
754
+ dateInputDebounceTime = input(200);
755
+ /**
756
+ * Emits an event to notify about disabling the time from the datepicker.
757
+ * When time is disable, we construct a pure date object in UTC 00:00:00 time.
758
+ */
759
+ siDatepickerDisabledTime = output();
760
+ /**
761
+ * Emits an event on state changes e.g. readonly, disable, ... .
762
+ */
763
+ stateChange = output();
764
+ /**
765
+ * Whether the date range input is disabled.
766
+ * @defaultValue false
767
+ */
768
+ // eslint-disable-next-line @angular-eslint/no-input-rename
769
+ disabledInput = input(false, { alias: 'disabled' });
770
+ /**
771
+ * Whether the date range input is readonly.
772
+ * @defaultValue false
773
+ */
774
+ readonly = input(false, { transform: booleanAttribute });
775
+ /**
776
+ * Overrides the value of aria-describedby
777
+ *
778
+ * @defaultValue
779
+ * ```
780
+ * `${this.id()}-errormessage`
781
+ * ```
782
+ */
783
+ errormessageId = input(`${this.id()}-errormessage`);
784
+ /** @internal */
785
+ validatorOnChange = () => { };
786
+ /**
787
+ * Date form input validator function, validating text format, min and max value.
788
+ */
789
+ validator = Validators.compose([
790
+ () => this.formatValidator(),
791
+ () => this.minValidator(),
792
+ () => this.maxValidator()
793
+ ]);
794
+ date;
795
+ /**
796
+ * Emits a new `date` value on input field value changes.
797
+ */
798
+ dateChange = output();
799
+ /** @internal */
800
+ disabled = computed(() => this.disabledInput() || this.disabledNgControl());
801
+ onTouched = () => { };
802
+ onModelChange = () => { };
803
+ dateString = signal('');
804
+ disabledNgControl = signal(false);
805
+ locale = inject(LOCALE_ID).toString();
806
+ format = '';
807
+ ngOnChanges(changes) {
808
+ if (changes.siDatepickerConfig && !changes.siDatepickerConfig.currentValue) {
809
+ this.siDatepickerConfig.set({});
810
+ }
811
+ if (changes.readonly || changes.disabledInput) {
812
+ this.stateChange.emit();
813
+ }
814
+ if (changes.siDatepickerConfig) {
815
+ // reflect possible change is date/time format
816
+ const format = this.format;
817
+ this.format = '';
818
+ this.getFormat();
819
+ const formatChanged = format !== this.format;
820
+ if (this.date && formatChanged) {
821
+ this.updateNativeValue();
822
+ }
823
+ }
824
+ }
825
+ validate(c) {
826
+ return this.validator(c);
827
+ }
828
+ registerOnChange(fn) {
829
+ this.onModelChange = fn;
830
+ }
831
+ registerOnTouched(fn) {
832
+ this.onTouched = fn;
833
+ }
834
+ registerOnValidatorChange(fn) {
835
+ this.validatorOnChange = fn;
836
+ }
837
+ setDisabledState(isDisabled) {
838
+ this.disabledNgControl.set(isDisabled);
839
+ this.stateChange.emit();
840
+ }
841
+ writeValue(value) {
842
+ // remove date when user input is empty
843
+ let emptyString = false;
844
+ // Flag to define invalid string
845
+ let invalidDate = false;
846
+ if (typeof value === 'string') {
847
+ emptyString = value.trim().length === 0;
848
+ value = parseDate(value, this.getFormat(), this.locale);
849
+ invalidDate = !value;
850
+ }
851
+ // Only emit changes to prevent that a destroyed output emit a value
852
+ if (this.date !== value) {
853
+ this.date = value;
854
+ this.dateChange.emit(this.date);
855
+ // We should not change the content of the input field when the user typed
856
+ // a wrong input. Otherwise the typed content changes and the user cannot
857
+ // correct the content.
858
+ if (!invalidDate || emptyString) {
859
+ this.updateNativeValue();
860
+ }
861
+ }
862
+ }
863
+ updateNativeValue() {
864
+ let dtStr = '';
865
+ if (isValid(this.date)) {
866
+ dtStr = formatDate(this.date, this.getFormat(), this.locale);
867
+ }
868
+ this.dateString.set(dtStr);
869
+ }
870
+ /**
871
+ * Handles `input` events on the input element.
872
+ * @param value - current input value.
873
+ */
874
+ onInput(value) {
875
+ const parsedDate = parseDate(value, this.getFormat(), this.locale);
876
+ // Is same date
877
+ const hasChanged = !(parsedDate === this.date);
878
+ if (hasChanged) {
879
+ this.date = parsedDate;
880
+ this.onModelChange(this.date);
881
+ this.dateChange.emit(this.date);
882
+ }
883
+ }
884
+ onBlur(event) {
885
+ this.onTouched();
886
+ }
887
+ getFormat() {
888
+ if (!this.format) {
889
+ this.format = getDatepickerFormat(this.locale, this.siDatepickerConfig());
890
+ }
891
+ return this.format;
892
+ }
893
+ /**
894
+ * Callback when the datepicker changes his value.
895
+ * @param date - updated date
896
+ */
897
+ onDateChanged(date) {
898
+ // update input element
899
+ this.writeValue(date);
900
+ // update the Forms ngModel
901
+ this.onModelChange(this.date);
902
+ }
903
+ /**
904
+ * Datepicker consider time / ignore time changed.
905
+ * @param disabledTime - disable time
906
+ * @internal
907
+ */
908
+ onDisabledTime(disabledTime) {
909
+ this.format = '';
910
+ // Temporary reset internal date to force an update with the new date format
911
+ const currentDate = this.date;
912
+ this.date = undefined;
913
+ this.siDatepickerConfig().disabledTime = disabledTime;
914
+ // Ensure the time format will be removed
915
+ this.onDateChanged(currentDate);
916
+ this.siDatepickerDisabledTime.emit(disabledTime);
917
+ }
918
+ /** The form control validator for date format */
919
+ formatValidator() {
920
+ const invalidFormat = this.date && isNaN(this.date.getTime());
921
+ return invalidFormat ? { dateFormat: { format: this.getFormat() } } : null;
922
+ }
923
+ /** The form control validator for the min date. */
924
+ minValidator() {
925
+ const controlValue = this.date;
926
+ const siDatepickerConfig = this.siDatepickerConfig();
927
+ const min = getMinDate(siDatepickerConfig?.minDate);
928
+ const withTime = siDatepickerConfig?.showTime;
929
+ return !min ||
930
+ !isValid(controlValue) ||
931
+ (withTime ? controlValue >= min : compareDate(controlValue, min) >= 0)
932
+ ? null
933
+ : { minDate: { min, actual: controlValue } };
934
+ }
935
+ /** The form control validator for the min date. */
936
+ maxValidator() {
937
+ const controlValue = this.date;
938
+ const siDatepickerConfig = this.siDatepickerConfig();
939
+ const max = getMaxDate(siDatepickerConfig?.maxDate);
940
+ const withTime = siDatepickerConfig?.showTime;
941
+ return !max ||
942
+ !isValid(controlValue) ||
943
+ (withTime ? controlValue <= max : compareDate(controlValue, max) <= 0)
944
+ ? null
945
+ : { maxDate: { max, actual: controlValue } };
946
+ }
947
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiDateInputDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
948
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.0.6", type: SiDateInputDirective, isStandalone: true, selector: "[siDateInput]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, siDatepickerConfig: { classPropertyName: "siDatepickerConfig", publicName: "siDatepickerConfig", isSignal: true, isRequired: false, transformFunction: null }, dateInputDebounceTime: { classPropertyName: "dateInputDebounceTime", publicName: "dateInputDebounceTime", 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 }, errormessageId: { classPropertyName: "errormessageId", publicName: "errormessageId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { siDatepickerConfig: "siDatepickerConfigChange", siDatepickerDisabledTime: "siDatepickerDisabledTime", stateChange: "stateChange", dateChange: "dateChange" }, host: { listeners: { "input": "onInput($event.target.value)", "blur": "onBlur($event)" }, properties: { "attr.id": "id()", "attr.disabled": "disabled() || null", "attr.readonly": "readonly() || null", "class.readonly": "readonly()", "attr.aria-describedby": "errormessageId()", "value": "dateString()" } }, providers: [
949
+ {
950
+ provide: NG_VALUE_ACCESSOR,
951
+ useExisting: SiDateInputDirective,
952
+ multi: true
953
+ },
954
+ {
955
+ provide: NG_VALIDATORS,
956
+ useExisting: SiDateInputDirective,
957
+ multi: true
958
+ },
959
+ {
960
+ provide: SI_FORM_ITEM_CONTROL,
961
+ useExisting: SiDateInputDirective
962
+ }
963
+ ], exportAs: ["siDateInput"], usesOnChanges: true, ngImport: i0 });
964
+ }
965
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiDateInputDirective, decorators: [{
966
+ type: Directive,
967
+ args: [{
968
+ selector: '[siDateInput]',
969
+ exportAs: 'siDateInput',
970
+ providers: [
971
+ {
972
+ provide: NG_VALUE_ACCESSOR,
973
+ useExisting: SiDateInputDirective,
974
+ multi: true
975
+ },
976
+ {
977
+ provide: NG_VALIDATORS,
978
+ useExisting: SiDateInputDirective,
979
+ multi: true
980
+ },
981
+ {
982
+ provide: SI_FORM_ITEM_CONTROL,
983
+ useExisting: SiDateInputDirective
984
+ }
985
+ ],
986
+ host: {
987
+ '[attr.id]': 'id()',
988
+ '[attr.disabled]': 'disabled() || null',
989
+ '[attr.readonly]': 'readonly() || null',
990
+ '[class.readonly]': 'readonly()',
991
+ '[attr.aria-describedby]': 'errormessageId()',
992
+ '[value]': 'dateString()'
993
+ }
994
+ }]
995
+ }], propDecorators: { onInput: [{
996
+ type: HostListener,
997
+ args: ['input', ['$event.target.value']]
998
+ }], onBlur: [{
999
+ type: HostListener,
1000
+ args: ['blur', ['$event']]
1001
+ }] } });
1002
+
1003
+ /**
1004
+ * Copyright Siemens 2016 - 2025.
1005
+ * SPDX-License-Identifier: MIT
1006
+ */
1007
+ class SiCalendarDateCellDirective {
1008
+ cell = input.required();
1009
+ compareAdapter = input.required();
1010
+ /** @defaultValue inject(ElementRef) */
1011
+ ref = inject(ElementRef);
1012
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiCalendarDateCellDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1013
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.0.6", type: SiCalendarDateCellDirective, isStandalone: true, selector: "[siCalendarDateCell]", inputs: { cell: { classPropertyName: "cell", publicName: "cell", isSignal: true, isRequired: true, transformFunction: null }, compareAdapter: { classPropertyName: "compareAdapter", publicName: "compareAdapter", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.aria-disabled": "cell().disabled", "class.disabled": "cell().disabled", "attr.aria-label": "cell().ariaLabel", "class.today": "this.cell().isToday", "attr.aria-current": "this.cell().isToday ? \"date\" : null" }, classAttribute: "si-calendar-date-cell" }, ngImport: i0 });
1014
+ }
1015
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiCalendarDateCellDirective, decorators: [{
1016
+ type: Directive,
1017
+ args: [{
1018
+ selector: '[siCalendarDateCell]',
1019
+ host: {
1020
+ class: 'si-calendar-date-cell',
1021
+ '[attr.aria-disabled]': 'cell().disabled',
1022
+ '[class.disabled]': 'cell().disabled',
1023
+ '[attr.aria-label]': 'cell().ariaLabel',
1024
+ '[class.today]': 'this.cell().isToday',
1025
+ '[attr.aria-current]': 'this.cell().isToday ? "date" : null'
1026
+ }
1027
+ }]
1028
+ }] });
1029
+
1030
+ /**
1031
+ * Copyright Siemens 2016 - 2025.
1032
+ * SPDX-License-Identifier: MIT
1033
+ */
1034
+ /**
1035
+ * Compare dates in the month view.
1036
+ */
1037
+ class DayCompareAdapter {
1038
+ isAfter(current, start) {
1039
+ return isAfter(current, start);
1040
+ }
1041
+ isBetween(current, from, to) {
1042
+ return isBetween(current, from, to);
1043
+ }
1044
+ isEqual(current, other) {
1045
+ return isSameDate(current, other);
1046
+ }
1047
+ isEqualOrBefore(current, other) {
1048
+ return isSameOrBefore(current, other);
1049
+ }
1050
+ isEqualOrBetween(current, from, to) {
1051
+ return isSameOrBetween(current, from, to);
1052
+ }
1053
+ }
1054
+ /**
1055
+ * Compare dates in the year view.
1056
+ */
1057
+ class MonthCompareAdapter {
1058
+ isAfter(current, start) {
1059
+ return isAfterMonth(current, start);
1060
+ }
1061
+ isBetween(current, from, to) {
1062
+ return isBetweenMonth(current, from, to);
1063
+ }
1064
+ isEqual(current, other) {
1065
+ return isSameMonth(current, other);
1066
+ }
1067
+ isEqualOrBefore(current, other) {
1068
+ return isSameOrBeforeMonth(current, other);
1069
+ }
1070
+ isEqualOrBetween(current, from, to) {
1071
+ return isSameOrBetweenMonth(current, from, to);
1072
+ }
1073
+ }
1074
+ class YearCompareAdapter {
1075
+ isAfter(current, other) {
1076
+ return isAfterYear(current, other);
1077
+ }
1078
+ isBetween(current, from, to) {
1079
+ return isBetweenYears(current, from, to);
1080
+ }
1081
+ isEqual(current, other) {
1082
+ return isSameYear(current, other);
1083
+ }
1084
+ isEqualOrBefore(current, other) {
1085
+ if (!other) {
1086
+ return false;
1087
+ }
1088
+ return isSameOrBeforeYear(current, other);
1089
+ }
1090
+ isEqualOrBetween(current, from, to) {
1091
+ return isSameOrBetweenYears(current, from, to);
1092
+ }
1093
+ }
1094
+
1095
+ /**
1096
+ * Copyright Siemens 2016 - 2025.
1097
+ * SPDX-License-Identifier: MIT
1098
+ */
1099
+ /**
1100
+ * Base interface for selections.
1101
+ */
1102
+ class SelectionStrategy {
1103
+ compare;
1104
+ constructor(compare) {
1105
+ this.compare = compare;
1106
+ }
1107
+ }
1108
+ /**
1109
+ * Strategy the handle single selection within the {@link SiCalendarBodyComponent}.
1110
+ */
1111
+ class SingleSelectionStrategy extends SelectionStrategy {
1112
+ isSelected(cell, start, end) {
1113
+ return this.compare.isEqual(cell.valueRaw, start);
1114
+ }
1115
+ inRange(cell, start, end) {
1116
+ return false;
1117
+ }
1118
+ isRangeSelected(cell, date) {
1119
+ return false;
1120
+ }
1121
+ previewRangeHover(cell, hoverCell, start) {
1122
+ return false;
1123
+ }
1124
+ previewRangeHoverEnd(cell, hoverCell, start) {
1125
+ return false;
1126
+ }
1127
+ }
1128
+ /**
1129
+ * Strategy the handle range selection within the {@link SiCalendarBodyComponent}.
1130
+ */
1131
+ class RangeSelectionStrategy extends SelectionStrategy {
1132
+ isSelected(cell, start, end) {
1133
+ return this.compare.isEqual(cell.valueRaw, start) || this.compare.isEqual(cell.valueRaw, end);
1134
+ }
1135
+ inRange(c, start, end) {
1136
+ if (!start || !end) {
1137
+ return false;
1138
+ }
1139
+ return this.compare.isBetween(c.valueRaw, start, end);
1140
+ }
1141
+ isRangeSelected(cell, date) {
1142
+ return this.compare.isEqual(cell.valueRaw, date);
1143
+ }
1144
+ previewRangeHover(cell, hoverCell, start) {
1145
+ if (!hoverCell || cell.disabled || !start) {
1146
+ return false;
1147
+ }
1148
+ return (this.compare.isAfter(cell.valueRaw, start) &&
1149
+ this.compare.isEqualOrBefore(cell.valueRaw, hoverCell.valueRaw));
1150
+ }
1151
+ previewRangeHoverEnd(cell, hoverCell, start) {
1152
+ if (!hoverCell || cell.disabled || !start) {
1153
+ return false;
1154
+ }
1155
+ return (this.compare.isAfter(cell.valueRaw, start) &&
1156
+ this.compare.isEqual(cell.valueRaw, hoverCell.valueRaw));
1157
+ }
1158
+ }
1159
+ class SiCalendarBodyComponent {
1160
+ /** The active date, the cell which will receive the focus. */
1161
+ focusedDate = model.required();
1162
+ /** The date which shall be indicated as currently selected. */
1163
+ startDate = input();
1164
+ /** Selected end value which is only considered with enableRangeSelection. */
1165
+ endDate = input();
1166
+ /**
1167
+ * The cells to display in the table.
1168
+ *
1169
+ * @defaultValue []
1170
+ */
1171
+ rows = input([]);
1172
+ /**
1173
+ * Labels for each row, which can be used to display the week number.
1174
+ * @defaultValue undefined
1175
+ */
1176
+ rowLabels = input(undefined);
1177
+ /**
1178
+ * Additional row label CSS class(es).
1179
+ *
1180
+ * @defaultValue []
1181
+ */
1182
+ rowLabelCssClasses = input([]);
1183
+ /**
1184
+ * Choose the selection strategy between single or range selection.
1185
+ * @defaultValue false
1186
+ */
1187
+ enableRangeSelection = input(false);
1188
+ /**
1189
+ * Indicate whether a range preview shall be displayed.
1190
+ * It's necessary since to display a preview also datepicker has a valid endDate.
1191
+ *
1192
+ * @defaultValue true
1193
+ */
1194
+ previewRange = input(true, { transform: booleanAttribute });
1195
+ /** The cell which which has the mouse hover. */
1196
+ activeHover = model();
1197
+ /**
1198
+ * Compare date functions which are necessary to compare a the dates according the current view.
1199
+ *
1200
+ * @defaultValue new DayCompareAdapter()
1201
+ */
1202
+ compareAdapter = input(new DayCompareAdapter());
1203
+ /** Emits when a user select a cell via click, space or enter. */
1204
+ selectedValueChange = output();
1205
+ calendarDateCells = viewChildren(SiCalendarDateCellDirective);
1206
+ selection = computed(() => this.enableRangeSelection()
1207
+ ? new RangeSelectionStrategy(this.compareAdapter())
1208
+ : new SingleSelectionStrategy(this.compareAdapter()));
1209
+ /**
1210
+ * Focus calendar cell which is marked as active cell.
1211
+ */
1212
+ focusActiveCell() {
1213
+ setTimeout(() => {
1214
+ const focusedDateCells = this.calendarDateCells().filter(dateCell => this.compareAdapter().isEqual(this.focusedDate(), dateCell.cell().valueRaw));
1215
+ if (focusedDateCells.length > 0) {
1216
+ focusedDateCells[0].ref.nativeElement.focus();
1217
+ }
1218
+ });
1219
+ }
1220
+ isActive(cell) {
1221
+ return this.compareAdapter().isEqual(this.focusedDate(), cell.valueRaw);
1222
+ }
1223
+ cellCss(cell) {
1224
+ return cell.cssClasses;
1225
+ }
1226
+ emitActiveHover(cell) {
1227
+ this.activeHover.set(cell);
1228
+ }
1229
+ emitSelectCell(selection) {
1230
+ if (selection.disabled) {
1231
+ return;
1232
+ }
1233
+ this.selectedValueChange.emit(selection.valueRaw);
1234
+ }
1235
+ emitActiveDateChange(cell) {
1236
+ if (!cell.disabled && !cell.isPreview) {
1237
+ // To provide a date-range preview it is necessary to maintain hoverCell also in case of keyboard usage
1238
+ this.emitActiveHover(cell);
1239
+ this.focusedDate.set(cell.valueRaw);
1240
+ }
1241
+ }
1242
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiCalendarBodyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1243
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: SiCalendarBodyComponent, isStandalone: true, selector: "[si-calendar-body]", inputs: { focusedDate: { classPropertyName: "focusedDate", publicName: "focusedDate", isSignal: true, isRequired: true, transformFunction: null }, startDate: { classPropertyName: "startDate", publicName: "startDate", isSignal: true, isRequired: false, transformFunction: null }, endDate: { classPropertyName: "endDate", publicName: "endDate", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, rowLabels: { classPropertyName: "rowLabels", publicName: "rowLabels", isSignal: true, isRequired: false, transformFunction: null }, rowLabelCssClasses: { classPropertyName: "rowLabelCssClasses", publicName: "rowLabelCssClasses", isSignal: true, isRequired: false, transformFunction: null }, enableRangeSelection: { classPropertyName: "enableRangeSelection", publicName: "enableRangeSelection", isSignal: true, isRequired: false, transformFunction: null }, previewRange: { classPropertyName: "previewRange", publicName: "previewRange", isSignal: true, isRequired: false, transformFunction: null }, activeHover: { classPropertyName: "activeHover", publicName: "activeHover", isSignal: true, isRequired: false, transformFunction: null }, compareAdapter: { classPropertyName: "compareAdapter", publicName: "compareAdapter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { focusedDate: "focusedDateChange", activeHover: "activeHoverChange", selectedValueChange: "selectedValueChange" }, host: { classAttribute: "si-calendar-body" }, viewQueries: [{ propertyName: "calendarDateCells", predicate: SiCalendarDateCellDirective, descendants: true, isSignal: true }], exportAs: ["siCalendarBody"], ngImport: i0, template: "@for (row of rows(); track rowIndex; let rowIndex = $index) {\n <tr role=\"row\">\n <!-- Typically used for week numbers -->\n @if (rowLabels()) {\n <td class=\"si-calendar-row-label\" [attr.data-row]=\"rowIndex\" [ngClass]=\"rowLabelCssClasses()\">\n {{ rowLabels()?.at(rowIndex) ?? '' }}\n </td>\n }\n @for (col of row; track colIndex; let colIndex = $index) {\n <td\n role=\"gridcell\"\n class=\"si-calendar-cell\"\n [attr.data-row]=\"rowIndex\"\n [attr.data-col]=\"colIndex\"\n [class.range-hover]=\"\n previewRange() && selection().previewRangeHover(col, activeHover(), startDate())\n \"\n [class.range-hover-end]=\"\n previewRange() && selection().previewRangeHoverEnd(col, activeHover(), startDate())\n \"\n [class.range]=\"selection().inRange(col, startDate(), endDate())\"\n [class.range-start]=\"selection().isRangeSelected(col, startDate())\"\n [class.range-end]=\"selection().isRangeSelected(col, endDate())\"\n >\n <button\n siCalendarDateCell\n type=\"button\"\n [cell]=\"col\"\n [compareAdapter]=\"compareAdapter()\"\n [ngClass]=\"cellCss(col)\"\n [attr.cdkFocusInitial]=\"isActive(col) ? '' : null\"\n [class.selected]=\"selection().isSelected(col, startDate(), endDate())\"\n [class.text-secondary]=\"\n col.isPreview &&\n !col.disabled &&\n !selection().isRangeSelected(col, startDate()) &&\n !selection().isRangeSelected(col, endDate()) &&\n !selection().inRange(col, startDate(), endDate())\n \"\n [tabindex]=\"isActive(col) ? '0' : '-1'\"\n (mouseover)=\"emitActiveHover(col)\"\n (click)=\"emitSelectCell(col)\"\n (focus)=\"emitActiveDateChange(col)\"\n >\n {{ col.displayValue }}\n </button>\n </td>\n }\n </tr>\n}\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: SiCalendarDateCellDirective, selector: "[siCalendarDateCell]", inputs: ["cell", "compareAdapter"] }] });
1244
+ }
1245
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiCalendarBodyComponent, decorators: [{
1246
+ type: Component,
1247
+ args: [{ selector: '[si-calendar-body]', exportAs: 'siCalendarBody', imports: [NgClass, A11yModule, SiCalendarDateCellDirective], host: {
1248
+ class: 'si-calendar-body'
1249
+ }, template: "@for (row of rows(); track rowIndex; let rowIndex = $index) {\n <tr role=\"row\">\n <!-- Typically used for week numbers -->\n @if (rowLabels()) {\n <td class=\"si-calendar-row-label\" [attr.data-row]=\"rowIndex\" [ngClass]=\"rowLabelCssClasses()\">\n {{ rowLabels()?.at(rowIndex) ?? '' }}\n </td>\n }\n @for (col of row; track colIndex; let colIndex = $index) {\n <td\n role=\"gridcell\"\n class=\"si-calendar-cell\"\n [attr.data-row]=\"rowIndex\"\n [attr.data-col]=\"colIndex\"\n [class.range-hover]=\"\n previewRange() && selection().previewRangeHover(col, activeHover(), startDate())\n \"\n [class.range-hover-end]=\"\n previewRange() && selection().previewRangeHoverEnd(col, activeHover(), startDate())\n \"\n [class.range]=\"selection().inRange(col, startDate(), endDate())\"\n [class.range-start]=\"selection().isRangeSelected(col, startDate())\"\n [class.range-end]=\"selection().isRangeSelected(col, endDate())\"\n >\n <button\n siCalendarDateCell\n type=\"button\"\n [cell]=\"col\"\n [compareAdapter]=\"compareAdapter()\"\n [ngClass]=\"cellCss(col)\"\n [attr.cdkFocusInitial]=\"isActive(col) ? '' : null\"\n [class.selected]=\"selection().isSelected(col, startDate(), endDate())\"\n [class.text-secondary]=\"\n col.isPreview &&\n !col.disabled &&\n !selection().isRangeSelected(col, startDate()) &&\n !selection().isRangeSelected(col, endDate()) &&\n !selection().inRange(col, startDate(), endDate())\n \"\n [tabindex]=\"isActive(col) ? '0' : '-1'\"\n (mouseover)=\"emitActiveHover(col)\"\n (click)=\"emitSelectCell(col)\"\n (focus)=\"emitActiveDateChange(col)\"\n >\n {{ col.displayValue }}\n </button>\n </td>\n }\n </tr>\n}\n" }]
1250
+ }] });
1251
+
1252
+ /**
1253
+ * Copyright Siemens 2016 - 2025.
1254
+ * SPDX-License-Identifier: MIT
1255
+ */
1256
+ class SiCalendarDirectionButtonComponent {
1257
+ ariaLabel = input.required();
1258
+ /** @defaultValue false */
1259
+ disabled = input(false, { transform: booleanAttribute });
1260
+ direction = input();
1261
+ /**
1262
+ * Emit on button click.
1263
+ */
1264
+ clicked = output();
1265
+ icon = computed(() => this.direction() === 'left' ? this.icons.elementLeft2 : this.icons.elementRight2);
1266
+ buttonClass = computed(() => this.direction() === 'left' ? 'previous-button' : 'next-button');
1267
+ icons = addIcons({ elementLeft2, elementRight2 });
1268
+ onClick() {
1269
+ this.clicked.emit();
1270
+ }
1271
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiCalendarDirectionButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1272
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.0.6", type: SiCalendarDirectionButtonComponent, isStandalone: true, selector: "si-calendar-direction-button", inputs: { ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: true, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked" }, ngImport: i0, template: `<button
1273
+ role="button"
1274
+ type="button"
1275
+ class="btn btn-circle btn-sm btn-tertiary"
1276
+ [ngClass]="buttonClass()"
1277
+ [disabled]="disabled() || null"
1278
+ [attr.aria-label]="ariaLabel()"
1279
+ (click)="onClick()"
1280
+ >
1281
+ <si-icon-next class="icon flip-rtl" [icon]="icon()" />
1282
+ </button>`, isInline: true, dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: SiIconNextComponent, selector: "si-icon-next", inputs: ["icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1283
+ }
1284
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiCalendarDirectionButtonComponent, decorators: [{
1285
+ type: Component,
1286
+ args: [{
1287
+ selector: 'si-calendar-direction-button',
1288
+ template: `<button
1289
+ role="button"
1290
+ type="button"
1291
+ class="btn btn-circle btn-sm btn-tertiary"
1292
+ [ngClass]="buttonClass()"
1293
+ [disabled]="disabled() || null"
1294
+ [attr.aria-label]="ariaLabel()"
1295
+ (click)="onClick()"
1296
+ >
1297
+ <si-icon-next class="icon flip-rtl" [icon]="icon()" />
1298
+ </button>`,
1299
+ changeDetection: ChangeDetectionStrategy.OnPush,
1300
+ imports: [NgClass, SiIconNextComponent]
1301
+ }]
1302
+ }] });
1303
+
1304
+ /**
1305
+ * Copyright Siemens 2016 - 2025.
1306
+ * SPDX-License-Identifier: MIT
1307
+ */
1308
+ /**
1309
+ * Helper directive to set the initial focus to the calendar body cell.
1310
+ */
1311
+ class SiInitialFocusComponent {
1312
+ /** The cell which has the mouse hover. */
1313
+ activeHover = model();
1314
+ /** The date which is displayed as selected. */
1315
+ startDate = input();
1316
+ /** The date which is displayed as selected end. The value is only considered with enableRangeSelection. */
1317
+ endDate = input();
1318
+ /**
1319
+ * Guard to set the focus during ngAfterViewInit, we just set the focus after we first initialized the view
1320
+ *
1321
+ * @defaultValue true
1322
+ */
1323
+ initialFocus = input(true);
1324
+ /** The minimum selectable date. */
1325
+ minDate = input();
1326
+ /** The maximum selectable date. */
1327
+ maxDate = input();
1328
+ /**
1329
+ * Optional input to control the minimum month the datepicker can show and the user can navigate.
1330
+ * The `minMonth` can be larger than the `minDate` This option enables the usage of multiple
1331
+ * datepickers next to each other while the more left calendar always
1332
+ * shows an earlier month the more right one.
1333
+ */
1334
+ minMonth = input();
1335
+ /**
1336
+ * Optional input to control the maximum month the datepicker can show and the user can navigate.
1337
+ * The `maxMonth` can be smaller than the `maxDate` This option enables the usage of multiple
1338
+ * datepickers next to each other while the more left calendar always
1339
+ * shows an earlier month the more right one.
1340
+ */
1341
+ maxMonth = input();
1342
+ /** Aria label for the next button. Needed for a11y. */
1343
+ previousLabel = input.required();
1344
+ /** Aria label for the next button. Needed for a11y. */
1345
+ nextLabel = input.required();
1346
+ /**
1347
+ * Is range selection enabled, when enabled it shows a preview between the startDate and the focused date.
1348
+ *
1349
+ * @defaultValue false
1350
+ */
1351
+ isRangeSelection = input(false, { transform: booleanAttribute });
1352
+ /**
1353
+ * Indicate whether a range preview shall be displayed.
1354
+ * When enabled a preview is visible between startDate and focusedDate.
1355
+ *
1356
+ * @defaultValue true
1357
+ */
1358
+ previewRange = input(true, { transform: booleanAttribute });
1359
+ /**
1360
+ * Emits when a new value is selected. In case where the value is null to
1361
+ * user aborted the selection by Escape.
1362
+ */
1363
+ selectedValueChange = output();
1364
+ /** The body of calendar table */
1365
+ calendarBody = viewChild.required(SiCalendarBodyComponent);
1366
+ ngAfterViewInit() {
1367
+ if (this.initialFocus()) {
1368
+ this.focusActiveCell();
1369
+ }
1370
+ }
1371
+ /**
1372
+ * Focus calendar cell which is marked as active cell.
1373
+ */
1374
+ focusActiveCell() {
1375
+ this.calendarBody().focusActiveCell();
1376
+ }
1377
+ onActiveHoverChange(event) {
1378
+ this.activeHover.set(event);
1379
+ }
1380
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiInitialFocusComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1381
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.0.6", type: SiInitialFocusComponent, isStandalone: true, selector: "ng-component", inputs: { activeHover: { classPropertyName: "activeHover", publicName: "activeHover", isSignal: true, isRequired: false, transformFunction: null }, startDate: { classPropertyName: "startDate", publicName: "startDate", isSignal: true, isRequired: false, transformFunction: null }, endDate: { classPropertyName: "endDate", publicName: "endDate", isSignal: true, isRequired: false, transformFunction: null }, initialFocus: { classPropertyName: "initialFocus", publicName: "initialFocus", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, minMonth: { classPropertyName: "minMonth", publicName: "minMonth", isSignal: true, isRequired: false, transformFunction: null }, maxMonth: { classPropertyName: "maxMonth", publicName: "maxMonth", isSignal: true, isRequired: false, transformFunction: null }, previousLabel: { classPropertyName: "previousLabel", publicName: "previousLabel", isSignal: true, isRequired: true, transformFunction: null }, nextLabel: { classPropertyName: "nextLabel", publicName: "nextLabel", isSignal: true, isRequired: true, transformFunction: null }, isRangeSelection: { classPropertyName: "isRangeSelection", publicName: "isRangeSelection", isSignal: true, isRequired: false, transformFunction: null }, previewRange: { classPropertyName: "previewRange", publicName: "previewRange", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeHover: "activeHoverChange", selectedValueChange: "selectedValueChange" }, viewQueries: [{ propertyName: "calendarBody", first: true, predicate: SiCalendarBodyComponent, descendants: true, isSignal: true }], ngImport: i0, template: '', isInline: true });
1382
+ }
1383
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiInitialFocusComponent, decorators: [{
1384
+ type: Component,
1385
+ args: [{
1386
+ template: ''
1387
+ }]
1388
+ }] });
1389
+
1390
+ /**
1391
+ * Copyright Siemens 2016 - 2025.
1392
+ * SPDX-License-Identifier: MIT
1393
+ */
1394
+ /**
1395
+ * Show dates of a single month as table and handles the keyboard interactions.
1396
+ * The focusedDate is handled according the keyboard interactions.
1397
+ */
1398
+ class SiDaySelectionComponent extends SiInitialFocusComponent {
1399
+ /**
1400
+ * Indicate whether the week numbers shall be hidden.
1401
+ *
1402
+ * @defaultValue false
1403
+ */
1404
+ hideWeekNumbers = input(false, { transform: booleanAttribute });
1405
+ /**
1406
+ * Defines the starting day of the week. Default is `monday`.
1407
+ *
1408
+ * @defaultValue 'monday'
1409
+ */
1410
+ weekStartDay = input('monday');
1411
+ /**
1412
+ * The active date, the cell which will receive the focus.
1413
+ * @defaultValue calendarUtils.today()
1414
+ */
1415
+ focusedDate = model.required();
1416
+ /** Today button text */
1417
+ todayLabel = input();
1418
+ /** Aria label for calendar week column */
1419
+ calenderWeekLabel = input();
1420
+ /** Emits when the active focused date changed to another month / year, typically during keyboard navigation */
1421
+ activeMonthChange = output();
1422
+ /** Emits when the user requests a different to show a different view */
1423
+ viewChange = output();
1424
+ /** The translated list of week days. */
1425
+ days = computed(() => getDayStrings(this.locale, this.weekStartDay()));
1426
+ /** The week numbers which are shown as row label */
1427
+ weekNumbers = computed(() => this.weeks().map(w => getWeekOfYear(w[0].valueRaw, this.weekStartDay()).toString()));
1428
+ /**
1429
+ * The current visible list of calendar days.
1430
+ * Every time the focusedDate changes to either another month or year the list will be rebuild.
1431
+ */
1432
+ weeks = computed(() => {
1433
+ const focusedDate = this.focusedDate();
1434
+ const monthStart = getFirstDateInMonth(focusedDate);
1435
+ const monthEnd = getLastDateInMonth(focusedDate);
1436
+ /**
1437
+ * We start the month with the first day in the week which has the effect that dates are
1438
+ * visible which aren't in the active month.
1439
+ */
1440
+ const startDate = getWeekStartDate(monthStart, this.weekStartDay());
1441
+ const minDate = this.minDate();
1442
+ const maxDate = this.maxDate();
1443
+ const weeks = [[], [], [], [], [], []];
1444
+ let weekIndex = 0;
1445
+ for (let i = 0, date = new Date(startDate); weeks[weeks.length - 1].length < 7; i++, date.setDate(date.getDate() + 1)) {
1446
+ if (i > 0 && i % 7 === 0) {
1447
+ weekIndex++;
1448
+ }
1449
+ const activeMonth = isSameOrBetween(date, monthStart, monthEnd);
1450
+ const isToday = isSameDate(date, today());
1451
+ const outOfRange = !isSameOrBetween(date, minDate, maxDate);
1452
+ weeks.at(weekIndex)?.push({
1453
+ value: date.getDate(),
1454
+ disabled: outOfRange,
1455
+ ariaLabel: date.toDateString(),
1456
+ displayValue: date.getDate().toString(),
1457
+ isPreview: !activeMonth,
1458
+ isToday,
1459
+ valueRaw: createDate(date),
1460
+ cssClasses: ['day', activeMonth ? 'si-title-1' : 'si-body-1']
1461
+ });
1462
+ }
1463
+ return weeks;
1464
+ });
1465
+ /** Compare date based on the current view */
1466
+ compareAdapter = new DayCompareAdapter();
1467
+ /** Disable today button if it is the same month */
1468
+ isTodayButtonDisabled = computed(() => isSameMonth(today(), this.focusedDate()));
1469
+ /**
1470
+ * Indicate the previous button shall be disabled.
1471
+ * This happens when the focusedDate is equal or before the minDate.
1472
+ */
1473
+ isPreviousButtonDisabled = computed(() => {
1474
+ const minDate = this.minDate();
1475
+ const focusedDate = this.focusedDate();
1476
+ return minDate && (isSameMonth(focusedDate, minDate) || isAfterMonth(minDate, focusedDate));
1477
+ });
1478
+ /**
1479
+ * Indicate the next button shall be disabled.
1480
+ * This happens when the focusedDate is equal or after the maxDate.
1481
+ */
1482
+ isNextButtonDisabled = computed(() => {
1483
+ const maxDate = this.maxDate();
1484
+ const focusedDate = this.focusedDate();
1485
+ return maxDate && (isSameMonth(focusedDate, maxDate) || isAfterMonth(focusedDate, maxDate));
1486
+ });
1487
+ locale = inject(LOCALE_ID).toString();
1488
+ calendarBodyKeyDown(event) {
1489
+ const isRtl = isRTL();
1490
+ switch (event.key) {
1491
+ case 'ArrowLeft':
1492
+ this.updateFocusedDateByDay(isRtl ? 1 : -1);
1493
+ break;
1494
+ case 'ArrowRight':
1495
+ this.updateFocusedDateByDay(isRtl ? -1 : 1);
1496
+ break;
1497
+ case 'ArrowUp':
1498
+ this.updateFocusedDateByDay(-7);
1499
+ break;
1500
+ case 'ArrowDown':
1501
+ this.updateFocusedDateByDay(7);
1502
+ break;
1503
+ case 'Home':
1504
+ this.updateFocusedDate(getWeekStartDate(this.focusedDate(), this.weekStartDay()));
1505
+ break;
1506
+ case 'End':
1507
+ this.updateFocusedDate(getWeekEndDate(this.focusedDate(), this.weekStartDay()));
1508
+ break;
1509
+ case 'PageDown':
1510
+ this.updateFocusedDateByMonth(1);
1511
+ break;
1512
+ case 'PageUp':
1513
+ this.updateFocusedDateByMonth(-1);
1514
+ break;
1515
+ case 'Enter':
1516
+ case 'Space':
1517
+ default:
1518
+ // Don't prevent default or focus active cell on keys that we don't explicitly handle.
1519
+ return;
1520
+ }
1521
+ // Prevent unexpected default actions such as form submission.
1522
+ event.preventDefault();
1523
+ }
1524
+ updateFocusedDateByDay(offset) {
1525
+ this.updateFocusedDate(addDaysInRange(this.focusedDate(), offset, this.minDate(), this.maxDate()));
1526
+ }
1527
+ updateFocusedDateByMonth(offset) {
1528
+ this.updateFocusedDate(addMonthsInRange(this.focusedDate(), offset, this.minDate(), this.maxDate()));
1529
+ }
1530
+ updateFocusedDate(newDate) {
1531
+ const prevDate = this.focusedDate();
1532
+ if (!isSameDate(prevDate, newDate)) {
1533
+ this.focusedDate.set(newDate);
1534
+ if (isAnotherMonthOrYear(newDate, prevDate)) {
1535
+ this.activeMonthChange.emit(newDate);
1536
+ }
1537
+ this.focusActiveCell();
1538
+ }
1539
+ }
1540
+ /**
1541
+ * Update month of focusedDate.
1542
+ * @param offset -1 or -1.
1543
+ */
1544
+ setMonthOffset(offset) {
1545
+ // Only update emit focusedDate since the focus shall stay on the button.
1546
+ const actualMonth = addMonthsInRange(this.focusedDate(), offset, this.minDate(), this.maxDate());
1547
+ this.focusedDate.set(actualMonth);
1548
+ this.activeMonthChange.emit(actualMonth);
1549
+ }
1550
+ /** Change the focusedDate to today */
1551
+ goToToday() {
1552
+ this.focusedDate.set(today());
1553
+ this.focusActiveCell();
1554
+ }
1555
+ emitSelectedValue(selected) {
1556
+ if (selected !== this.startDate() || selected !== this.endDate()) {
1557
+ this.selectedValueChange.emit(selected);
1558
+ }
1559
+ }
1560
+ emitActiveDate(active) {
1561
+ this.focusedDate.set(active);
1562
+ }
1563
+ emitViewChange(view) {
1564
+ this.viewChange.emit(view);
1565
+ }
1566
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiDaySelectionComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1567
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: SiDaySelectionComponent, isStandalone: true, selector: "si-day-selection", inputs: { hideWeekNumbers: { classPropertyName: "hideWeekNumbers", publicName: "hideWeekNumbers", isSignal: true, isRequired: false, transformFunction: null }, weekStartDay: { classPropertyName: "weekStartDay", publicName: "weekStartDay", isSignal: true, isRequired: false, transformFunction: null }, focusedDate: { classPropertyName: "focusedDate", publicName: "focusedDate", isSignal: true, isRequired: true, transformFunction: null }, todayLabel: { classPropertyName: "todayLabel", publicName: "todayLabel", isSignal: true, isRequired: false, transformFunction: null }, calenderWeekLabel: { classPropertyName: "calenderWeekLabel", publicName: "calenderWeekLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { focusedDate: "focusedDateChange", activeMonthChange: "activeMonthChange", viewChange: "viewChange" }, usesInheritance: true, ngImport: i0, template: "<div class=\"header\">\n <si-calendar-direction-button\n direction=\"left\"\n [ariaLabel]=\"previousLabel() | translate\"\n [disabled]=\"isPreviousButtonDisabled()\"\n (clicked)=\"setMonthOffset(-1)\"\n />\n <div class=\"flex-fill\">\n <button\n type=\"button\"\n class=\"open-month-view flex-fill text-end px-2 btn btn-tertiary calendar-button\"\n tabindex=\"0\"\n (click)=\"emitViewChange('month')\"\n >\n {{ focusedDate() | date: 'MMMM' }}\n </button>\n <button\n type=\"button\"\n class=\"open-year-view flex-fill text-start px-2 btn btn-tertiary calendar-button\"\n tabindex=\"0\"\n (click)=\"emitViewChange('year')\"\n >\n {{ focusedDate() | date: 'yyyy' }}\n </button>\n </div>\n <si-calendar-direction-button\n direction=\"right\"\n [ariaLabel]=\"nextLabel() | translate\"\n [disabled]=\"isNextButtonDisabled()\"\n (clicked)=\"setMonthOffset(1)\"\n />\n</div>\n<table class=\"px-9 mt-6\" role=\"grid\">\n <thead class=\"si-calendar-table-header\">\n <tr>\n @if (!hideWeekNumbers()) {\n <th scope=\"col\" class=\"week-num\">\n <span class=\"visually-hidden\">{{ calenderWeekLabel() | translate }}</span>\n </th>\n }\n @for (day of days(); track $index) {\n <th scope=\"col\">\n <span class=\"si-hidden-xs si-hidden-sm\">{{ day }}</span>\n </th>\n }\n </tr>\n </thead>\n <tbody\n si-calendar-body\n rowLabelCssClasses=\"week-num\"\n [focusedDate]=\"focusedDate()\"\n [compareAdapter]=\"compareAdapter\"\n [startDate]=\"startDate()\"\n [endDate]=\"endDate()\"\n [enableRangeSelection]=\"isRangeSelection()\"\n [previewRange]=\"previewRange()\"\n [rows]=\"weeks()\"\n [rowLabels]=\"hideWeekNumbers() ? undefined : weekNumbers()\"\n [activeHover]=\"activeHover()\"\n (activeHoverChange)=\"onActiveHoverChange($event)\"\n (selectedValueChange)=\"emitSelectedValue($event)\"\n (focusedDateChange)=\"emitActiveDate($event!)\"\n (keydown)=\"calendarBodyKeyDown($event)\"\n >\n </tbody>\n</table>\n<div class=\"footer pt-2 ps-8 pe-8\">\n <button\n type=\"button\"\n class=\"today-button btn btn-tertiary flex-fill\"\n [disabled]=\"isTodayButtonDisabled()\"\n (click)=\"goToToday()\"\n >\n {{ todayLabel() ?? 'Today' | translate }}\n </button>\n</div>\n", dependencies: [{ kind: "pipe", type: DatePipe, name: "date" }, { kind: "component", type: SiCalendarBodyComponent, selector: "[si-calendar-body]", inputs: ["focusedDate", "startDate", "endDate", "rows", "rowLabels", "rowLabelCssClasses", "enableRangeSelection", "previewRange", "activeHover", "compareAdapter"], outputs: ["focusedDateChange", "activeHoverChange", "selectedValueChange"], exportAs: ["siCalendarBody"] }, { kind: "component", type: SiCalendarDirectionButtonComponent, selector: "si-calendar-direction-button", inputs: ["ariaLabel", "disabled", "direction"], outputs: ["clicked"] }, { kind: "ngmodule", type: SiTranslateModule }, { kind: "pipe", type: i2.SiTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1568
+ }
1569
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiDaySelectionComponent, decorators: [{
1570
+ type: Component,
1571
+ args: [{ selector: 'si-day-selection', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
1572
+ DatePipe,
1573
+ SiCalendarBodyComponent,
1574
+ SiCalendarDirectionButtonComponent,
1575
+ SiTranslateModule
1576
+ ], template: "<div class=\"header\">\n <si-calendar-direction-button\n direction=\"left\"\n [ariaLabel]=\"previousLabel() | translate\"\n [disabled]=\"isPreviousButtonDisabled()\"\n (clicked)=\"setMonthOffset(-1)\"\n />\n <div class=\"flex-fill\">\n <button\n type=\"button\"\n class=\"open-month-view flex-fill text-end px-2 btn btn-tertiary calendar-button\"\n tabindex=\"0\"\n (click)=\"emitViewChange('month')\"\n >\n {{ focusedDate() | date: 'MMMM' }}\n </button>\n <button\n type=\"button\"\n class=\"open-year-view flex-fill text-start px-2 btn btn-tertiary calendar-button\"\n tabindex=\"0\"\n (click)=\"emitViewChange('year')\"\n >\n {{ focusedDate() | date: 'yyyy' }}\n </button>\n </div>\n <si-calendar-direction-button\n direction=\"right\"\n [ariaLabel]=\"nextLabel() | translate\"\n [disabled]=\"isNextButtonDisabled()\"\n (clicked)=\"setMonthOffset(1)\"\n />\n</div>\n<table class=\"px-9 mt-6\" role=\"grid\">\n <thead class=\"si-calendar-table-header\">\n <tr>\n @if (!hideWeekNumbers()) {\n <th scope=\"col\" class=\"week-num\">\n <span class=\"visually-hidden\">{{ calenderWeekLabel() | translate }}</span>\n </th>\n }\n @for (day of days(); track $index) {\n <th scope=\"col\">\n <span class=\"si-hidden-xs si-hidden-sm\">{{ day }}</span>\n </th>\n }\n </tr>\n </thead>\n <tbody\n si-calendar-body\n rowLabelCssClasses=\"week-num\"\n [focusedDate]=\"focusedDate()\"\n [compareAdapter]=\"compareAdapter\"\n [startDate]=\"startDate()\"\n [endDate]=\"endDate()\"\n [enableRangeSelection]=\"isRangeSelection()\"\n [previewRange]=\"previewRange()\"\n [rows]=\"weeks()\"\n [rowLabels]=\"hideWeekNumbers() ? undefined : weekNumbers()\"\n [activeHover]=\"activeHover()\"\n (activeHoverChange)=\"onActiveHoverChange($event)\"\n (selectedValueChange)=\"emitSelectedValue($event)\"\n (focusedDateChange)=\"emitActiveDate($event!)\"\n (keydown)=\"calendarBodyKeyDown($event)\"\n >\n </tbody>\n</table>\n<div class=\"footer pt-2 ps-8 pe-8\">\n <button\n type=\"button\"\n class=\"today-button btn btn-tertiary flex-fill\"\n [disabled]=\"isTodayButtonDisabled()\"\n (click)=\"goToToday()\"\n >\n {{ todayLabel() ?? 'Today' | translate }}\n </button>\n</div>\n" }]
1577
+ }] });
1578
+
1579
+ /**
1580
+ * Copyright Siemens 2016 - 2025.
1581
+ * SPDX-License-Identifier: MIT
1582
+ */
1583
+ /**
1584
+ * Show months of a single year as table and handles the keyboard interactions.
1585
+ * The focus and focusedDate is handled according the keyboard interactions.
1586
+ */
1587
+ class SiMonthSelectionComponent extends SiInitialFocusComponent {
1588
+ /**
1589
+ * The translated list of months.
1590
+ *
1591
+ * @defaultValue []
1592
+ */
1593
+ months = input([]);
1594
+ /**
1595
+ * The active date, the cell which will receive the focus.
1596
+ */
1597
+ focusedDate = model.required();
1598
+ /** Emits when the active focused date is changed to another month / year, typically during keyboard navigation. */
1599
+ activeMonthChange = output();
1600
+ /** Emits when the user requests a different to show a different view. */
1601
+ viewChange = output();
1602
+ /** Listen Escape event to switch view back */
1603
+ triggerEsc(event) {
1604
+ this.selectedValueChange.emit(null);
1605
+ event.preventDefault();
1606
+ event.stopPropagation(); // Prevents the overlay from closing.
1607
+ }
1608
+ /**
1609
+ * The current visible list of calendar months.
1610
+ * Every time the focusedDate changes to another year the list will update.
1611
+ */
1612
+ monthCells = [];
1613
+ compareAdapter = new MonthCompareAdapter();
1614
+ /** Number of column before the row is wrapped */
1615
+ columnCount = 2;
1616
+ /**
1617
+ * Indicate the previous button shall be disabled.
1618
+ * This happens when the focusedDate is equal or before the minDate.
1619
+ */
1620
+ isPreviousButtonDisabled = computed(() => {
1621
+ const minDate = this.minDate();
1622
+ const focusedDate = this.focusedDate();
1623
+ return minDate && (isSameYear(focusedDate, minDate) || isAfterYear(minDate, focusedDate));
1624
+ });
1625
+ /**
1626
+ * Indicate the next button shall be disabled.
1627
+ * This happens when the focusedDate is equal or after the maxDate.
1628
+ */
1629
+ isNextButtonDisabled = computed(() => {
1630
+ const maxDate = this.maxDate();
1631
+ const focusedDate = this.focusedDate();
1632
+ return maxDate && (isSameYear(focusedDate, maxDate) || isAfterYear(focusedDate, maxDate));
1633
+ });
1634
+ ngOnChanges(changes) {
1635
+ if (changes.maxDate ||
1636
+ changes.minDate ||
1637
+ changes.maxMonth ||
1638
+ changes.minMonth ||
1639
+ changes.focusedDate) {
1640
+ this.initView();
1641
+ }
1642
+ }
1643
+ calendarBodyKeyDown(event) {
1644
+ const isRtl = isRTL();
1645
+ switch (event.key) {
1646
+ case 'ArrowLeft':
1647
+ this.updateFocusedDate(isRtl ? 1 : -1);
1648
+ break;
1649
+ case 'ArrowRight':
1650
+ this.updateFocusedDate(isRtl ? -1 : 1);
1651
+ break;
1652
+ case 'ArrowUp':
1653
+ this.updateFocusedDate(-1 * this.columnCount);
1654
+ break;
1655
+ case 'ArrowDown':
1656
+ this.updateFocusedDate(this.columnCount);
1657
+ break;
1658
+ case 'Escape':
1659
+ this.selectedValueChange.emit(null);
1660
+ event.preventDefault();
1661
+ event.stopPropagation(); // Prevents the overlay from closing.
1662
+ return;
1663
+ case 'Enter':
1664
+ case 'Space':
1665
+ default:
1666
+ // Don't prevent default or focus active cell on keys that we don't explicitly handle.
1667
+ return;
1668
+ }
1669
+ // Prevent unexpected default actions such as form submission.
1670
+ event.preventDefault();
1671
+ }
1672
+ updateFocusedDate(offset) {
1673
+ const prevDate = this.focusedDate();
1674
+ const newDate = addMonthsInRange(prevDate, offset, this.minDate(), this.maxDate());
1675
+ this.focusedDate.set(newDate);
1676
+ if (!this.compareAdapter.isEqual(prevDate, newDate)) {
1677
+ // Synchronize focusedDate with year view
1678
+ this.focusActiveCell();
1679
+ this.emitActiveMonthChange(newDate, prevDate);
1680
+ }
1681
+ }
1682
+ /**
1683
+ * Add offset to year and update focusedDate.
1684
+ */
1685
+ setYearOffset(offset) {
1686
+ const prevDate = this.focusedDate();
1687
+ const newActive = createDate(prevDate);
1688
+ newActive.setFullYear(newActive.getFullYear() + offset);
1689
+ this.focusedDate.set(newActive);
1690
+ this.emitActiveMonthChange(newActive, prevDate);
1691
+ }
1692
+ emitSelectedValue(selected) {
1693
+ this.selectedValueChange.emit(selected);
1694
+ }
1695
+ emitFocusedDate(focused) {
1696
+ // Take over the current day on month changes
1697
+ focused.setDate(this.focusedDate().getDate());
1698
+ this.focusedDate.set(focused);
1699
+ }
1700
+ emitActiveMonthChange(focus, prevFocus) {
1701
+ if (isAnotherYear(focus, prevFocus)) {
1702
+ this.activeMonthChange.emit(focus);
1703
+ }
1704
+ }
1705
+ emitViewChange() {
1706
+ this.viewChange.emit('year');
1707
+ }
1708
+ /**
1709
+ * Initialize view based on the focusedDate.
1710
+ */
1711
+ initView() {
1712
+ this.monthCells = [];
1713
+ let row = [];
1714
+ // The cell date object needs to be the first to prevent that we jump to the next month when
1715
+ // setting the month. For example the focusedDate is 31. setting february would result in the
1716
+ // 3. March.
1717
+ const startDate = getFirstDateInYear(this.focusedDate());
1718
+ const today$1 = today();
1719
+ const months = this.months();
1720
+ for (let i = 0; i <= 11; i++) {
1721
+ if (i > 0 && i % this.columnCount === 0) {
1722
+ this.monthCells.push(row);
1723
+ row = [];
1724
+ }
1725
+ const date = new Date(startDate);
1726
+ date.setMonth(i);
1727
+ const isToday = this.compareAdapter.isEqual(date, today$1);
1728
+ const isDisabled = !this.compareAdapter.isEqualOrBetween(date, this.minDate(), this.maxDate());
1729
+ row.push({
1730
+ value: date.getDate(),
1731
+ disabled: isDisabled,
1732
+ ariaLabel: `${months[date.getMonth()]} ${this.focusedDate().getFullYear()}`,
1733
+ displayValue: months[date.getMonth()],
1734
+ isPreview: false,
1735
+ isToday,
1736
+ valueRaw: createDate(date),
1737
+ cssClasses: ['month', 'si-title-1', 'text-truncate']
1738
+ });
1739
+ }
1740
+ this.monthCells.push(row);
1741
+ }
1742
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiMonthSelectionComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1743
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.0.6", type: SiMonthSelectionComponent, isStandalone: true, selector: "si-month-selection", inputs: { months: { classPropertyName: "months", publicName: "months", isSignal: true, isRequired: false, transformFunction: null }, focusedDate: { classPropertyName: "focusedDate", publicName: "focusedDate", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { focusedDate: "focusedDateChange", activeMonthChange: "activeMonthChange", viewChange: "viewChange" }, host: { listeners: { "keydown.Escape": "triggerEsc($event)" } }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div class=\"header\">\n <si-calendar-direction-button\n direction=\"left\"\n [ariaLabel]=\"previousLabel()\"\n [disabled]=\"isPreviousButtonDisabled()\"\n (clicked)=\"setYearOffset(-1)\"\n />\n <button\n type=\"button\"\n class=\"open-year-view flex-fill mx-4 btn btn-tertiary calendar-button\"\n tabindex=\"0\"\n (click)=\"emitViewChange()\"\n >\n {{ focusedDate() | date: 'yyyy' }}\n </button>\n <si-calendar-direction-button\n direction=\"right\"\n [ariaLabel]=\"nextLabel()\"\n [disabled]=\"isNextButtonDisabled()\"\n (clicked)=\"setYearOffset(1)\"\n />\n</div>\n<table class=\"px-9 mt-6\" role=\"grid\">\n <tbody\n si-calendar-body\n [focusedDate]=\"focusedDate()\"\n [compareAdapter]=\"compareAdapter\"\n [startDate]=\"startDate()\"\n [endDate]=\"endDate()\"\n [enableRangeSelection]=\"isRangeSelection()\"\n [previewRange]=\"previewRange()\"\n [rows]=\"monthCells\"\n [activeHover]=\"activeHover()\"\n (activeHoverChange)=\"onActiveHoverChange($event)\"\n (selectedValueChange)=\"emitSelectedValue($event)\"\n (focusedDateChange)=\"emitFocusedDate($event)\"\n (keydown)=\"calendarBodyKeyDown($event)\"\n >\n </tbody>\n</table>\n", dependencies: [{ kind: "component", type: SiCalendarDirectionButtonComponent, selector: "si-calendar-direction-button", inputs: ["ariaLabel", "disabled", "direction"], outputs: ["clicked"] }, { kind: "component", type: SiCalendarBodyComponent, selector: "[si-calendar-body]", inputs: ["focusedDate", "startDate", "endDate", "rows", "rowLabels", "rowLabelCssClasses", "enableRangeSelection", "previewRange", "activeHover", "compareAdapter"], outputs: ["focusedDateChange", "activeHoverChange", "selectedValueChange"], exportAs: ["siCalendarBody"] }, { kind: "pipe", type: DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1744
+ }
1745
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiMonthSelectionComponent, decorators: [{
1746
+ type: Component,
1747
+ args: [{ selector: 'si-month-selection', changeDetection: ChangeDetectionStrategy.OnPush, imports: [SiCalendarDirectionButtonComponent, SiCalendarBodyComponent, DatePipe], template: "<div class=\"header\">\n <si-calendar-direction-button\n direction=\"left\"\n [ariaLabel]=\"previousLabel()\"\n [disabled]=\"isPreviousButtonDisabled()\"\n (clicked)=\"setYearOffset(-1)\"\n />\n <button\n type=\"button\"\n class=\"open-year-view flex-fill mx-4 btn btn-tertiary calendar-button\"\n tabindex=\"0\"\n (click)=\"emitViewChange()\"\n >\n {{ focusedDate() | date: 'yyyy' }}\n </button>\n <si-calendar-direction-button\n direction=\"right\"\n [ariaLabel]=\"nextLabel()\"\n [disabled]=\"isNextButtonDisabled()\"\n (clicked)=\"setYearOffset(1)\"\n />\n</div>\n<table class=\"px-9 mt-6\" role=\"grid\">\n <tbody\n si-calendar-body\n [focusedDate]=\"focusedDate()\"\n [compareAdapter]=\"compareAdapter\"\n [startDate]=\"startDate()\"\n [endDate]=\"endDate()\"\n [enableRangeSelection]=\"isRangeSelection()\"\n [previewRange]=\"previewRange()\"\n [rows]=\"monthCells\"\n [activeHover]=\"activeHover()\"\n (activeHoverChange)=\"onActiveHoverChange($event)\"\n (selectedValueChange)=\"emitSelectedValue($event)\"\n (focusedDateChange)=\"emitFocusedDate($event)\"\n (keydown)=\"calendarBodyKeyDown($event)\"\n >\n </tbody>\n</table>\n" }]
1748
+ }], propDecorators: { triggerEsc: [{
1749
+ type: HostListener,
1750
+ args: ['keydown.Escape', ['$event']]
1751
+ }] } });
1752
+
1753
+ /**
1754
+ * Copyright Siemens 2016 - 2025.
1755
+ * SPDX-License-Identifier: MIT
1756
+ */
1757
+ /**
1758
+ * Show months of a single year as table and handles the keyboard interactions.
1759
+ * The focus and focusedDate is handled according the keyboard interactions.
1760
+ */
1761
+ class SiYearSelectionComponent extends SiInitialFocusComponent {
1762
+ /**
1763
+ * The active date, the cell which will receive the focus.
1764
+ */
1765
+ focusedDate = model.required();
1766
+ /** Emits when the active focused date changed to another month / year, typically during keyboard navigation. */
1767
+ yearRangeChange = output();
1768
+ /** Listen Escape event to switch view back */
1769
+ triggerEsc(event) {
1770
+ this.selectedValueChange.emit(null);
1771
+ event.preventDefault();
1772
+ event.stopPropagation(); // Prevents the overlay from closing.
1773
+ }
1774
+ /** Number of column before the row is wrapped */
1775
+ columnCount = 3;
1776
+ /** The number of years which shall be displayed, this number should be even and dividable by columnCount */
1777
+ yearsToDisplay = 18;
1778
+ /** Lower windows bound for displayed year range */
1779
+ fromYear = signal(undefined);
1780
+ /** Upper windows bound for displayed year range */
1781
+ toYear = signal(undefined);
1782
+ /**
1783
+ * The current visible list of calendar years.
1784
+ * Every time the focusedDate changes to another year the list will be rebuilt.
1785
+ */
1786
+ yearCells = [];
1787
+ compareAdapter = new YearCompareAdapter();
1788
+ /** Is previous button disabled based on the minDate. */
1789
+ isPreviousButtonDisabled = computed(() => {
1790
+ const minDate$1 = this.minDate();
1791
+ const minMonth = this.minMonth();
1792
+ if (!minDate$1 && !minMonth) {
1793
+ return false;
1794
+ }
1795
+ const min = minDate(minDate$1, minMonth);
1796
+ return (this.compareAdapter.isEqual(this.fromYear(), min) ||
1797
+ this.compareAdapter.isAfter(min, this.fromYear()));
1798
+ });
1799
+ /** Is next button disabled based on the maxDate */
1800
+ isNextButtonDisabled = computed(() => {
1801
+ const maxDate = this.maxDate();
1802
+ if (!maxDate) {
1803
+ return false;
1804
+ }
1805
+ return (this.compareAdapter.isEqual(this.toYear(), maxDate) ||
1806
+ this.compareAdapter.isAfter(this.toYear(), maxDate));
1807
+ });
1808
+ ngOnChanges(changes) {
1809
+ if (changes.startDate || changes.focusedDate || changes.maxDate || changes.minDate) {
1810
+ this.initView();
1811
+ }
1812
+ }
1813
+ calendarBodyKeyDown(event) {
1814
+ const isRtl = isRTL();
1815
+ const oldActiveDate = this.focusedDate();
1816
+ switch (event.key) {
1817
+ case 'ArrowLeft':
1818
+ this.setYearOffset(isRtl ? 1 : -1);
1819
+ break;
1820
+ case 'ArrowRight':
1821
+ this.setYearOffset(isRtl ? -1 : 1);
1822
+ break;
1823
+ case 'ArrowUp':
1824
+ this.setYearOffset(-1 * this.columnCount);
1825
+ break;
1826
+ case 'ArrowDown':
1827
+ this.setYearOffset(this.columnCount);
1828
+ break;
1829
+ case 'PageUp':
1830
+ this.setYearOffset(-1 * (oldActiveDate.getFullYear() - this.fromYear().getFullYear()));
1831
+ break;
1832
+ case 'PageDown':
1833
+ this.setYearOffset(this.toYear().getFullYear() - oldActiveDate.getFullYear());
1834
+ break;
1835
+ case 'Escape':
1836
+ this.selectedValueChange.emit(null);
1837
+ event.preventDefault();
1838
+ event.stopPropagation(); // Prevents the overlay from closing.
1839
+ return;
1840
+ case 'Enter':
1841
+ case 'Space':
1842
+ default:
1843
+ // Don't prevent default or focus active cell on keys that we don't explicitly handle.
1844
+ return;
1845
+ }
1846
+ if (!this.compareAdapter.isEqual(oldActiveDate, this.focusedDate())) {
1847
+ this.focusActiveCell();
1848
+ }
1849
+ // Prevent unexpected default actions such as form submission.
1850
+ event.preventDefault();
1851
+ }
1852
+ /**
1853
+ * Change the active date and the range of displayed years.
1854
+ * The windowOffset control the amount of ranges the view shall move forward or backward.
1855
+ * The number of displayed years ia controlled by yearsToDisplay.
1856
+ */
1857
+ changeVisibleYearRange(windowOffset) {
1858
+ const offset = windowOffset * this.yearsToDisplay;
1859
+ this.setYearOffset(offset);
1860
+ }
1861
+ emitSelectedValue(selected) {
1862
+ this.selectedValueChange.emit(selected);
1863
+ }
1864
+ /**
1865
+ * Determine the year range start and end year.
1866
+ * - Based on the active date this function will find the start and
1867
+ * ending year of the current displayed range.
1868
+ * - In case the focusedDate is either before or after the current range the
1869
+ * start and end year will move the entire window (yearsToDisplay)
1870
+ */
1871
+ initYearRange() {
1872
+ // Did we exceed the display current displayed year range
1873
+ let changed = false;
1874
+ const focusedDate = this.focusedDate();
1875
+ const fromYear = this.fromYear();
1876
+ const toYear = this.toYear();
1877
+ if (!fromYear || !toYear) {
1878
+ const start = focusedDate.getFullYear() - this.yearsToDisplay / 2;
1879
+ this.fromYear.set(new Date(start, 0, 1));
1880
+ this.toYear.set(new Date(start + this.yearsToDisplay - 1, 0, 1));
1881
+ changed = true;
1882
+ }
1883
+ else if (this.compareAdapter.isAfter(focusedDate, toYear)) {
1884
+ // Change window forward
1885
+ const rangeDistance = Math.floor(Math.abs(focusedDate.getFullYear() - fromYear.getFullYear()) / this.yearsToDisplay);
1886
+ const newFromYear = fromYear.getFullYear() + rangeDistance * this.yearsToDisplay;
1887
+ this.fromYear.set(new Date(newFromYear, 0, 1));
1888
+ this.toYear.set(new Date(newFromYear + this.yearsToDisplay - 1, 0, 1));
1889
+ changed = true;
1890
+ }
1891
+ else if (this.compareAdapter.isAfter(fromYear, focusedDate)) {
1892
+ // Change window backwards
1893
+ const rangeDistance = Math.ceil(Math.abs(focusedDate.getFullYear() - fromYear.getFullYear()) / this.yearsToDisplay);
1894
+ const newFromYear = fromYear.getFullYear() - rangeDistance * this.yearsToDisplay;
1895
+ this.fromYear.set(new Date(newFromYear, 0, 1));
1896
+ this.toYear.set(new Date(newFromYear + this.yearsToDisplay - 1, 0, 1));
1897
+ changed = true;
1898
+ }
1899
+ if (changed) {
1900
+ this.yearRangeChange.emit([this.fromYear(), this.toYear()]);
1901
+ }
1902
+ }
1903
+ /**
1904
+ * Initialize view based on the focusedDate.
1905
+ */
1906
+ initView() {
1907
+ // Initial year limits
1908
+ this.initYearRange();
1909
+ this.yearCells = [];
1910
+ let row = [];
1911
+ // The cell date object needs to be the first to prevent that we jump to the next month when
1912
+ // setting the month. For example the focusedDate is 31. setting february would result in the
1913
+ // 3. March.
1914
+ const startDate = getFirstDateInYear(this.fromYear());
1915
+ const today$1 = today();
1916
+ for (let i = 0; i < this.yearsToDisplay; i++) {
1917
+ if (i > 0 && i % this.columnCount === 0) {
1918
+ this.yearCells.push(row);
1919
+ row = [];
1920
+ }
1921
+ const date = createDate(startDate);
1922
+ date.setFullYear(date.getFullYear() + i);
1923
+ const isToday = this.compareAdapter.isEqual(date, today$1);
1924
+ const isDisabled = !this.compareAdapter.isEqualOrBetween(date, this.minDate(), this.maxDate());
1925
+ const year = date.getFullYear().toString();
1926
+ row.push({
1927
+ value: date.getDate(),
1928
+ disabled: isDisabled,
1929
+ ariaLabel: year,
1930
+ displayValue: year,
1931
+ isPreview: false,
1932
+ isToday,
1933
+ valueRaw: createDate(date),
1934
+ cssClasses: ['year', 'si-title-1']
1935
+ });
1936
+ }
1937
+ this.yearCells.push(row);
1938
+ }
1939
+ /**
1940
+ * Add offset to year and update focusedDate.
1941
+ * If the new year is outside min/max date the year will set to the closest year in range.
1942
+ */
1943
+ setYearOffset(offset) {
1944
+ const newActive = addYearsInRange(this.focusedDate(), offset, this.minDate(), this.maxDate());
1945
+ this.focusedDate.set(newActive);
1946
+ if (!this.fromYear() || !isBetween(this.focusedDate(), this.fromYear(), this.toYear())) {
1947
+ // Re-calc years view
1948
+ this.initView();
1949
+ }
1950
+ }
1951
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiYearSelectionComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1952
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.0.6", type: SiYearSelectionComponent, isStandalone: true, selector: "si-year-selection", inputs: { focusedDate: { classPropertyName: "focusedDate", publicName: "focusedDate", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { focusedDate: "focusedDateChange", yearRangeChange: "yearRangeChange" }, host: { listeners: { "keydown.Escape": "triggerEsc($event)" } }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div class=\"header\">\n <si-calendar-direction-button\n direction=\"left\"\n [ariaLabel]=\"previousLabel()\"\n [disabled]=\"isPreviousButtonDisabled()\"\n (clicked)=\"changeVisibleYearRange(-1)\"\n />\n <span class=\"year-range-label flex-fill mx-4 si-title-1 text-secondary calendar-button\">\n {{ fromYear() | date: 'yyyy' }} - {{ toYear() | date: 'yyyy' }}\n </span>\n <si-calendar-direction-button\n direction=\"right\"\n [ariaLabel]=\"nextLabel()\"\n [disabled]=\"isNextButtonDisabled()\"\n (clicked)=\"changeVisibleYearRange(1)\"\n />\n</div>\n<table class=\"px-9 mt-6\" role=\"grid\">\n <tbody\n si-calendar-body\n [focusedDate]=\"focusedDate()\"\n [compareAdapter]=\"compareAdapter\"\n [startDate]=\"startDate()\"\n [endDate]=\"endDate()\"\n [enableRangeSelection]=\"isRangeSelection()\"\n [previewRange]=\"previewRange()\"\n [rows]=\"yearCells\"\n (selectedValueChange)=\"emitSelectedValue($event)\"\n (keydown)=\"calendarBodyKeyDown($event)\"\n >\n </tbody>\n</table>\n", dependencies: [{ kind: "component", type: SiCalendarDirectionButtonComponent, selector: "si-calendar-direction-button", inputs: ["ariaLabel", "disabled", "direction"], outputs: ["clicked"] }, { kind: "component", type: SiCalendarBodyComponent, selector: "[si-calendar-body]", inputs: ["focusedDate", "startDate", "endDate", "rows", "rowLabels", "rowLabelCssClasses", "enableRangeSelection", "previewRange", "activeHover", "compareAdapter"], outputs: ["focusedDateChange", "activeHoverChange", "selectedValueChange"], exportAs: ["siCalendarBody"] }, { kind: "pipe", type: DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1953
+ }
1954
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiYearSelectionComponent, decorators: [{
1955
+ type: Component,
1956
+ args: [{ selector: 'si-year-selection', changeDetection: ChangeDetectionStrategy.OnPush, imports: [SiCalendarDirectionButtonComponent, SiCalendarBodyComponent, DatePipe], template: "<div class=\"header\">\n <si-calendar-direction-button\n direction=\"left\"\n [ariaLabel]=\"previousLabel()\"\n [disabled]=\"isPreviousButtonDisabled()\"\n (clicked)=\"changeVisibleYearRange(-1)\"\n />\n <span class=\"year-range-label flex-fill mx-4 si-title-1 text-secondary calendar-button\">\n {{ fromYear() | date: 'yyyy' }} - {{ toYear() | date: 'yyyy' }}\n </span>\n <si-calendar-direction-button\n direction=\"right\"\n [ariaLabel]=\"nextLabel()\"\n [disabled]=\"isNextButtonDisabled()\"\n (clicked)=\"changeVisibleYearRange(1)\"\n />\n</div>\n<table class=\"px-9 mt-6\" role=\"grid\">\n <tbody\n si-calendar-body\n [focusedDate]=\"focusedDate()\"\n [compareAdapter]=\"compareAdapter\"\n [startDate]=\"startDate()\"\n [endDate]=\"endDate()\"\n [enableRangeSelection]=\"isRangeSelection()\"\n [previewRange]=\"previewRange()\"\n [rows]=\"yearCells\"\n (selectedValueChange)=\"emitSelectedValue($event)\"\n (keydown)=\"calendarBodyKeyDown($event)\"\n >\n </tbody>\n</table>\n" }]
1957
+ }], propDecorators: { triggerEsc: [{
1958
+ type: HostListener,
1959
+ args: ['keydown.Escape', ['$event']]
1960
+ }] } });
1961
+
1962
+ /**
1963
+ * Copyright Siemens 2016 - 2025.
1964
+ * SPDX-License-Identifier: MIT
1965
+ */
1966
+ class SiTimepickerComponent {
1967
+ static idCounter = 0;
1968
+ /** @internal */
1969
+ invalidHours = false;
1970
+ /** @internal */
1971
+ invalidMinutes = false;
1972
+ /** @internal */
1973
+ invalidSeconds = false;
1974
+ /** @internal */
1975
+ invalidMilliseconds = false;
1976
+ /**
1977
+ * @defaultValue
1978
+ * ```
1979
+ * `__si-timepicker-${SiTimepickerComponent.idCounter++}`
1980
+ * ```
1981
+ */
1982
+ id = input(`__si-timepicker-${SiTimepickerComponent.idCounter++}`);
1983
+ labelledby = inject(new HostAttributeToken('aria-labelledby'), {
1984
+ optional: true
1985
+ }) ?? `${this.id()}-label`;
1986
+ /**
1987
+ * All input fields will be disabled if set to true.
1988
+ *
1989
+ * @defaultValue false
1990
+ */
1991
+ // eslint-disable-next-line @angular-eslint/no-input-rename
1992
+ disabledInput = input(false, { alias: 'disabled' });
1993
+ /**
1994
+ * @defaultValue 'hh'
1995
+ */
1996
+ hoursLabel = input('hh');
1997
+ /**
1998
+ * @defaultValue 'mm'
1999
+ */
2000
+ minutesLabel = input('mm');
2001
+ /**
2002
+ * @defaultValue 'ss'
2003
+ */
2004
+ secondsLabel = input('ss');
2005
+ /**
2006
+ * @defaultValue 'ms'
2007
+ */
2008
+ millisecondsLabel = input('ms');
2009
+ /**
2010
+ * Hide the labels of the input fields.
2011
+ * @defaultValue false
2012
+ */
2013
+ hideLabels = input(false, { transform: booleanAttribute });
2014
+ /**
2015
+ * @defaultValue
2016
+ * ```
2017
+ * $localize`:@@SI_DATEPICKER.HOURS:Hours`
2018
+ * ```
2019
+ */
2020
+ hoursAriaLabel = input($localize `:@@SI_DATEPICKER.HOURS:Hours`);
2021
+ /**
2022
+ * @defaultValue
2023
+ * ```
2024
+ * $localize`:@@SI_DATEPICKER.MINUTES:Minutes`
2025
+ * ```
2026
+ */
2027
+ minutesAriaLabel = input($localize `:@@SI_DATEPICKER.MINUTES:Minutes`);
2028
+ /**
2029
+ * @defaultValue
2030
+ * ```
2031
+ * $localize`:@@SI_DATEPICKER.SECONDS:Seconds`
2032
+ * ```
2033
+ */
2034
+ secondsAriaLabel = input($localize `:@@SI_DATEPICKER.SECONDS:Seconds`);
2035
+ /**
2036
+ * @defaultValue
2037
+ * ```
2038
+ * $localize`:@@SI_DATEPICKER.MILLISECONDS:Milliseconds`
2039
+ * ```
2040
+ */
2041
+ millisecondsAriaLabel = input($localize `:@@SI_DATEPICKER.MILLISECONDS:Milliseconds`);
2042
+ /**
2043
+ * @defaultValue 'hh'
2044
+ */
2045
+ hoursPlaceholder = input('hh');
2046
+ /**
2047
+ * @defaultValue 'mm'
2048
+ */
2049
+ minutesPlaceholder = input('mm');
2050
+ /**
2051
+ * @defaultValue 'ss'
2052
+ */
2053
+ secondsPlaceholder = input('ss');
2054
+ /**
2055
+ * @defaultValue 'ms'
2056
+ */
2057
+ millisecondsPlaceholder = input('ms');
2058
+ meridians = input();
2059
+ /**
2060
+ * @defaultValue 'am/pm'
2061
+ */
2062
+ meridiansLabel = input('am/pm');
2063
+ /**
2064
+ * @defaultValue
2065
+ * ```
2066
+ * $localize`:@@SI_DATEPICKER.PERIOD:Period`
2067
+ * ```
2068
+ */
2069
+ meridiansAriaLabel = input($localize `:@@SI_DATEPICKER.PERIOD:Period`);
2070
+ /** @defaultValue true */
2071
+ showMinutes = input(true, { transform: booleanAttribute });
2072
+ /** @defaultValue false */
2073
+ showSeconds = input(false, { transform: booleanAttribute });
2074
+ /** @defaultValue false */
2075
+ showMilliseconds = input(false, { transform: booleanAttribute });
2076
+ /**
2077
+ * Show time in 12-hour period including the select to toggle between AM/PM.
2078
+ */
2079
+ showMeridian = input();
2080
+ /**
2081
+ * A minimum time limit. The date part of the date object will be ignored.
2082
+ */
2083
+ min = input();
2084
+ /**
2085
+ * A maximum time limit. The date part of the date object will be ignored.
2086
+ */
2087
+ max = input();
2088
+ /** @defaultValue false */
2089
+ readonly = input(false, { transform: booleanAttribute });
2090
+ isValid = output();
2091
+ meridianChange = output();
2092
+ inputCompleted = output();
2093
+ inputParts = viewChildren('inputPart');
2094
+ /** @internal */
2095
+ errormessageId = `${this.id()}-errormessage`;
2096
+ onChange = () => { };
2097
+ onTouched = () => { };
2098
+ // The following are the time values for the ui.
2099
+ hours = '';
2100
+ minutes = '';
2101
+ seconds = '';
2102
+ milliseconds = '';
2103
+ periods = computed(() => {
2104
+ const meridians = this.meridians();
2105
+ return meridians?.length ? meridians : this.periodDefaults;
2106
+ });
2107
+ use12HourClock = computed(() => this.showMeridian() ?? getLocaleTimeFormat(this.locale, FormatWidth.Full).includes('a'));
2108
+ disabled = computed(() => this.disabledInput() || this.disabledNgControl());
2109
+ meridian = signal('');
2110
+ disabledNgControl = signal(false);
2111
+ locale = inject(LOCALE_ID).toString();
2112
+ cdRef = inject(ChangeDetectorRef);
2113
+ /**
2114
+ * Holds the time as date object that is presented by this control.
2115
+ */
2116
+ time;
2117
+ periodDefaults;
2118
+ constructor() {
2119
+ this.periodDefaults = getLocaleDayPeriods(this.locale, FormStyle.Format, TranslationWidth.Short).slice();
2120
+ }
2121
+ writeValue(obj) {
2122
+ if (this.isValidDate(obj)) {
2123
+ this.setTime(this.parseTime(obj));
2124
+ }
2125
+ else if (obj == null) {
2126
+ this.setTime();
2127
+ }
2128
+ if (obj) {
2129
+ this.isInputValid(this.hours, this.minutes, this.seconds, this.milliseconds, this.isPM());
2130
+ }
2131
+ this.cdRef.markForCheck();
2132
+ }
2133
+ /** @internal */
2134
+ isPM() {
2135
+ return this.use12HourClock() && this.meridian() === 'pm';
2136
+ }
2137
+ registerOnChange(fn) {
2138
+ this.onChange = fn;
2139
+ }
2140
+ registerOnTouched(fn) {
2141
+ this.onTouched = fn;
2142
+ }
2143
+ setDisabledState(isDisabled) {
2144
+ this.disabledNgControl.set(isDisabled);
2145
+ }
2146
+ /**
2147
+ * Handle Enter, Arrow up/down and Space key press events.
2148
+ */
2149
+ handleKeyPressEvent(event) {
2150
+ const target = event.target;
2151
+ switch (event.key) {
2152
+ case 'Enter':
2153
+ this.focusNext(event);
2154
+ break;
2155
+ case 'ArrowUp':
2156
+ case 'ArrowDown':
2157
+ if (!this.readonly()) {
2158
+ this.changeTimeComponent(target.name, event.key === 'ArrowUp');
2159
+ }
2160
+ else {
2161
+ event.preventDefault();
2162
+ }
2163
+ break;
2164
+ case ' ':
2165
+ if (this.readonly()) {
2166
+ event.preventDefault();
2167
+ }
2168
+ break;
2169
+ default:
2170
+ break;
2171
+ }
2172
+ }
2173
+ toHtmlInputElement = (target) => target;
2174
+ updateHours(value) {
2175
+ value = value.toString();
2176
+ if (this.hours !== value) {
2177
+ this.hours = value;
2178
+ const isValid = this.isHourInputValid(this.hours, this.isPM()) && this.isValidLimit();
2179
+ if (!isValid) {
2180
+ this.invalidHours = true;
2181
+ this.isValid.emit(false);
2182
+ this.onChange(null);
2183
+ }
2184
+ else {
2185
+ this.invalidHours = false;
2186
+ this.updateTime();
2187
+ }
2188
+ }
2189
+ }
2190
+ updateMinutes(value) {
2191
+ value = value.toString();
2192
+ if (this.minutes !== value) {
2193
+ this.minutes = value;
2194
+ const isValid = this.isMinuteInputValid(this.minutes) && this.isValidLimit();
2195
+ if (!isValid) {
2196
+ this.invalidMinutes = true;
2197
+ this.isValid.emit(false);
2198
+ this.onChange(null);
2199
+ }
2200
+ else {
2201
+ this.invalidMinutes = false;
2202
+ this.updateTime();
2203
+ }
2204
+ }
2205
+ }
2206
+ updateSeconds(value) {
2207
+ value = value.toString();
2208
+ if (this.seconds !== value) {
2209
+ this.seconds = value.toString();
2210
+ const isValid = this.isSecondInputValid(this.seconds) && this.isValidLimit();
2211
+ if (!isValid) {
2212
+ this.invalidSeconds = true;
2213
+ this.isValid.emit(false);
2214
+ this.onChange(null);
2215
+ }
2216
+ else {
2217
+ this.invalidSeconds = false;
2218
+ this.updateTime();
2219
+ }
2220
+ }
2221
+ }
2222
+ updateMilliseconds(value) {
2223
+ value = value.toString();
2224
+ if (this.milliseconds !== value) {
2225
+ this.milliseconds = value.toString();
2226
+ const isValid = this.isMillisecondInputValid(this.milliseconds) && this.isValidLimit();
2227
+ if (!isValid) {
2228
+ this.invalidMilliseconds = true;
2229
+ this.isValid.emit(false);
2230
+ this.onChange(null);
2231
+ }
2232
+ else {
2233
+ this.invalidMilliseconds = false;
2234
+ this.updateTime();
2235
+ }
2236
+ }
2237
+ }
2238
+ toggleMeridian() {
2239
+ const time = this.changeTime(this.time, { hour: 12 });
2240
+ this.setTime(time);
2241
+ }
2242
+ /**
2243
+ * Takes the current UI values and updates the time object value
2244
+ * accordingly, if they UI input values are valid.
2245
+ */
2246
+ updateTime() {
2247
+ const minutes = this.showMinutes() ? this.minutes : undefined;
2248
+ const seconds = this.showSeconds() ? this.seconds : undefined;
2249
+ const milliseconds = this.showMilliseconds() ? this.milliseconds : undefined;
2250
+ if (!this.isInputValid(this.hours, minutes, seconds, milliseconds, this.isPM())) {
2251
+ this.isValid.emit(false);
2252
+ this.onChange(null);
2253
+ return;
2254
+ }
2255
+ const time = this.createDateUpdate(this.time, {
2256
+ hour: this.hours,
2257
+ minute: this.minutes,
2258
+ seconds: this.seconds,
2259
+ milliseconds: this.milliseconds,
2260
+ isPM: this.isPM()
2261
+ });
2262
+ this.setTime(time);
2263
+ }
2264
+ /**
2265
+ * Sets a new time object as model value, updates the user interface
2266
+ * and invokes onChange to let timepicker clients know about the update.
2267
+ * @param time - The new time to be set.
2268
+ */
2269
+ setTime(time) {
2270
+ if (this.time !== time) {
2271
+ this.time = time;
2272
+ this.updateUI(this.time);
2273
+ this.onChange(this.time);
2274
+ }
2275
+ }
2276
+ /**
2277
+ * Updates the user interface by filling the time components
2278
+ * into the time input fields. Sets empty values if the date
2279
+ * is undefined or invalid.
2280
+ *
2281
+ * @param value - The date object or string from with the time components are taken.
2282
+ */
2283
+ updateUI(value) {
2284
+ if (!value || !this.isValidDate(value)) {
2285
+ this.hours = '';
2286
+ this.minutes = '';
2287
+ this.seconds = '';
2288
+ this.milliseconds = '';
2289
+ this.meridian.set('am');
2290
+ this.meridianChange.emit(this.meridian());
2291
+ }
2292
+ else {
2293
+ const time = this.parseTime(value);
2294
+ if (!time) {
2295
+ return;
2296
+ }
2297
+ let hours = time.getHours();
2298
+ if (this.use12HourClock()) {
2299
+ this.meridian.set(hours >= 12 ? 'pm' : 'am');
2300
+ this.meridianChange.emit(this.meridian());
2301
+ hours = hours % 12;
2302
+ if (hours === 0) {
2303
+ hours = 12;
2304
+ }
2305
+ }
2306
+ this.hours = hours.toString().padStart(2, '0');
2307
+ this.minutes = time.getMinutes().toString().padStart(2, '0');
2308
+ this.seconds = time.getUTCSeconds().toString().padStart(2, '0');
2309
+ this.milliseconds = time.getUTCMilliseconds().toString().padStart(3, '0');
2310
+ }
2311
+ }
2312
+ isValidDate(value) {
2313
+ if (!value) {
2314
+ return false;
2315
+ }
2316
+ if (typeof value === 'string') {
2317
+ return this.isValidDate(new Date(value));
2318
+ }
2319
+ if (value instanceof Date && isNaN(value.getHours())) {
2320
+ return false;
2321
+ }
2322
+ return true;
2323
+ }
2324
+ parseTime(value) {
2325
+ if (typeof value === 'string') {
2326
+ return new Date(value);
2327
+ }
2328
+ return value;
2329
+ }
2330
+ parseHours(value, isPM = false) {
2331
+ const hour = this.toNumber(value);
2332
+ if (isNaN(hour) || hour < 0 || hour > (isPM ? 12 : 24)) {
2333
+ return NaN;
2334
+ }
2335
+ return hour;
2336
+ }
2337
+ parseMinutes(value) {
2338
+ const minute = this.toNumber(value);
2339
+ if (isNaN(minute) || minute < 0 || minute > 60) {
2340
+ return NaN;
2341
+ }
2342
+ return minute;
2343
+ }
2344
+ parseSeconds(value) {
2345
+ const seconds = this.toNumber(value);
2346
+ if (isNaN(seconds) || seconds < 0 || seconds > 60) {
2347
+ return NaN;
2348
+ }
2349
+ return seconds;
2350
+ }
2351
+ parseMilliseconds(value) {
2352
+ const milliseconds = this.toNumber(value);
2353
+ if (isNaN(milliseconds) || milliseconds < 0 || milliseconds > 1000) {
2354
+ return NaN;
2355
+ }
2356
+ return milliseconds;
2357
+ }
2358
+ createDateUpdate(date, time) {
2359
+ let hour = this.parseHours(time.hour);
2360
+ const minute = this.parseMinutes(time.minute);
2361
+ const seconds = this.parseSeconds(time.seconds) || 0;
2362
+ const milliseconds = this.parseMilliseconds(time.milliseconds) || 0;
2363
+ if (time.isPM && hour !== 12) {
2364
+ hour += 12;
2365
+ }
2366
+ if (!date) {
2367
+ if (!isNaN(hour) && !isNaN(minute)) {
2368
+ return createDate(new Date(), hour, minute, seconds, milliseconds);
2369
+ }
2370
+ else {
2371
+ return date;
2372
+ }
2373
+ }
2374
+ else if (isNaN(hour) || isNaN(minute)) {
2375
+ return date;
2376
+ }
2377
+ else {
2378
+ return createDate(date, hour, minute, seconds, milliseconds);
2379
+ }
2380
+ }
2381
+ toNumber(value) {
2382
+ if (typeof value === 'undefined') {
2383
+ return NaN;
2384
+ }
2385
+ else if (typeof value === 'number') {
2386
+ return value;
2387
+ }
2388
+ return parseInt(value, 10);
2389
+ }
2390
+ isInputValid(hours, minutes = '0', seconds = '0', milliseconds = '0', isPM) {
2391
+ if (!this.isValidLimit()) {
2392
+ this.invalidHours = true;
2393
+ this.invalidMinutes = true;
2394
+ this.invalidSeconds = true;
2395
+ this.invalidMilliseconds = true;
2396
+ }
2397
+ else {
2398
+ this.invalidHours = !this.isHourInputValid(hours, isPM);
2399
+ this.invalidMinutes = !this.isMinuteInputValid(minutes);
2400
+ this.invalidSeconds = !this.isSecondInputValid(seconds);
2401
+ this.invalidMilliseconds = !this.isMillisecondInputValid(milliseconds);
2402
+ }
2403
+ return (!this.invalidHours &&
2404
+ !this.invalidMinutes &&
2405
+ !this.invalidSeconds &&
2406
+ !this.invalidMilliseconds);
2407
+ }
2408
+ isHourInputValid(hours, isPM) {
2409
+ return !isNaN(this.parseHours(hours, isPM));
2410
+ }
2411
+ isMinuteInputValid(minutes) {
2412
+ return !isNaN(this.parseMinutes(minutes));
2413
+ }
2414
+ isSecondInputValid(seconds) {
2415
+ return !isNaN(this.parseSeconds(seconds));
2416
+ }
2417
+ isMillisecondInputValid(milliseconds) {
2418
+ return !isNaN(this.parseMilliseconds(milliseconds));
2419
+ }
2420
+ isValidLimit() {
2421
+ const refDate = new Date();
2422
+ const newDate = this.createDateUpdate(refDate, {
2423
+ hour: this.hours,
2424
+ minute: this.minutes,
2425
+ seconds: this.seconds,
2426
+ milliseconds: this.milliseconds,
2427
+ isPM: this.isPM()
2428
+ });
2429
+ if (!newDate) {
2430
+ return false;
2431
+ }
2432
+ let refMax;
2433
+ const max = this.max();
2434
+ if (max) {
2435
+ refMax = new Date(refDate);
2436
+ refMax.setHours(max.getHours());
2437
+ refMax.setMinutes(max.getMinutes());
2438
+ refMax.setSeconds(max.getSeconds());
2439
+ refMax.setMilliseconds(max.getMilliseconds());
2440
+ }
2441
+ let refMin;
2442
+ const min = this.min();
2443
+ if (min) {
2444
+ refMin = new Date(refDate);
2445
+ refMin.setHours(min.getHours());
2446
+ refMin.setMinutes(min.getMinutes());
2447
+ refMin.setSeconds(min.getSeconds());
2448
+ refMin.setMilliseconds(min.getMilliseconds());
2449
+ }
2450
+ if (refMax && newDate > refMax) {
2451
+ return false;
2452
+ }
2453
+ else if (refMin && newDate < refMin) {
2454
+ return false;
2455
+ }
2456
+ return true;
2457
+ }
2458
+ changeTimeComponent(key, up) {
2459
+ const change = up ? 1 : -1;
2460
+ const date = this.createDateUpdate(new Date(), {
2461
+ hour: this.hours,
2462
+ minute: this.minutes,
2463
+ seconds: this.seconds,
2464
+ milliseconds: this.milliseconds,
2465
+ isPM: this.isPM()
2466
+ });
2467
+ switch (key) {
2468
+ case 'hours': {
2469
+ const newTime = this.changeTime(date, { hour: change });
2470
+ let hour = newTime.getHours();
2471
+ if (this.use12HourClock()) {
2472
+ hour = hour % 12;
2473
+ if (hour === 0 && !this.isPM()) {
2474
+ hour = 12;
2475
+ }
2476
+ else if (hour === 0 && this.isPM()) {
2477
+ this.toggleMeridian();
2478
+ }
2479
+ }
2480
+ this.updateHours(hour);
2481
+ break;
2482
+ }
2483
+ case 'minutes': {
2484
+ const newTime = this.changeTime(date, { minute: change });
2485
+ this.updateMinutes(newTime.getMinutes());
2486
+ break;
2487
+ }
2488
+ case 'seconds': {
2489
+ const newTime = this.changeTime(date, { seconds: change });
2490
+ this.updateSeconds(newTime.getSeconds());
2491
+ break;
2492
+ }
2493
+ case 'milliseconds': {
2494
+ const newTime = this.changeTime(date, { milliseconds: change });
2495
+ this.updateMilliseconds(newTime.getMilliseconds());
2496
+ break;
2497
+ }
2498
+ default:
2499
+ break;
2500
+ }
2501
+ }
2502
+ changeTime(value, diff) {
2503
+ if (!value) {
2504
+ return this.changeTime(createDate(new Date(), 0, 0, 0, 0), diff);
2505
+ }
2506
+ if (!diff) {
2507
+ return value;
2508
+ }
2509
+ let hour = value.getHours();
2510
+ let minutes = value.getMinutes();
2511
+ let seconds = value.getSeconds();
2512
+ let milliseconds = value.getMilliseconds();
2513
+ if (diff.hour) {
2514
+ hour = hour + this.toNumber(diff.hour);
2515
+ }
2516
+ if (diff.minute) {
2517
+ minutes = minutes + this.toNumber(diff.minute);
2518
+ }
2519
+ if (diff.seconds) {
2520
+ seconds = seconds + this.toNumber(diff.seconds);
2521
+ }
2522
+ if (diff.milliseconds) {
2523
+ milliseconds = milliseconds + this.toNumber(diff.milliseconds);
2524
+ }
2525
+ return createDate(value, hour, minutes, seconds, milliseconds);
2526
+ }
2527
+ /**
2528
+ * Focuses the next available input/select field or emit inputCompleted event.
2529
+ */
2530
+ focusNext(event) {
2531
+ const target = event.target;
2532
+ if (!target) {
2533
+ return;
2534
+ }
2535
+ const targets = this.inputParts();
2536
+ const position = targets?.findIndex(t => t.nativeElement === target);
2537
+ if (position === undefined || position === -1) {
2538
+ return;
2539
+ }
2540
+ if (position < targets.length - 1) {
2541
+ targets[position + 1].nativeElement.focus();
2542
+ }
2543
+ else {
2544
+ this.inputCompleted.emit();
2545
+ }
2546
+ }
2547
+ focusChange(event) {
2548
+ if (event === null) {
2549
+ this.onTouched();
2550
+ }
2551
+ }
2552
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTimepickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2553
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: SiTimepickerComponent, isStandalone: true, selector: "si-timepicker", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, hoursLabel: { classPropertyName: "hoursLabel", publicName: "hoursLabel", isSignal: true, isRequired: false, transformFunction: null }, minutesLabel: { classPropertyName: "minutesLabel", publicName: "minutesLabel", isSignal: true, isRequired: false, transformFunction: null }, secondsLabel: { classPropertyName: "secondsLabel", publicName: "secondsLabel", isSignal: true, isRequired: false, transformFunction: null }, millisecondsLabel: { classPropertyName: "millisecondsLabel", publicName: "millisecondsLabel", isSignal: true, isRequired: false, transformFunction: null }, hideLabels: { classPropertyName: "hideLabels", publicName: "hideLabels", isSignal: true, isRequired: false, transformFunction: null }, hoursAriaLabel: { classPropertyName: "hoursAriaLabel", publicName: "hoursAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, minutesAriaLabel: { classPropertyName: "minutesAriaLabel", publicName: "minutesAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, secondsAriaLabel: { classPropertyName: "secondsAriaLabel", publicName: "secondsAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, millisecondsAriaLabel: { classPropertyName: "millisecondsAriaLabel", publicName: "millisecondsAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, hoursPlaceholder: { classPropertyName: "hoursPlaceholder", publicName: "hoursPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, minutesPlaceholder: { classPropertyName: "minutesPlaceholder", publicName: "minutesPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, secondsPlaceholder: { classPropertyName: "secondsPlaceholder", publicName: "secondsPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, millisecondsPlaceholder: { classPropertyName: "millisecondsPlaceholder", publicName: "millisecondsPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, meridians: { classPropertyName: "meridians", publicName: "meridians", isSignal: true, isRequired: false, transformFunction: null }, meridiansLabel: { classPropertyName: "meridiansLabel", publicName: "meridiansLabel", isSignal: true, isRequired: false, transformFunction: null }, meridiansAriaLabel: { classPropertyName: "meridiansAriaLabel", publicName: "meridiansAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, showMinutes: { classPropertyName: "showMinutes", publicName: "showMinutes", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, showMilliseconds: { classPropertyName: "showMilliseconds", publicName: "showMilliseconds", isSignal: true, isRequired: false, transformFunction: null }, showMeridian: { classPropertyName: "showMeridian", publicName: "showMeridian", 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 }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { isValid: "isValid", meridianChange: "meridianChange", inputCompleted: "inputCompleted" }, host: { attributes: { "role": "group" }, properties: { "class.readonly": "readonly()", "attr.aria-labelledby": "labelledby" }, classAttribute: "form-custom-control" }, providers: [
2554
+ {
2555
+ provide: NG_VALUE_ACCESSOR,
2556
+ useExisting: SiTimepickerComponent,
2557
+ multi: true
2558
+ },
2559
+ {
2560
+ provide: SI_FORM_ITEM_CONTROL,
2561
+ useExisting: SiTimepickerComponent
2562
+ }
2563
+ ], viewQueries: [{ propertyName: "inputParts", predicate: ["inputPart"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"d-flex flex-row flex-wrap\"\n cdkMonitorSubtreeFocus\n (cdkFocusChange)=\"focusChange($event)\"\n>\n <label class=\"min-width\">\n @if (!hideLabels()) {\n <span class=\"form-label\">{{ (hoursLabel() | translate) || '&nbsp;' }}</span>\n }\n <input\n #inputPart\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"2[0-4]|[01]?[0-9]\"\n class=\"form-control hide-feedback-icon\"\n name=\"hours\"\n maxlength=\"2\"\n autocomplete=\"off\"\n [attr.aria-label]=\"hoursAriaLabel() | translate\"\n [attr.aria-describedby]=\"errormessageId\"\n [class.is-invalid]=\"invalidHours\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [placeholder]=\"hoursPlaceholder()\"\n [value]=\"hours\"\n (change)=\"updateHours(toHtmlInputElement($event.target).value)\"\n (blur)=\"updateHours(toHtmlInputElement($event.target).value)\"\n (keydown)=\"handleKeyPressEvent($event)\"\n />\n </label>\n\n @if (showMinutes()) {\n <ng-container *ngTemplateOutlet=\"separator\" />\n <label class=\"min-width\">\n @if (!hideLabels()) {\n <span class=\"form-label\">{{ (minutesLabel() | translate) || '&nbsp;' }}</span>\n }\n <input\n #inputPart\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"[0-5]?[0-9]\"\n class=\"form-control hide-feedback-icon\"\n name=\"minutes\"\n maxlength=\"2\"\n autocomplete=\"off\"\n [attr.aria-label]=\"minutesAriaLabel() | translate\"\n [attr.aria-describedby]=\"errormessageId\"\n [class.is-invalid]=\"invalidMinutes\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [placeholder]=\"minutesPlaceholder()\"\n [value]=\"minutes\"\n (change)=\"updateMinutes(toHtmlInputElement($event.target).value)\"\n (blur)=\"updateMinutes(toHtmlInputElement($event.target).value)\"\n (keydown)=\"handleKeyPressEvent($event)\"\n />\n </label>\n }\n\n @if (showSeconds()) {\n <ng-container *ngTemplateOutlet=\"separator\" />\n <label class=\"min-width\">\n @if (!hideLabels()) {\n <span class=\"form-label\">{{ (secondsLabel() | translate) || '&nbsp;' }}</span>\n }\n <input\n #inputPart\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"[0-5]?[0-9]\"\n class=\"form-control hide-feedback-icon\"\n name=\"seconds\"\n maxlength=\"2\"\n autocomplete=\"off\"\n [attr.aria-label]=\"secondsAriaLabel() | translate\"\n [attr.aria-describedby]=\"errormessageId\"\n [class.is-invalid]=\"invalidSeconds\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [placeholder]=\"secondsPlaceholder()\"\n [value]=\"seconds\"\n (change)=\"updateSeconds(toHtmlInputElement($event.target).value)\"\n (blur)=\"updateSeconds(toHtmlInputElement($event.target).value)\"\n (keydown)=\"handleKeyPressEvent($event)\"\n />\n </label>\n }\n\n @if (showMilliseconds()) {\n <ng-container *ngTemplateOutlet=\"separator; context: { separator: '.' }\" />\n <label class=\"min-width\">\n @if (!hideLabels()) {\n <span class=\"form-label\">{{ (millisecondsLabel() | translate) || '&nbsp;' }}</span>\n }\n <input\n #inputPart\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"[0-9]{1,3}\"\n class=\"form-control hide-feedback-icon\"\n name=\"milliseconds\"\n maxlength=\"3\"\n autocomplete=\"off\"\n [attr.aria-label]=\"millisecondsAriaLabel() | translate\"\n [attr.aria-describedby]=\"errormessageId\"\n [class.is-invalid]=\"invalidMilliseconds\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [placeholder]=\"millisecondsPlaceholder()\"\n [value]=\"milliseconds\"\n (change)=\"updateMilliseconds(toHtmlInputElement($event.target).value)\"\n (blur)=\"updateMilliseconds(toHtmlInputElement($event.target).value)\"\n (keydown)=\"handleKeyPressEvent($event)\"\n />\n </label>\n }\n\n @if (use12HourClock()) {\n <label class=\"ms-2\">\n @if (!hideLabels()) {\n <span class=\"form-label\">{{ (meridiansLabel() | translate) || '&nbsp;' }}</span>\n }\n <select\n #inputPart\n class=\"form-control\"\n [attr.aria-label]=\"meridiansAriaLabel() | translate\"\n [attr.aria-describedby]=\"errormessageId\"\n [class.readonly]=\"readonly()\"\n [disabled]=\"disabled()\"\n (change)=\"toggleMeridian()\"\n (keydown)=\"handleKeyPressEvent($event)\"\n >\n <option value=\"am\" [selected]=\"meridian() === 'am'\">{{ periods()[0] }}</option>\n <option value=\"pm\" [selected]=\"meridian() === 'pm'\">{{ periods()[1] }}</option>\n </select>\n </label>\n }\n</div>\n\n<ng-template #separator let-separator=\"separator\">\n <div class=\"align-self-end pb-3 px-1\" aria-hidden=\"true\">{{ separator ? separator : ':' }}</div>\n</ng-template>\n", styles: [":host{display:block}.min-width{inline-size:100%;max-inline-size:45px;min-inline-size:35px}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "ngmodule", type: SiTranslateModule }, { kind: "pipe", type: i2.SiTranslatePipe, name: "translate" }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i3.CdkMonitorFocus, selector: "[cdkMonitorElementFocus], [cdkMonitorSubtreeFocus]", outputs: ["cdkFocusChange"], exportAs: ["cdkMonitorFocus"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2564
+ }
2565
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiTimepickerComponent, decorators: [{
2566
+ type: Component,
2567
+ args: [{ selector: 'si-timepicker', providers: [
2568
+ {
2569
+ provide: NG_VALUE_ACCESSOR,
2570
+ useExisting: SiTimepickerComponent,
2571
+ multi: true
2572
+ },
2573
+ {
2574
+ provide: SI_FORM_ITEM_CONTROL,
2575
+ useExisting: SiTimepickerComponent
2576
+ }
2577
+ ], changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgTemplateOutlet, FormsModule, SiTranslateModule, A11yModule], host: {
2578
+ role: 'group',
2579
+ class: 'form-custom-control',
2580
+ '[class.readonly]': 'readonly()',
2581
+ '[attr.aria-labelledby]': 'labelledby'
2582
+ }, template: "<div\n class=\"d-flex flex-row flex-wrap\"\n cdkMonitorSubtreeFocus\n (cdkFocusChange)=\"focusChange($event)\"\n>\n <label class=\"min-width\">\n @if (!hideLabels()) {\n <span class=\"form-label\">{{ (hoursLabel() | translate) || '&nbsp;' }}</span>\n }\n <input\n #inputPart\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"2[0-4]|[01]?[0-9]\"\n class=\"form-control hide-feedback-icon\"\n name=\"hours\"\n maxlength=\"2\"\n autocomplete=\"off\"\n [attr.aria-label]=\"hoursAriaLabel() | translate\"\n [attr.aria-describedby]=\"errormessageId\"\n [class.is-invalid]=\"invalidHours\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [placeholder]=\"hoursPlaceholder()\"\n [value]=\"hours\"\n (change)=\"updateHours(toHtmlInputElement($event.target).value)\"\n (blur)=\"updateHours(toHtmlInputElement($event.target).value)\"\n (keydown)=\"handleKeyPressEvent($event)\"\n />\n </label>\n\n @if (showMinutes()) {\n <ng-container *ngTemplateOutlet=\"separator\" />\n <label class=\"min-width\">\n @if (!hideLabels()) {\n <span class=\"form-label\">{{ (minutesLabel() | translate) || '&nbsp;' }}</span>\n }\n <input\n #inputPart\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"[0-5]?[0-9]\"\n class=\"form-control hide-feedback-icon\"\n name=\"minutes\"\n maxlength=\"2\"\n autocomplete=\"off\"\n [attr.aria-label]=\"minutesAriaLabel() | translate\"\n [attr.aria-describedby]=\"errormessageId\"\n [class.is-invalid]=\"invalidMinutes\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [placeholder]=\"minutesPlaceholder()\"\n [value]=\"minutes\"\n (change)=\"updateMinutes(toHtmlInputElement($event.target).value)\"\n (blur)=\"updateMinutes(toHtmlInputElement($event.target).value)\"\n (keydown)=\"handleKeyPressEvent($event)\"\n />\n </label>\n }\n\n @if (showSeconds()) {\n <ng-container *ngTemplateOutlet=\"separator\" />\n <label class=\"min-width\">\n @if (!hideLabels()) {\n <span class=\"form-label\">{{ (secondsLabel() | translate) || '&nbsp;' }}</span>\n }\n <input\n #inputPart\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"[0-5]?[0-9]\"\n class=\"form-control hide-feedback-icon\"\n name=\"seconds\"\n maxlength=\"2\"\n autocomplete=\"off\"\n [attr.aria-label]=\"secondsAriaLabel() | translate\"\n [attr.aria-describedby]=\"errormessageId\"\n [class.is-invalid]=\"invalidSeconds\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [placeholder]=\"secondsPlaceholder()\"\n [value]=\"seconds\"\n (change)=\"updateSeconds(toHtmlInputElement($event.target).value)\"\n (blur)=\"updateSeconds(toHtmlInputElement($event.target).value)\"\n (keydown)=\"handleKeyPressEvent($event)\"\n />\n </label>\n }\n\n @if (showMilliseconds()) {\n <ng-container *ngTemplateOutlet=\"separator; context: { separator: '.' }\" />\n <label class=\"min-width\">\n @if (!hideLabels()) {\n <span class=\"form-label\">{{ (millisecondsLabel() | translate) || '&nbsp;' }}</span>\n }\n <input\n #inputPart\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"[0-9]{1,3}\"\n class=\"form-control hide-feedback-icon\"\n name=\"milliseconds\"\n maxlength=\"3\"\n autocomplete=\"off\"\n [attr.aria-label]=\"millisecondsAriaLabel() | translate\"\n [attr.aria-describedby]=\"errormessageId\"\n [class.is-invalid]=\"invalidMilliseconds\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [placeholder]=\"millisecondsPlaceholder()\"\n [value]=\"milliseconds\"\n (change)=\"updateMilliseconds(toHtmlInputElement($event.target).value)\"\n (blur)=\"updateMilliseconds(toHtmlInputElement($event.target).value)\"\n (keydown)=\"handleKeyPressEvent($event)\"\n />\n </label>\n }\n\n @if (use12HourClock()) {\n <label class=\"ms-2\">\n @if (!hideLabels()) {\n <span class=\"form-label\">{{ (meridiansLabel() | translate) || '&nbsp;' }}</span>\n }\n <select\n #inputPart\n class=\"form-control\"\n [attr.aria-label]=\"meridiansAriaLabel() | translate\"\n [attr.aria-describedby]=\"errormessageId\"\n [class.readonly]=\"readonly()\"\n [disabled]=\"disabled()\"\n (change)=\"toggleMeridian()\"\n (keydown)=\"handleKeyPressEvent($event)\"\n >\n <option value=\"am\" [selected]=\"meridian() === 'am'\">{{ periods()[0] }}</option>\n <option value=\"pm\" [selected]=\"meridian() === 'pm'\">{{ periods()[1] }}</option>\n </select>\n </label>\n }\n</div>\n\n<ng-template #separator let-separator=\"separator\">\n <div class=\"align-self-end pb-3 px-1\" aria-hidden=\"true\">{{ separator ? separator : ':' }}</div>\n</ng-template>\n", styles: [":host{display:block}.min-width{inline-size:100%;max-inline-size:45px;min-inline-size:35px}\n"] }]
2583
+ }], ctorParameters: () => [] });
2584
+
2585
+ /**
2586
+ * Copyright Siemens 2016 - 2025.
2587
+ * SPDX-License-Identifier: MIT
2588
+ */
2589
+ let idCounter = 1;
2590
+ class SiDatepickerComponent {
2591
+ locale = inject(LOCALE_ID).toString();
2592
+ /**
2593
+ * The date which is currently focused
2594
+ * Compare to the selected date or range the calendar requires to have one element to focus.
2595
+ */
2596
+ focusedDate = model();
2597
+ /**
2598
+ * The selected date of the datepicker. Use for
2599
+ * initialization and for bidirectional binding.
2600
+ */
2601
+ date = model();
2602
+ /**
2603
+ * The selected date range of the datepicker. Use for
2604
+ * initialization and for bidirectional binding.
2605
+ */
2606
+ dateRange = model();
2607
+ /** @internal */
2608
+ dateRangeRole = input();
2609
+ /**
2610
+ * Set initial focus to calendar body.
2611
+ *
2612
+ * @defaultValue false
2613
+ */
2614
+ initialFocus = input(false);
2615
+ /**
2616
+ * Disabled the optional visible time picker.
2617
+ *
2618
+ * @defaultValue false
2619
+ */
2620
+ disabledTime = model(false);
2621
+ /**
2622
+ * Object to configure the datepicker.
2623
+ *
2624
+ * @defaultValue
2625
+ * ```
2626
+ * {}
2627
+ * ```
2628
+ */
2629
+ config = model({});
2630
+ /**
2631
+ * Aria label for the previous button. Needed for a11y.
2632
+ *
2633
+ * @defaultValue
2634
+ * ```
2635
+ * $localize`:@@SI_DATEPICKER.PREVIOUS:Previous`
2636
+ * ```
2637
+ */
2638
+ previousLabel = input($localize `:@@SI_DATEPICKER.PREVIOUS:Previous`);
2639
+ /**
2640
+ * Aria label for the next button. Needed for a11y.
2641
+ *
2642
+ * @defaultValue
2643
+ * ```
2644
+ * $localize`:@@SI_DATEPICKER.NEXT:Next`
2645
+ * ```
2646
+ */
2647
+ nextLabel = input($localize `:@@SI_DATEPICKER.NEXT:Next`);
2648
+ /**
2649
+ * Aria label for week number column
2650
+ *
2651
+ * @defaultValue
2652
+ * ```
2653
+ * $localize`:@@SI_DATEPICKER.CALENDAR_WEEK_LABEL:Calendar week`
2654
+ * ```
2655
+ */
2656
+ calenderWeekLabel = input($localize `:@@SI_DATEPICKER.CALENDAR_WEEK_LABEL:Calendar week`);
2657
+ /**
2658
+ * Enable/disable 12H mode in timepicker. Defaults to locale
2659
+ *
2660
+ * @defaultValue undefined
2661
+ */
2662
+ time12h = input(undefined, {
2663
+ transform: booleanAttribute
2664
+ });
2665
+ /**
2666
+ * Use this to force date range operation to select either start date or end date.
2667
+ *
2668
+ * @defaultValue 'START'
2669
+ */
2670
+ rangeType = model('START');
2671
+ /**
2672
+ * Optional input to control the minimum month the datepicker can show and the user can navigate.
2673
+ * The `minMonth` can be larger than the `minDate` This option enables the usage of multiple
2674
+ * datepickers next to each other while the more left calendar always
2675
+ * shows a earlier month the the more right one.
2676
+ * @internal
2677
+ */
2678
+ minMonth = input();
2679
+ /**
2680
+ * Optional input to control the maximum month the datepicker can show and the user can navigate.
2681
+ * The `maxMonth` can be smaller than the `maxDate` This option enables the usage of multiple
2682
+ * datepickers next to each other while the more left calendar always
2683
+ * shows a earlier month the the more right one.
2684
+ * @internal
2685
+ */
2686
+ maxMonth = input();
2687
+ /**
2688
+ * Option to hide the time switch.
2689
+ *
2690
+ * @defaultValue false
2691
+ */
2692
+ hideTimeToggle = input(false);
2693
+ /** @internal */
2694
+ hideCalendar = input(false);
2695
+ /**
2696
+ * Optional timepicker label.
2697
+ */
2698
+ timepickerLabel = input();
2699
+ get startDate() {
2700
+ return this.config().enableDateRange ? this.dateRange()?.start : this.date();
2701
+ }
2702
+ get endDate() {
2703
+ return this.config().enableDateRange ? this.dateRange()?.end : undefined;
2704
+ }
2705
+ /**
2706
+ * Returns the date object if not range selection is enabled. Otherwise, if
2707
+ * the date range role is 'END', the date range end date is returned. If
2708
+ * date range role is not 'END', the date range start date is returned.
2709
+ */
2710
+ getRelevantDate() {
2711
+ return !this.config().enableDateRange
2712
+ ? this.date()
2713
+ : this.dateRangeRole() === 'END'
2714
+ ? this.dateRange()?.end
2715
+ : this.dateRange()?.start;
2716
+ }
2717
+ defaultDisabledTimeText = $localize `:@@SI_DATEPICKER.DISABLED_TIME_TEXT:Ignore time`;
2718
+ defaultEnableTimeText = $localize `:@@SI_DATEPICKER.ENABLED_TIME_TEXT:Consider time`;
2719
+ includeTimeLabel = computed(() => this.disabledTime()
2720
+ ? (this.config().disabledTimeText ?? this.defaultDisabledTimeText)
2721
+ : (this.config().enabledTimeText ?? this.defaultEnableTimeText));
2722
+ get weekStartDay() {
2723
+ return this.config().weekStartDay ?? this.localeWeekStart;
2724
+ }
2725
+ get hideWeekNumbers() {
2726
+ return this.config().hideWeekNumbers ?? false;
2727
+ }
2728
+ /**
2729
+ * The active view
2730
+ */
2731
+ view = signal('week');
2732
+ /**
2733
+ * Get the current shown view.
2734
+ */
2735
+ activeView = computed(() => {
2736
+ switch (this.view()) {
2737
+ case 'month':
2738
+ return this.monthSelection();
2739
+ case 'year':
2740
+ return this.yearSelection();
2741
+ default:
2742
+ return this.daySelection();
2743
+ }
2744
+ });
2745
+ actualFocusedDate = computed(() => this.focusedDate() ?? today());
2746
+ requireFocus = signal(this.initialFocus());
2747
+ /** When the user switch from the year or month view via keyboard selection we force the focus. */
2748
+ forceFocus = computed(() => this.requireFocus() || this.initialFocus());
2749
+ months = [];
2750
+ switchId = `__si-datepicker-switch-id-${idCounter++}`;
2751
+ timepickerId = `__si-datepicker-timepicker-id-${idCounter++}`;
2752
+ /**
2753
+ * Configuration which view shall be shown after year selection,
2754
+ * when onlyMonthSelection is enabled the month view is shown otherwise the week view.
2755
+ */
2756
+ yearViewSwitchTo = 'week';
2757
+ monthViewSwitchTo = 'week';
2758
+ cdRef = inject(ChangeDetectorRef);
2759
+ localeWeekStart;
2760
+ /**
2761
+ * Date object to track and change the time. Keeping time and date
2762
+ * in separate objects to not change the date when flipping time.
2763
+ * After change, a new date object is created with an adapted time.
2764
+ */
2765
+ time;
2766
+ /**
2767
+ * Used to hold the last time when setting the time to disabled.
2768
+ * Value will be reset on enabling the time again.
2769
+ */
2770
+ previousTime;
2771
+ timePicker = viewChild(SiTimepickerComponent);
2772
+ /** Reference to the current day selection component. Shown when view === 'week' */
2773
+ daySelection = viewChild(SiDaySelectionComponent);
2774
+ /** Reference to the current month selection component. Shown when view === 'month' */
2775
+ monthSelection = viewChild(SiMonthSelectionComponent);
2776
+ /** Reference to the current year selection component. Shown when view === 'year' */
2777
+ yearSelection = viewChild(SiYearSelectionComponent);
2778
+ /**
2779
+ * The cell which which has the mouse hover.
2780
+ * @internal
2781
+ */
2782
+ activeHover = model();
2783
+ constructor() {
2784
+ this.initCalendarLabels();
2785
+ const weekStart = getLocaleFirstDayOfWeek(this.locale);
2786
+ this.localeWeekStart =
2787
+ weekStart === WeekDay.Sunday
2788
+ ? 'sunday'
2789
+ : weekStart === WeekDay.Saturday
2790
+ ? 'saturday'
2791
+ : 'monday';
2792
+ }
2793
+ ngOnChanges(changes) {
2794
+ const config = this.config();
2795
+ if (changes.date && !config.enableDateRange) {
2796
+ if (this.date() && !isValid(this.date())) {
2797
+ this.date.set(undefined);
2798
+ }
2799
+ const date = this.date();
2800
+ if (date) {
2801
+ if (changes.date.isFirstChange()) {
2802
+ this.previousTime = new Date(date);
2803
+ this.time = date;
2804
+ }
2805
+ if (this.time?.getTime() !== date?.getTime()) {
2806
+ this.time = date;
2807
+ }
2808
+ this.focusedDate.set(date);
2809
+ }
2810
+ }
2811
+ if (changes.config?.currentValue?.disabledTime) {
2812
+ this.disabledTime.set(changes.config?.currentValue?.disabledTime);
2813
+ this.onDisabledTimeChanged();
2814
+ }
2815
+ if (changes.config?.firstChange) {
2816
+ if (config.onlyMonthSelection) {
2817
+ this.yearViewSwitchTo = 'month';
2818
+ this.monthViewSwitchTo = 'month';
2819
+ this.view.set('month');
2820
+ }
2821
+ }
2822
+ // Date-range input field has changed
2823
+ if (changes.dateRange) {
2824
+ // Ensure the dateRange object only contain valid start/end dates
2825
+ const dateRange = this.dateRange();
2826
+ if (dateRange) {
2827
+ if (!isValid(dateRange?.start)) {
2828
+ dateRange.start = undefined;
2829
+ }
2830
+ if (!isValid(dateRange?.end)) {
2831
+ dateRange.end = undefined;
2832
+ }
2833
+ }
2834
+ // Only one calendar is used when no dateRangeRole is available.
2835
+ const dateRangeRole = this.dateRangeRole();
2836
+ if (!dateRangeRole) {
2837
+ const previous = changes.dateRange.previousValue;
2838
+ if (dateRange?.end && !isSameDate(dateRange.end, previous?.end)) {
2839
+ this.focusedDate.set(dateRange.end);
2840
+ }
2841
+ if (dateRange?.start && !isSameDate(dateRange.start, previous?.start)) {
2842
+ this.focusedDate.set(dateRange.start);
2843
+ }
2844
+ }
2845
+ else {
2846
+ // Date range selection with two calendars
2847
+ const newDate = dateRangeRole === 'START' ? dateRange?.start : dateRange?.end;
2848
+ if (newDate && changes.dateRange.isFirstChange()) {
2849
+ this.previousTime = new Date(newDate);
2850
+ this.time = newDate;
2851
+ }
2852
+ }
2853
+ }
2854
+ if (changes.minMonth?.currentValue &&
2855
+ isAfter(changes.minMonth.currentValue, this.actualFocusedDate())) {
2856
+ this.focusedDate.set(changes.minMonth.currentValue);
2857
+ }
2858
+ if (changes.maxMonth?.currentValue &&
2859
+ isAfter(this.actualFocusedDate(), changes.maxMonth.currentValue)) {
2860
+ this.focusedDate.set(changes.maxMonth.currentValue);
2861
+ }
2862
+ }
2863
+ ngOnInit() {
2864
+ const config = this.config();
2865
+ const dateRange = this.dateRange();
2866
+ const dateRangeRole = this.dateRangeRole();
2867
+ if (config.enableDateRange && this.rangeType() === 'END' && dateRange?.end && !dateRangeRole) {
2868
+ // The user chose to trigger the datepicker from the date-range end, in this
2869
+ // case we
2870
+ this.focusedDate.set(dateRange.end);
2871
+ }
2872
+ else if (config.enableDateRange && dateRangeRole === 'START') {
2873
+ const maxMonth = config?.onlyMonthSelection ? this.maxMonth() : config.maxDate;
2874
+ this.focusedDate.set(getDateSameOrBetween(dateRange?.start ? dateRange.start : (this.focusedDate() ?? today()), config.minDate, maxMonth));
2875
+ }
2876
+ else if (config.enableDateRange && dateRangeRole === 'END') {
2877
+ const minMonth = config?.onlyMonthSelection ? this.minMonth() : config.minDate;
2878
+ this.focusedDate.set(getDateSameOrBetween(dateRange?.end ? dateRange.end : (this.focusedDate() ?? today()), minMonth, config.maxDate));
2879
+ }
2880
+ else {
2881
+ this.focusedDate.set(getDateSameOrBetween(isValid(this.startDate) ? this.startDate : (this.focusedDate() ?? today()), config.minDate, config.maxDate));
2882
+ }
2883
+ }
2884
+ ngAfterViewInit() {
2885
+ // After the view is created the first time we want that the children components set
2886
+ // the focus to the calendarBody. Means when we select a date in month-selection,
2887
+ // the day selection shall focus automatically the day in calendarBody.
2888
+ setTimeout(() => this.requireFocus.set(true));
2889
+ }
2890
+ /** Initialize day and month labels */
2891
+ initCalendarLabels() {
2892
+ this.months = getLocaleMonthNames(this.locale.toString());
2893
+ }
2894
+ /**
2895
+ * Validates and sets a new date to the this.date model object of this component
2896
+ * and fires the related events. The model object shall not be updated elsewhere
2897
+ * with a new date object. Shall only be called on simple date selection and not
2898
+ * on date range selection.
2899
+ *
2900
+ * @param newDate - The new date to be set.
2901
+ */
2902
+ setDate(newDate) {
2903
+ const dateWithoutTime = getDateWithoutTime(newDate);
2904
+ const config = this.config();
2905
+ const validForMinDate = !(config?.minDate && dateWithoutTime < getDateWithoutTime(config.minDate));
2906
+ const configValue = this.config();
2907
+ const validForMaxDate = !(configValue?.maxDate && dateWithoutTime > getDateWithoutTime(configValue.maxDate));
2908
+ const date = this.date();
2909
+ if (date !== newDate && validForMinDate && validForMaxDate) {
2910
+ const previousValue = date;
2911
+ this.date.set(newDate);
2912
+ // eslint-disable-next-line @angular-eslint/no-lifecycle-call
2913
+ this.ngOnChanges({
2914
+ date: new SimpleChange(previousValue, date, previousValue === undefined)
2915
+ });
2916
+ //this.dateChange.emit(date);
2917
+ }
2918
+ else if (!validForMinDate || !validForMaxDate) {
2919
+ // eslint-disable-next-line @angular-eslint/no-lifecycle-call
2920
+ this.ngOnChanges({ date: new SimpleChange(undefined, date, true) });
2921
+ }
2922
+ if (config.enableTimeValidation && this.timePicker() && (config.minDate || config.maxDate)) {
2923
+ this.validateTime(newDate);
2924
+ }
2925
+ this.cdRef.markForCheck();
2926
+ }
2927
+ /**
2928
+ * Validates and sets the new date range to the dateRange model
2929
+ * object.
2930
+ * @param newDateRange - The new range to be set.
2931
+ * @returns True if the new range is valid and set. Otherwise false.
2932
+ */
2933
+ setDateRange(newDateRange) {
2934
+ const config = this.config();
2935
+ if (newDateRange.start) {
2936
+ const isValidRange = isSameOrBetween(newDateRange.start, config?.minDate, config?.maxDate);
2937
+ if (!isValidRange) {
2938
+ return false;
2939
+ }
2940
+ }
2941
+ if (newDateRange.end) {
2942
+ const isValidRange = isSameOrBetween(newDateRange.end, config?.minDate, config?.maxDate);
2943
+ if (!isValidRange) {
2944
+ return false;
2945
+ }
2946
+ }
2947
+ this.dateRange.set(newDateRange);
2948
+ return true;
2949
+ }
2950
+ timeSelected(newTime) {
2951
+ if (!newTime) {
2952
+ return;
2953
+ }
2954
+ // Break event cycle
2955
+ if (this.time?.getTime() === newTime.getTime()) {
2956
+ this.validateTime(newTime);
2957
+ return;
2958
+ }
2959
+ this.previousTime = this.time;
2960
+ this.time = newTime;
2961
+ const oldDate = this.getRelevantDate() ?? new Date();
2962
+ let newDate;
2963
+ if (this.disabledTime()) {
2964
+ // if time is disabled, ensure that 00:00:00 is displayed in any timezone
2965
+ newDate = createDate(oldDate);
2966
+ this.time = newDate;
2967
+ }
2968
+ else {
2969
+ newDate = createDate(oldDate, this.time.getHours(), this.time.getMinutes(), this.time.getSeconds(), this.time.getMilliseconds());
2970
+ }
2971
+ if (!this.config().enableDateRange) {
2972
+ this.setDate(newDate);
2973
+ }
2974
+ else {
2975
+ const newDateRange = this.dateRangeRole() === 'START'
2976
+ ? { start: newDate, end: this.dateRange()?.end }
2977
+ : { start: this.dateRange()?.start, end: newDate };
2978
+ this.setDateRange(newDateRange);
2979
+ }
2980
+ }
2981
+ toggleDisabledTime() {
2982
+ this.disabledTime.update(previous => !previous);
2983
+ this.config.update(c => {
2984
+ c.disabledTime = this.disabledTime();
2985
+ return c;
2986
+ });
2987
+ this.onDisabledTimeChanged();
2988
+ }
2989
+ onDisabledTimeChanged() {
2990
+ if (!this.config().enableDateRange) {
2991
+ if (this.disabledTime()) {
2992
+ const date = this.date() ?? new Date();
2993
+ const newTime = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0));
2994
+ this.timeSelected(newTime);
2995
+ }
2996
+ else if (this.previousTime) {
2997
+ this.timeSelected(this.previousTime);
2998
+ }
2999
+ else {
3000
+ this.timeSelected(new Date());
3001
+ }
3002
+ }
3003
+ }
3004
+ validateTime(date) {
3005
+ // wait for a cycle to initialize timepicker
3006
+ setTimeout(() => {
3007
+ const config = this.config();
3008
+ const timePicker = this.timePicker();
3009
+ if (!this.disabledTime() &&
3010
+ ((config.minDate && date < config.minDate) || (config.maxDate && date > config.maxDate))) {
3011
+ timePicker.invalidHours = timePicker.invalidMinutes = true;
3012
+ timePicker.invalidSeconds = timePicker.invalidMilliseconds = true;
3013
+ }
3014
+ else {
3015
+ timePicker.invalidHours = timePicker.invalidMinutes = false;
3016
+ timePicker.invalidSeconds = timePicker.invalidMilliseconds = false;
3017
+ }
3018
+ this.cdRef.markForCheck();
3019
+ });
3020
+ }
3021
+ /**
3022
+ * Handle selection in the day view.
3023
+ * @param selection - selected date.
3024
+ */
3025
+ selectionChange(selection) {
3026
+ const newDate = createDate(selection, this.time?.getHours(), this.time?.getMinutes(), this.time?.getSeconds(), this.time?.getMilliseconds());
3027
+ if (this.config().enableDateRange) {
3028
+ const rangeType = this.rangeType();
3029
+ let newDateRange = !rangeType || rangeType === 'START'
3030
+ ? { start: newDate, end: undefined }
3031
+ : { start: this.dateRange()?.start, end: newDate };
3032
+ let newRangeType = !rangeType || rangeType === 'START' ? 'START' : 'END';
3033
+ // The user selected a date before the current range start. Now the clicked day
3034
+ // is used as new start and the end is cleared
3035
+ if (newDateRange.start && newDateRange.end && newDateRange.end < newDateRange.start) {
3036
+ newDateRange = { start: newDateRange.end, end: undefined };
3037
+ newRangeType = 'START'; // Switch back to start so that the next selection is end
3038
+ }
3039
+ // Reset end range when we started start
3040
+ if (newRangeType === 'START' && newDateRange.end) {
3041
+ newDateRange.end = undefined;
3042
+ }
3043
+ const rangeValid = this.setDateRange(newDateRange);
3044
+ if (rangeValid) {
3045
+ // Toggle rangeType every time the user uses the datepicker to change the range
3046
+ this.rangeType.set(newRangeType === 'START' ? 'END' : 'START');
3047
+ }
3048
+ }
3049
+ else {
3050
+ this.focusedDate.set(newDate);
3051
+ this.setDate(newDate);
3052
+ }
3053
+ }
3054
+ /**
3055
+ * Handle month/year changes
3056
+ * @param selection - the selected month or null of cancelled.
3057
+ */
3058
+ activeMonthChange(selection) {
3059
+ if (selection) {
3060
+ this.focusedDate.set(changeDay(selection, this.actualFocusedDate().getDate()));
3061
+ const config = this.config();
3062
+ if (config.onlyMonthSelection) {
3063
+ if (config.enableDateRange) {
3064
+ this.selectionChange(selection);
3065
+ }
3066
+ else {
3067
+ this.setDate(selection);
3068
+ }
3069
+ }
3070
+ }
3071
+ this.view.set(this.monthViewSwitchTo);
3072
+ }
3073
+ /**
3074
+ * Handle year changes
3075
+ * @param selection - the selected year or null of cancelled.
3076
+ */
3077
+ activeYearChange(selection) {
3078
+ if (selection) {
3079
+ selection.setMonth(this.actualFocusedDate().getMonth());
3080
+ this.focusedDate.set(changeDay(selection, this.actualFocusedDate().getDate()));
3081
+ }
3082
+ this.view.set(this.yearViewSwitchTo);
3083
+ }
3084
+ /**
3085
+ * Focus the active cell in view.
3086
+ * The function is required to transfer the focus from input to the active date cell.
3087
+ */
3088
+ focusActiveCell() {
3089
+ this.activeView()?.focusActiveCell();
3090
+ }
3091
+ onActiveHoverChange(event) {
3092
+ this.activeHover.set(event);
3093
+ }
3094
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiDatepickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3095
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: SiDatepickerComponent, isStandalone: true, selector: "si-datepicker", inputs: { focusedDate: { classPropertyName: "focusedDate", publicName: "focusedDate", isSignal: true, isRequired: false, transformFunction: null }, date: { classPropertyName: "date", publicName: "date", isSignal: true, isRequired: false, transformFunction: null }, dateRange: { classPropertyName: "dateRange", publicName: "dateRange", isSignal: true, isRequired: false, transformFunction: null }, dateRangeRole: { classPropertyName: "dateRangeRole", publicName: "dateRangeRole", isSignal: true, isRequired: false, transformFunction: null }, initialFocus: { classPropertyName: "initialFocus", publicName: "initialFocus", isSignal: true, isRequired: false, transformFunction: null }, disabledTime: { classPropertyName: "disabledTime", publicName: "disabledTime", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, previousLabel: { classPropertyName: "previousLabel", publicName: "previousLabel", isSignal: true, isRequired: false, transformFunction: null }, nextLabel: { classPropertyName: "nextLabel", publicName: "nextLabel", isSignal: true, isRequired: false, transformFunction: null }, calenderWeekLabel: { classPropertyName: "calenderWeekLabel", publicName: "calenderWeekLabel", isSignal: true, isRequired: false, transformFunction: null }, time12h: { classPropertyName: "time12h", publicName: "time12h", isSignal: true, isRequired: false, transformFunction: null }, rangeType: { classPropertyName: "rangeType", publicName: "rangeType", isSignal: true, isRequired: false, transformFunction: null }, minMonth: { classPropertyName: "minMonth", publicName: "minMonth", isSignal: true, isRequired: false, transformFunction: null }, maxMonth: { classPropertyName: "maxMonth", publicName: "maxMonth", isSignal: true, isRequired: false, transformFunction: null }, hideTimeToggle: { classPropertyName: "hideTimeToggle", publicName: "hideTimeToggle", isSignal: true, isRequired: false, transformFunction: null }, hideCalendar: { classPropertyName: "hideCalendar", publicName: "hideCalendar", isSignal: true, isRequired: false, transformFunction: null }, timepickerLabel: { classPropertyName: "timepickerLabel", publicName: "timepickerLabel", isSignal: true, isRequired: false, transformFunction: null }, activeHover: { classPropertyName: "activeHover", publicName: "activeHover", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { focusedDate: "focusedDateChange", date: "dateChange", dateRange: "dateRangeChange", disabledTime: "disabledTimeChange", config: "configChange", rangeType: "rangeTypeChange", activeHover: "activeHoverChange" }, viewQueries: [{ propertyName: "timePicker", first: true, predicate: SiTimepickerComponent, descendants: true, isSignal: true }, { propertyName: "daySelection", first: true, predicate: SiDaySelectionComponent, descendants: true, isSignal: true }, { propertyName: "monthSelection", first: true, predicate: SiMonthSelectionComponent, descendants: true, isSignal: true }, { propertyName: "yearSelection", first: true, predicate: SiYearSelectionComponent, descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: "@if (!hideCalendar()) {\n <div class=\"text-center pb-6 calendar\">\n @switch (view()) {\n @case ('year') {\n <si-year-selection\n [focusedDate]=\"actualFocusedDate()\"\n [startDate]=\"startDate\"\n [endDate]=\"endDate\"\n [minDate]=\"config().minDate\"\n [maxDate]=\"config().maxDate\"\n [minMonth]=\"minMonth()\"\n [maxMonth]=\"maxMonth()\"\n [isRangeSelection]=\"config().enableDateRange!\"\n [previousLabel]=\"previousLabel() | translate\"\n [nextLabel]=\"nextLabel() | translate\"\n (selectedValueChange)=\"activeYearChange($event)\"\n />\n }\n @case ('month') {\n <si-month-selection\n [startDate]=\"startDate\"\n [endDate]=\"endDate\"\n [months]=\"months\"\n [minDate]=\"config().minDate\"\n [maxDate]=\"config().maxDate\"\n [minMonth]=\"minMonth()\"\n [maxMonth]=\"maxMonth()\"\n [isRangeSelection]=\"config().enableDateRange!\"\n [previewRange]=\"rangeType() === 'END'\"\n [previousLabel]=\"previousLabel() | translate\"\n [nextLabel]=\"nextLabel() | translate\"\n [activeHover]=\"activeHover()\"\n [focusedDate]=\"actualFocusedDate()\"\n (activeHoverChange)=\"onActiveHoverChange($event)\"\n (focusedDateChange)=\"focusedDate.set($event)\"\n (selectedValueChange)=\"activeMonthChange($event)\"\n (viewChange)=\"view.set($event)\"\n />\n }\n @case ('week') {\n <si-day-selection\n [initialFocus]=\"forceFocus()\"\n [startDate]=\"startDate\"\n [endDate]=\"dateRange()?.end\"\n [isRangeSelection]=\"config().enableDateRange!\"\n [previewRange]=\"rangeType() === 'END'\"\n [hideWeekNumbers]=\"hideWeekNumbers\"\n [minDate]=\"config().minDate\"\n [maxDate]=\"config().maxDate\"\n [minMonth]=\"minMonth()\"\n [weekStartDay]=\"weekStartDay\"\n [calenderWeekLabel]=\"calenderWeekLabel()\"\n [previousLabel]=\"previousLabel() | translate\"\n [nextLabel]=\"nextLabel() | translate\"\n [todayLabel]=\"config().todayText\"\n [activeHover]=\"activeHover()\"\n [focusedDate]=\"actualFocusedDate()\"\n (activeHoverChange)=\"onActiveHoverChange($event)\"\n (focusedDateChange)=\"focusedDate.set($event)\"\n (selectedValueChange)=\"selectionChange($event!)\"\n (viewChange)=\"view.set($event)\"\n />\n }\n }\n </div>\n}\n@if (this.config().showTime) {\n <div\n class=\"timepicker-container px-9 pb-6\"\n [class.pt-6]=\"!hideCalendar()\"\n [class.border-top]=\"!hideCalendar()\"\n >\n @if (!config().mandatoryTime && !hideTimeToggle()) {\n <div class=\"mb-5 form-check form-switch\">\n <input\n type=\"checkbox\"\n class=\"form-check-input\"\n role=\"switch\"\n [id]=\"switchId\"\n [checked]=\"!disabledTime()\"\n (change)=\"toggleDisabledTime()\"\n />\n <label class=\"form-check-label\" [for]=\"switchId\">{{\n includeTimeLabel() | translate\n }}</label>\n </div>\n }\n <div class=\"mt-auto\">\n @if (timepickerLabel()) {\n <label class=\"form-label\" [for]=\"timepickerId\">{{ timepickerLabel() | translate }}</label>\n }\n <si-timepicker\n #timePicker\n [id]=\"timepickerId\"\n [ngModel]=\"time\"\n [disabled]=\"disabledTime()\"\n [hoursLabel]=\"config().hoursLabel ?? timePicker.hoursLabel()\"\n [minutesLabel]=\"config().minutesLabel ?? timePicker.minutesLabel()\"\n [secondsLabel]=\"config().secondsLabel ?? timePicker.secondsLabel()\"\n [millisecondsLabel]=\"config().millisecondsLabel ?? timePicker.millisecondsLabel()\"\n [hideLabels]=\"config().hideLabels ?? timePicker.hideLabels()\"\n [hoursAriaLabel]=\"config().hoursAriaLabel ?? timePicker.hoursAriaLabel()\"\n [minutesAriaLabel]=\"config().minutesAriaLabel ?? timePicker.minutesAriaLabel()\"\n [secondsAriaLabel]=\"config().secondsAriaLabel ?? timePicker.secondsAriaLabel()\"\n [millisecondsAriaLabel]=\"\n config().millisecondsAriaLabel ?? timePicker.millisecondsAriaLabel()\n \"\n [hoursPlaceholder]=\"config().hoursPlaceholder ?? timePicker.hoursPlaceholder()\"\n [minutesPlaceholder]=\"config().minutesPlaceholder ?? timePicker.minutesPlaceholder()\"\n [secondsPlaceholder]=\"config().secondsPlaceholder ?? timePicker.secondsPlaceholder()\"\n [millisecondsPlaceholder]=\"\n config().millisecondsPlaceholder ?? timePicker.millisecondsPlaceholder()\n \"\n [meridians]=\"config().meridians ?? timePicker.meridians()\"\n [meridiansLabel]=\"config().meridiansLabel ?? timePicker.meridiansLabel()\"\n [meridiansAriaLabel]=\"config().meridiansAriaLabel ?? timePicker.meridiansAriaLabel()\"\n [showMinutes]=\"config().showMinutes ?? true\"\n [showSeconds]=\"config().showSeconds ?? false\"\n [showMilliseconds]=\"config().showMilliseconds ?? false\"\n [showMeridian]=\"time12h()\"\n (ngModelChange)=\"timeSelected($event)\"\n />\n </div>\n </div>\n}\n", styles: [":host ::ng-deep .selection .month:not(.disabled):hover,:host ::ng-deep .selection .year:not(.disabled):hover,:host ::ng-deep .year:not(.disabled):not(.selected):hover,:host ::ng-deep .month:not(.disabled):not(.selected):hover,:host ::ng-deep .day:not(.disabled):not(.selected):hover{background:var(--element-base-1-hover);color:var(--element-ui-0)}:host ::ng-deep .year,:host ::ng-deep .month,:host ::ng-deep .day{block-size:32px;line-height:32px;inline-size:100%}:host ::ng-deep .day{inline-size:32px}:host ::ng-deep .year,:host ::ng-deep .month,:host ::ng-deep .day{margin-inline:auto;position:relative;border:unset;background-color:unset;padding:0;cursor:pointer;border-radius:var(--element-button-radius)}:host{background:var(--element-base-1);border-radius:var(--element-radius-2);display:flex;flex-direction:column;inline-size:348px}:host ::ng-deep .header,:host ::ng-deep .footer{display:flex;align-items:center}:host ::ng-deep .header{padding-block-start:12px;padding-block-end:16px;padding-inline:32px;border-block-end:1px solid var(--element-ui-4)}:host ::ng-deep .header a{text-decoration:none;cursor:pointer}:host ::ng-deep .footer{margin-block-start:4px;text-align:center}:host ::ng-deep table{inline-size:100%;border-collapse:separate;border-spacing:0 3px;table-layout:fixed;margin-block-end:-3px}:host ::ng-deep .day.selected{background:var(--element-ui-0);color:var(--element-base-1)}:host ::ng-deep .month.selected{background:var(--element-ui-0);color:var(--element-base-1)}:host ::ng-deep .year.selected{background:var(--element-ui-0);color:var(--element-base-1)}:host ::ng-deep td[role=gridcell]{text-align:center}:host ::ng-deep th{font-weight:400;text-align:center;block-size:32px}:host ::ng-deep .week-num,:host ::ng-deep th{font-size:.75rem;color:var(--element-text-secondary);inline-size:32px;cursor:default}:host ::ng-deep .today.selected:before{border-color:var(--element-ui-5)}:host ::ng-deep .today:before{position:absolute;content:\"\";inset:1px;border:1px solid var(--element-ui-1);border-radius:var(--element-radius-2);display:inline-block}:host ::ng-deep .selection .month,:host ::ng-deep .selection .year{block-size:30px;line-height:30px;cursor:pointer}:host ::ng-deep .selection .month{inline-size:50%}:host ::ng-deep .selection .year{inline-size:33.3%}:host ::ng-deep .disabled{color:var(--element-text-disabled);font-weight:400!important;cursor:default!important}:host ::ng-deep .range{background-color:var(--element-ui-4)}:host ::ng-deep .range:hover{background:var(--element-base-1-hover)}:host ::ng-deep .range:hover div.si-title-1:hover{background:transparent}:host ::ng-deep .range-hover{background-color:var(--element-base-1-hover)}:host ::ng-deep .range-hover-end{border-start-end-radius:var(--element-button-radius);border-end-end-radius:var(--element-button-radius)}:host ::ng-deep td:is(.range-start,.range-end){background:var(--element-ui-0);color:var(--element-base-1)}:host ::ng-deep td:is(.range-start,.range-end) div.si-title-1:hover,:host ::ng-deep td:is(.range-start,.range-end) div.si-body-1:hover{background:transparent;color:var(--element-base-1)}:host ::ng-deep td:is(.range-start,.range-end) .today:before{border-color:var(--element-ui-5)}:host ::ng-deep td.range-start{border-start-start-radius:var(--element-button-radius);border-end-start-radius:var(--element-button-radius)}:host ::ng-deep td.range-end{border-start-end-radius:var(--element-button-radius);border-end-end-radius:var(--element-button-radius)}:host ::ng-deep .calendar-button{font-weight:700;font-size:.875rem;line-height:1.143;color:var(--element-text-active);min-inline-size:0!important}:host ::ng-deep .calendar{block-size:28em}:host ::ng-deep .timepicker-container{display:flex;flex:1 1 auto;flex-direction:column}\n"], dependencies: [{ kind: "component", type: SiYearSelectionComponent, selector: "si-year-selection", inputs: ["focusedDate"], outputs: ["focusedDateChange", "yearRangeChange"] }, { kind: "component", type: SiMonthSelectionComponent, selector: "si-month-selection", inputs: ["months", "focusedDate"], outputs: ["focusedDateChange", "activeMonthChange", "viewChange"] }, { kind: "component", type: SiDaySelectionComponent, selector: "si-day-selection", inputs: ["hideWeekNumbers", "weekStartDay", "focusedDate", "todayLabel", "calenderWeekLabel"], outputs: ["focusedDateChange", "activeMonthChange", "viewChange"] }, { kind: "component", type: SiTimepickerComponent, selector: "si-timepicker", inputs: ["id", "disabled", "hoursLabel", "minutesLabel", "secondsLabel", "millisecondsLabel", "hideLabels", "hoursAriaLabel", "minutesAriaLabel", "secondsAriaLabel", "millisecondsAriaLabel", "hoursPlaceholder", "minutesPlaceholder", "secondsPlaceholder", "millisecondsPlaceholder", "meridians", "meridiansLabel", "meridiansAriaLabel", "showMinutes", "showSeconds", "showMilliseconds", "showMeridian", "min", "max", "readonly"], outputs: ["isValid", "meridianChange", "inputCompleted"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: SiTranslateModule }, { kind: "pipe", type: i2.SiTranslatePipe, name: "translate" }] });
3096
+ }
3097
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiDatepickerComponent, decorators: [{
3098
+ type: Component,
3099
+ args: [{ selector: 'si-datepicker', imports: [
3100
+ SiYearSelectionComponent,
3101
+ SiMonthSelectionComponent,
3102
+ SiDaySelectionComponent,
3103
+ SiTimepickerComponent,
3104
+ FormsModule,
3105
+ SiTranslateModule
3106
+ ], template: "@if (!hideCalendar()) {\n <div class=\"text-center pb-6 calendar\">\n @switch (view()) {\n @case ('year') {\n <si-year-selection\n [focusedDate]=\"actualFocusedDate()\"\n [startDate]=\"startDate\"\n [endDate]=\"endDate\"\n [minDate]=\"config().minDate\"\n [maxDate]=\"config().maxDate\"\n [minMonth]=\"minMonth()\"\n [maxMonth]=\"maxMonth()\"\n [isRangeSelection]=\"config().enableDateRange!\"\n [previousLabel]=\"previousLabel() | translate\"\n [nextLabel]=\"nextLabel() | translate\"\n (selectedValueChange)=\"activeYearChange($event)\"\n />\n }\n @case ('month') {\n <si-month-selection\n [startDate]=\"startDate\"\n [endDate]=\"endDate\"\n [months]=\"months\"\n [minDate]=\"config().minDate\"\n [maxDate]=\"config().maxDate\"\n [minMonth]=\"minMonth()\"\n [maxMonth]=\"maxMonth()\"\n [isRangeSelection]=\"config().enableDateRange!\"\n [previewRange]=\"rangeType() === 'END'\"\n [previousLabel]=\"previousLabel() | translate\"\n [nextLabel]=\"nextLabel() | translate\"\n [activeHover]=\"activeHover()\"\n [focusedDate]=\"actualFocusedDate()\"\n (activeHoverChange)=\"onActiveHoverChange($event)\"\n (focusedDateChange)=\"focusedDate.set($event)\"\n (selectedValueChange)=\"activeMonthChange($event)\"\n (viewChange)=\"view.set($event)\"\n />\n }\n @case ('week') {\n <si-day-selection\n [initialFocus]=\"forceFocus()\"\n [startDate]=\"startDate\"\n [endDate]=\"dateRange()?.end\"\n [isRangeSelection]=\"config().enableDateRange!\"\n [previewRange]=\"rangeType() === 'END'\"\n [hideWeekNumbers]=\"hideWeekNumbers\"\n [minDate]=\"config().minDate\"\n [maxDate]=\"config().maxDate\"\n [minMonth]=\"minMonth()\"\n [weekStartDay]=\"weekStartDay\"\n [calenderWeekLabel]=\"calenderWeekLabel()\"\n [previousLabel]=\"previousLabel() | translate\"\n [nextLabel]=\"nextLabel() | translate\"\n [todayLabel]=\"config().todayText\"\n [activeHover]=\"activeHover()\"\n [focusedDate]=\"actualFocusedDate()\"\n (activeHoverChange)=\"onActiveHoverChange($event)\"\n (focusedDateChange)=\"focusedDate.set($event)\"\n (selectedValueChange)=\"selectionChange($event!)\"\n (viewChange)=\"view.set($event)\"\n />\n }\n }\n </div>\n}\n@if (this.config().showTime) {\n <div\n class=\"timepicker-container px-9 pb-6\"\n [class.pt-6]=\"!hideCalendar()\"\n [class.border-top]=\"!hideCalendar()\"\n >\n @if (!config().mandatoryTime && !hideTimeToggle()) {\n <div class=\"mb-5 form-check form-switch\">\n <input\n type=\"checkbox\"\n class=\"form-check-input\"\n role=\"switch\"\n [id]=\"switchId\"\n [checked]=\"!disabledTime()\"\n (change)=\"toggleDisabledTime()\"\n />\n <label class=\"form-check-label\" [for]=\"switchId\">{{\n includeTimeLabel() | translate\n }}</label>\n </div>\n }\n <div class=\"mt-auto\">\n @if (timepickerLabel()) {\n <label class=\"form-label\" [for]=\"timepickerId\">{{ timepickerLabel() | translate }}</label>\n }\n <si-timepicker\n #timePicker\n [id]=\"timepickerId\"\n [ngModel]=\"time\"\n [disabled]=\"disabledTime()\"\n [hoursLabel]=\"config().hoursLabel ?? timePicker.hoursLabel()\"\n [minutesLabel]=\"config().minutesLabel ?? timePicker.minutesLabel()\"\n [secondsLabel]=\"config().secondsLabel ?? timePicker.secondsLabel()\"\n [millisecondsLabel]=\"config().millisecondsLabel ?? timePicker.millisecondsLabel()\"\n [hideLabels]=\"config().hideLabels ?? timePicker.hideLabels()\"\n [hoursAriaLabel]=\"config().hoursAriaLabel ?? timePicker.hoursAriaLabel()\"\n [minutesAriaLabel]=\"config().minutesAriaLabel ?? timePicker.minutesAriaLabel()\"\n [secondsAriaLabel]=\"config().secondsAriaLabel ?? timePicker.secondsAriaLabel()\"\n [millisecondsAriaLabel]=\"\n config().millisecondsAriaLabel ?? timePicker.millisecondsAriaLabel()\n \"\n [hoursPlaceholder]=\"config().hoursPlaceholder ?? timePicker.hoursPlaceholder()\"\n [minutesPlaceholder]=\"config().minutesPlaceholder ?? timePicker.minutesPlaceholder()\"\n [secondsPlaceholder]=\"config().secondsPlaceholder ?? timePicker.secondsPlaceholder()\"\n [millisecondsPlaceholder]=\"\n config().millisecondsPlaceholder ?? timePicker.millisecondsPlaceholder()\n \"\n [meridians]=\"config().meridians ?? timePicker.meridians()\"\n [meridiansLabel]=\"config().meridiansLabel ?? timePicker.meridiansLabel()\"\n [meridiansAriaLabel]=\"config().meridiansAriaLabel ?? timePicker.meridiansAriaLabel()\"\n [showMinutes]=\"config().showMinutes ?? true\"\n [showSeconds]=\"config().showSeconds ?? false\"\n [showMilliseconds]=\"config().showMilliseconds ?? false\"\n [showMeridian]=\"time12h()\"\n (ngModelChange)=\"timeSelected($event)\"\n />\n </div>\n </div>\n}\n", styles: [":host ::ng-deep .selection .month:not(.disabled):hover,:host ::ng-deep .selection .year:not(.disabled):hover,:host ::ng-deep .year:not(.disabled):not(.selected):hover,:host ::ng-deep .month:not(.disabled):not(.selected):hover,:host ::ng-deep .day:not(.disabled):not(.selected):hover{background:var(--element-base-1-hover);color:var(--element-ui-0)}:host ::ng-deep .year,:host ::ng-deep .month,:host ::ng-deep .day{block-size:32px;line-height:32px;inline-size:100%}:host ::ng-deep .day{inline-size:32px}:host ::ng-deep .year,:host ::ng-deep .month,:host ::ng-deep .day{margin-inline:auto;position:relative;border:unset;background-color:unset;padding:0;cursor:pointer;border-radius:var(--element-button-radius)}:host{background:var(--element-base-1);border-radius:var(--element-radius-2);display:flex;flex-direction:column;inline-size:348px}:host ::ng-deep .header,:host ::ng-deep .footer{display:flex;align-items:center}:host ::ng-deep .header{padding-block-start:12px;padding-block-end:16px;padding-inline:32px;border-block-end:1px solid var(--element-ui-4)}:host ::ng-deep .header a{text-decoration:none;cursor:pointer}:host ::ng-deep .footer{margin-block-start:4px;text-align:center}:host ::ng-deep table{inline-size:100%;border-collapse:separate;border-spacing:0 3px;table-layout:fixed;margin-block-end:-3px}:host ::ng-deep .day.selected{background:var(--element-ui-0);color:var(--element-base-1)}:host ::ng-deep .month.selected{background:var(--element-ui-0);color:var(--element-base-1)}:host ::ng-deep .year.selected{background:var(--element-ui-0);color:var(--element-base-1)}:host ::ng-deep td[role=gridcell]{text-align:center}:host ::ng-deep th{font-weight:400;text-align:center;block-size:32px}:host ::ng-deep .week-num,:host ::ng-deep th{font-size:.75rem;color:var(--element-text-secondary);inline-size:32px;cursor:default}:host ::ng-deep .today.selected:before{border-color:var(--element-ui-5)}:host ::ng-deep .today:before{position:absolute;content:\"\";inset:1px;border:1px solid var(--element-ui-1);border-radius:var(--element-radius-2);display:inline-block}:host ::ng-deep .selection .month,:host ::ng-deep .selection .year{block-size:30px;line-height:30px;cursor:pointer}:host ::ng-deep .selection .month{inline-size:50%}:host ::ng-deep .selection .year{inline-size:33.3%}:host ::ng-deep .disabled{color:var(--element-text-disabled);font-weight:400!important;cursor:default!important}:host ::ng-deep .range{background-color:var(--element-ui-4)}:host ::ng-deep .range:hover{background:var(--element-base-1-hover)}:host ::ng-deep .range:hover div.si-title-1:hover{background:transparent}:host ::ng-deep .range-hover{background-color:var(--element-base-1-hover)}:host ::ng-deep .range-hover-end{border-start-end-radius:var(--element-button-radius);border-end-end-radius:var(--element-button-radius)}:host ::ng-deep td:is(.range-start,.range-end){background:var(--element-ui-0);color:var(--element-base-1)}:host ::ng-deep td:is(.range-start,.range-end) div.si-title-1:hover,:host ::ng-deep td:is(.range-start,.range-end) div.si-body-1:hover{background:transparent;color:var(--element-base-1)}:host ::ng-deep td:is(.range-start,.range-end) .today:before{border-color:var(--element-ui-5)}:host ::ng-deep td.range-start{border-start-start-radius:var(--element-button-radius);border-end-start-radius:var(--element-button-radius)}:host ::ng-deep td.range-end{border-start-end-radius:var(--element-button-radius);border-end-end-radius:var(--element-button-radius)}:host ::ng-deep .calendar-button{font-weight:700;font-size:.875rem;line-height:1.143;color:var(--element-text-active);min-inline-size:0!important}:host ::ng-deep .calendar{block-size:28em}:host ::ng-deep .timepicker-container{display:flex;flex:1 1 auto;flex-direction:column}\n"] }]
3107
+ }], ctorParameters: () => [] });
3108
+
3109
+ /**
3110
+ * Copyright Siemens 2016 - 2025.
3111
+ * SPDX-License-Identifier: MIT
3112
+ */
3113
+ class SiDatepickerOverlayComponent {
3114
+ minMonth = signal(undefined);
3115
+ maxMonth = signal(undefined);
3116
+ datepicker = viewChild.required(SiDatepickerComponent);
3117
+ /**
3118
+ * {@inheritDoc SiDatepickerComponent#initialFocus}
3119
+ * @defaultValue false
3120
+ */
3121
+ initialFocus = input(false, { transform: booleanAttribute });
3122
+ /**
3123
+ * {@inheritDoc SiDatepickerComponent#config}
3124
+ * @defaultValue
3125
+ * ```
3126
+ * {}
3127
+ * ```
3128
+ */
3129
+ config = input({});
3130
+ /**
3131
+ * {@inheritDoc SiDatepickerComponent#date}
3132
+ */
3133
+ date = model();
3134
+ /**
3135
+ * {@inheritDoc SiDatepickerComponent#dateRange}
3136
+ */
3137
+ dateRange = model();
3138
+ /**
3139
+ * {@inheritDoc SiDatepickerComponent#rangeType}
3140
+ */
3141
+ rangeType = model();
3142
+ /**
3143
+ * {@inheritDoc SiDatepickerComponent#time12h}
3144
+ * @defaultValue false
3145
+ */
3146
+ time12h = input(false, { transform: booleanAttribute });
3147
+ /**
3148
+ * Emits an event to notify about disabling the time from the datepicker.
3149
+ * When time is disable, we construct a pure date object in UTC 00:00:00 time.
3150
+ */
3151
+ disabledTimeChange = output();
3152
+ /**
3153
+ * @deprecated Property provides internal information that should not be used.
3154
+ *
3155
+ * @defaultValue false
3156
+ */
3157
+ isFocused = false;
3158
+ document = inject(DOCUMENT);
3159
+ elementRef = inject(ElementRef);
3160
+ focusMonitor = inject(FocusMonitor);
3161
+ focusTrapFactory = inject(ConfigurableFocusTrapFactory);
3162
+ focusTrap;
3163
+ previousActiveElement;
3164
+ disableTime = false;
3165
+ activeHover;
3166
+ isTwoMonthDateRange = computed(() => !!this.config().enableDateRange &&
3167
+ (!!this.config().enableTwoMonthDateRange || !!this.config().showTime));
3168
+ firstDatepickerConfig = signal({});
3169
+ secondDatepickerConfig = signal({});
3170
+ /**
3171
+ * Indicate that the overlay is opened in small screen.
3172
+ * A modal dialog animation display when true and a wrapped two month calendar layout is displayed.
3173
+ *
3174
+ * @defaultValue false
3175
+ */
3176
+ isMobile = input(false);
3177
+ completeAnimation = signal(false);
3178
+ ngOnChanges(changes) {
3179
+ if (changes.config) {
3180
+ const config = this.config();
3181
+ this.firstDatepickerConfig.set(!this.isTwoMonthDateRange ? config : { ...config, hideLabels: true });
3182
+ this.secondDatepickerConfig.set({ ...config, hideLabels: true });
3183
+ }
3184
+ const dateRange = this.dateRange();
3185
+ if (changes.config?.currentValue?.onlyMonthSelection &&
3186
+ this.isTwoMonthDateRange() &&
3187
+ dateRange?.start) {
3188
+ this.minMonth.set(new Date(dateRange?.start.getFullYear(), 0, 1));
3189
+ }
3190
+ this.rangeType.set('START');
3191
+ if (isValid(changes.dateRange?.currentValue?.start) &&
3192
+ !isValid(changes.dateRange?.currentValue?.end)) {
3193
+ this.rangeType.set('END');
3194
+ }
3195
+ }
3196
+ ngOnInit() {
3197
+ this.focusTrap = this.focusTrapFactory.create(this.elementRef.nativeElement);
3198
+ this.previousActiveElement = this.document.activeElement ?? undefined;
3199
+ if (this.isMobile()) {
3200
+ setTimeout(() => this.completeAnimation.set(true), 150);
3201
+ }
3202
+ }
3203
+ ngAfterViewInit() {
3204
+ // Monitor focus events
3205
+ this.focusMonitor
3206
+ .monitor(this.elementRef, true)
3207
+ .subscribe(origin => (this.isFocused = origin !== undefined));
3208
+ }
3209
+ ngOnDestroy() {
3210
+ this.focusMonitor.stopMonitoring(this.elementRef);
3211
+ this.focusTrap.destroy();
3212
+ if (this.initialFocus() && this.previousActiveElement && 'focus' in this.previousActiveElement)
3213
+ this.previousActiveElement.focus();
3214
+ }
3215
+ /**
3216
+ * Focus active cell in the current datepicker view.
3217
+ */
3218
+ focusActiveCell() {
3219
+ this.datepicker().focusActiveCell();
3220
+ }
3221
+ firstDatepickerFocusDateChange(newFocusedDate) {
3222
+ if (!newFocusedDate) {
3223
+ return;
3224
+ }
3225
+ if (this.config()?.onlyMonthSelection) {
3226
+ this.minMonth.set(new Date(newFocusedDate.getFullYear() + 1, 0, 1));
3227
+ }
3228
+ else if (newFocusedDate !== this.maxMonth()) {
3229
+ this.minMonth.set(nextMonth(newFocusedDate));
3230
+ }
3231
+ }
3232
+ secondDatepickerFocusDateChange(newFocusedDate) {
3233
+ if (newFocusedDate && newFocusedDate !== this.minMonth()) {
3234
+ if (this.config()?.onlyMonthSelection) {
3235
+ this.maxMonth.set(new Date(newFocusedDate.getFullYear() - 1, 11, 31));
3236
+ }
3237
+ else {
3238
+ this.maxMonth.set(previousMonth(newFocusedDate));
3239
+ }
3240
+ }
3241
+ }
3242
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiDatepickerOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3243
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.6", type: SiDatepickerOverlayComponent, isStandalone: true, selector: "si-datepicker-overlay", inputs: { initialFocus: { classPropertyName: "initialFocus", publicName: "initialFocus", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, date: { classPropertyName: "date", publicName: "date", isSignal: true, isRequired: false, transformFunction: null }, dateRange: { classPropertyName: "dateRange", publicName: "dateRange", isSignal: true, isRequired: false, transformFunction: null }, rangeType: { classPropertyName: "rangeType", publicName: "rangeType", isSignal: true, isRequired: false, transformFunction: null }, time12h: { classPropertyName: "time12h", publicName: "time12h", isSignal: true, isRequired: false, transformFunction: null }, isMobile: { classPropertyName: "isMobile", publicName: "isMobile", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { date: "dateChange", dateRange: "dateRangeChange", rangeType: "rangeTypeChange", disabledTimeChange: "disabledTimeChange" }, host: { properties: { "class.flex-wrap": "isMobile()", "class.mobile-datepicker-overlay": "isMobile()", "class.fade": "isMobile()", "class.show": "completeAnimation()" }, classAttribute: "mt-md-1 d-flex elevation-2 rounded-2 overflow-auto align-items-stretch" }, viewQueries: [{ propertyName: "datepicker", first: true, predicate: SiDatepickerComponent, descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: `
3244
+ <si-datepicker
3245
+ #datepicker
3246
+ tabindex="-1"
3247
+ [initialFocus]="initialFocus()"
3248
+ [config]="firstDatepickerConfig()"
3249
+ [class.first-datepicker]="isTwoMonthDateRange() && !isMobile()"
3250
+ [class.first-datepicker-mobile]="isTwoMonthDateRange() && isMobile()"
3251
+ [date]="date()"
3252
+ [dateRange]="dateRange()"
3253
+ [dateRangeRole]="isTwoMonthDateRange() ? 'START' : undefined"
3254
+ [time12h]="time12h()"
3255
+ [timepickerLabel]="firstDatepickerConfig().startTimeLabel"
3256
+ [maxMonth]="maxMonth()"
3257
+ [rangeType]="rangeType()"
3258
+ [(activeHover)]="activeHover"
3259
+ (dateChange)="date.set($event)"
3260
+ (dateRangeChange)="dateRange.set($event)"
3261
+ (disabledTimeChange)="disableTime = $event; disabledTimeChange.emit($event)"
3262
+ (focusedDateChange)="firstDatepickerFocusDateChange($event)"
3263
+ (rangeTypeChange)="rangeType.set($event)"
3264
+ />
3265
+ @if (isTwoMonthDateRange()) {
3266
+ <si-datepicker
3267
+ #datepickerTwo
3268
+ class="mh-100 overflow-auto"
3269
+ tabindex="-1"
3270
+ dateRangeRole="END"
3271
+ [class.second-datepicker]="!isMobile()"
3272
+ [class.second-datepicker-mobile]="isMobile()"
3273
+ [hideTimeToggle]="true"
3274
+ [initialFocus]="initialFocus()"
3275
+ [config]="secondDatepickerConfig()"
3276
+ [date]="date()"
3277
+ [hideCalendar]="isMobile()"
3278
+ [minMonth]="minMonth()"
3279
+ [dateRange]="dateRange()"
3280
+ [disabledTime]="disableTime"
3281
+ [time12h]="time12h()"
3282
+ [timepickerLabel]="secondDatepickerConfig().endTimeLabel"
3283
+ [rangeType]="rangeType()"
3284
+ [(activeHover)]="activeHover"
3285
+ (dateRangeChange)="dateRange.set($event)"
3286
+ (focusedDateChange)="secondDatepickerFocusDateChange($event)"
3287
+ (rangeTypeChange)="rangeType.set($event)"
3288
+ />
3289
+ }
3290
+ `, isInline: true, styles: [":host{max-block-size:max-content;max-inline-size:min-content}:host.fade{transition:transform calc(.3s * var(--element-animations-enabled, 1)) ease-out;transform:translateY(-50px)}:host.show{transform:none}.mobile-datepicker-overlay{max-inline-size:348px}.first-datepicker{border-inline-end:0;border-start-end-radius:0;border-end-end-radius:0}.second-datepicker{border-inline-start:0;border-start-start-radius:0;border-end-start-radius:0}.first-datepicker-mobile{border-block-end:0;border-end-start-radius:0;border-end-end-radius:0}.second-datepicker-mobile{border-block-start:0;border-start-start-radius:0;border-start-end-radius:0}\n"], dependencies: [{ kind: "component", type: SiDatepickerComponent, selector: "si-datepicker", inputs: ["focusedDate", "date", "dateRange", "dateRangeRole", "initialFocus", "disabledTime", "config", "previousLabel", "nextLabel", "calenderWeekLabel", "time12h", "rangeType", "minMonth", "maxMonth", "hideTimeToggle", "hideCalendar", "timepickerLabel", "activeHover"], outputs: ["focusedDateChange", "dateChange", "dateRangeChange", "disabledTimeChange", "configChange", "rangeTypeChange", "activeHoverChange"] }, { kind: "ngmodule", type: A11yModule }], changeDetection: i0.ChangeDetectionStrategy.Default });
3291
+ }
3292
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiDatepickerOverlayComponent, decorators: [{
3293
+ type: Component,
3294
+ args: [{ selector: 'si-datepicker-overlay', host: {
3295
+ class: 'mt-md-1 d-flex elevation-2 rounded-2 overflow-auto align-items-stretch',
3296
+ '[class.flex-wrap]': 'isMobile()',
3297
+ '[class.mobile-datepicker-overlay]': 'isMobile()',
3298
+ '[class.fade]': 'isMobile()',
3299
+ '[class.show]': 'completeAnimation()'
3300
+ }, template: `
3301
+ <si-datepicker
3302
+ #datepicker
3303
+ tabindex="-1"
3304
+ [initialFocus]="initialFocus()"
3305
+ [config]="firstDatepickerConfig()"
3306
+ [class.first-datepicker]="isTwoMonthDateRange() && !isMobile()"
3307
+ [class.first-datepicker-mobile]="isTwoMonthDateRange() && isMobile()"
3308
+ [date]="date()"
3309
+ [dateRange]="dateRange()"
3310
+ [dateRangeRole]="isTwoMonthDateRange() ? 'START' : undefined"
3311
+ [time12h]="time12h()"
3312
+ [timepickerLabel]="firstDatepickerConfig().startTimeLabel"
3313
+ [maxMonth]="maxMonth()"
3314
+ [rangeType]="rangeType()"
3315
+ [(activeHover)]="activeHover"
3316
+ (dateChange)="date.set($event)"
3317
+ (dateRangeChange)="dateRange.set($event)"
3318
+ (disabledTimeChange)="disableTime = $event; disabledTimeChange.emit($event)"
3319
+ (focusedDateChange)="firstDatepickerFocusDateChange($event)"
3320
+ (rangeTypeChange)="rangeType.set($event)"
3321
+ />
3322
+ @if (isTwoMonthDateRange()) {
3323
+ <si-datepicker
3324
+ #datepickerTwo
3325
+ class="mh-100 overflow-auto"
3326
+ tabindex="-1"
3327
+ dateRangeRole="END"
3328
+ [class.second-datepicker]="!isMobile()"
3329
+ [class.second-datepicker-mobile]="isMobile()"
3330
+ [hideTimeToggle]="true"
3331
+ [initialFocus]="initialFocus()"
3332
+ [config]="secondDatepickerConfig()"
3333
+ [date]="date()"
3334
+ [hideCalendar]="isMobile()"
3335
+ [minMonth]="minMonth()"
3336
+ [dateRange]="dateRange()"
3337
+ [disabledTime]="disableTime"
3338
+ [time12h]="time12h()"
3339
+ [timepickerLabel]="secondDatepickerConfig().endTimeLabel"
3340
+ [rangeType]="rangeType()"
3341
+ [(activeHover)]="activeHover"
3342
+ (dateRangeChange)="dateRange.set($event)"
3343
+ (focusedDateChange)="secondDatepickerFocusDateChange($event)"
3344
+ (rangeTypeChange)="rangeType.set($event)"
3345
+ />
3346
+ }
3347
+ `, changeDetection: ChangeDetectionStrategy.Default, imports: [SiDatepickerComponent, A11yModule], styles: [":host{max-block-size:max-content;max-inline-size:min-content}:host.fade{transition:transform calc(.3s * var(--element-animations-enabled, 1)) ease-out;transform:translateY(-50px)}:host.show{transform:none}.mobile-datepicker-overlay{max-inline-size:348px}.first-datepicker{border-inline-end:0;border-start-end-radius:0;border-end-end-radius:0}.second-datepicker{border-inline-start:0;border-start-start-radius:0;border-end-start-radius:0}.first-datepicker-mobile{border-block-end:0;border-end-start-radius:0;border-end-end-radius:0}.second-datepicker-mobile{border-block-start:0;border-start-start-radius:0;border-start-end-radius:0}\n"] }]
3348
+ }] });
3349
+
3350
+ /**
3351
+ * Copyright Siemens 2016 - 2025.
3352
+ * SPDX-License-Identifier: MIT
3353
+ */
3354
+ // eslint-disable-next-line no-restricted-syntax
3355
+ var CloseCause;
3356
+ (function (CloseCause) {
3357
+ CloseCause["Backdrop"] = "backdrop";
3358
+ CloseCause["Detach"] = "detach";
3359
+ CloseCause["Escape"] = "escape";
3360
+ CloseCause["Select"] = "select";
3361
+ })(CloseCause || (CloseCause = {}));
3362
+ /**
3363
+ * Directive with the responsibility to open/close datepicker overlay.
3364
+ */
3365
+ class SiDatepickerOverlayDirective {
3366
+ /**
3367
+ * Position of the datepicker overlay. Accepts an array of positions or a single position.
3368
+ * The position will be chosen based on the first position that fits into the viewport.
3369
+ * The input is necessary since the positions between the siDatepicker directive and si-date-range
3370
+ * component are different.
3371
+ * @internal
3372
+ */
3373
+ placement = signal([
3374
+ {
3375
+ overlayX: 'start',
3376
+ overlayY: 'top',
3377
+ originX: 'start',
3378
+ originY: 'bottom'
3379
+ },
3380
+ {
3381
+ overlayX: 'start',
3382
+ overlayY: 'bottom',
3383
+ originX: 'start',
3384
+ originY: 'top'
3385
+ }
3386
+ ]);
3387
+ /**
3388
+ * Output event on closing datepicker e.g. by clicking backdrop or escape key.
3389
+ */
3390
+ siDatepickerClose = output();
3391
+ overlayRef;
3392
+ datepickerRef;
3393
+ autoCloseSelection = new Subject();
3394
+ /** Guard for siDatepickerClose event emitter to make sure the cause is emitter just once */
3395
+ ignoreClose = false;
3396
+ overlay = inject(Overlay);
3397
+ triggerElementRef = inject(ElementRef);
3398
+ mediaMatcher = inject(MediaMatcher);
3399
+ breakpointObserver = inject(BreakpointObserver);
3400
+ destroyRef = inject(DestroyRef);
3401
+ /**
3402
+ * When the media query matches on open the overlay is displayed like a modal dialog.
3403
+ * In case, users change the screen size to the matching media query we close the overlay
3404
+ * if it is open with a connected overlay strategy.
3405
+ */
3406
+ smallScreenQuery = `(max-width: ${BOOTSTRAP_BREAKPOINTS.mdMinimum}px) or (max-height: ${BOOTSTRAP_BREAKPOINTS.smMinimum}px)`;
3407
+ ngOnDestroy() {
3408
+ this.overlayRef?.dispose();
3409
+ this.datepickerRef = undefined;
3410
+ }
3411
+ /**
3412
+ * Toggle open/close overlay.
3413
+ * @param focus - move focus to the datepicker.
3414
+ * @param inputs - for datepicker.
3415
+ * @returns create datepicker overlay instance or undefined
3416
+ *
3417
+ * @deprecated Use {@link showOverlay} or {@link closeOverlay} instead.
3418
+ */
3419
+ toggleOverlay(focus, inputs) {
3420
+ if (!this.datepickerRef) {
3421
+ return this.showDatepicker().setInputs(inputs).focus(focus).datepickerRef;
3422
+ }
3423
+ else {
3424
+ return this.closeOverlay();
3425
+ }
3426
+ }
3427
+ /**
3428
+ * Show datepicker overlay.
3429
+ * @param focus - move focus to the datepicker.
3430
+ * @returns create datepicker overlay instance
3431
+ */
3432
+ showOverlay(focus = false, inputs) {
3433
+ return this.showDatepicker().setInputs(inputs).focus(focus).datepickerRef;
3434
+ }
3435
+ /**
3436
+ * Close datepicker.
3437
+ */
3438
+ closeOverlay() {
3439
+ if (this.overlayRef?.hasAttached()) {
3440
+ this.overlayRef?.detach();
3441
+ this.overlayRef?.dispose();
3442
+ }
3443
+ this.datepickerRef = undefined;
3444
+ return undefined;
3445
+ }
3446
+ /**
3447
+ * Focus active cell in datepicker.
3448
+ * @param focus - show transfer focus.
3449
+ * @returns current instance.
3450
+ */
3451
+ focus(focus = true) {
3452
+ if (focus) {
3453
+ this.datepickerRef?.setInput('initialFocus', true);
3454
+ this.datepickerRef?.instance.focusActiveCell();
3455
+ this.datepickerRef?.changeDetectorRef.markForCheck();
3456
+ }
3457
+ return this;
3458
+ }
3459
+ /** @deprecated Property provides internal information that should not be used. */
3460
+ isFocused() {
3461
+ return this.datepickerRef?.instance.isFocused ?? false;
3462
+ }
3463
+ /**
3464
+ * Indicate the datepicker is visible.
3465
+ * @returns is visible.
3466
+ */
3467
+ isShown() {
3468
+ return this.datepickerRef;
3469
+ }
3470
+ /** Set datepicker inputs */
3471
+ setInputs(inputs) {
3472
+ if (this.datepickerRef && inputs) {
3473
+ Object.entries(inputs).forEach(([key, value]) => {
3474
+ this.datepickerRef.setInput(key.toString(), value);
3475
+ });
3476
+ }
3477
+ return this;
3478
+ }
3479
+ /** Close overlay with cause select, which will recover the focus */
3480
+ closeAfterSelection() {
3481
+ this.autoCloseSelection.next();
3482
+ }
3483
+ /** Indicate whether the HTML element is a child of the datepicker overlay. */
3484
+ contains(element) {
3485
+ if (!element) {
3486
+ return false;
3487
+ }
3488
+ return this.overlayRef?.overlayElement?.contains(element) ?? false;
3489
+ }
3490
+ showDatepicker() {
3491
+ if (this.overlayRef?.hasAttached()) {
3492
+ return this;
3493
+ }
3494
+ // Since the connected overlay strategy has some limitations in small screens e.g.
3495
+ // the overlay is moved via style top without recalculating the (max)height which
3496
+ // can result in a cut of time picker.
3497
+ // To overcome this issue the overlay use the global position strategy in small screens.
3498
+ const smallScreen = this.mediaMatcher.matchMedia(this.smallScreenQuery).matches;
3499
+ if (smallScreen) {
3500
+ this.createMobileOverlay();
3501
+ }
3502
+ else {
3503
+ this.createDesktopOverlay();
3504
+ }
3505
+ this.closeStream(this.overlayRef)
3506
+ .pipe(takeUntilDestroyed(this.destroyRef), takeUntil(outputToObservable(this.siDatepickerClose)))
3507
+ .subscribe(cause => {
3508
+ // The handler is called multiple times since we need to listen to detach events
3509
+ if (this.datepickerRef && !this.ignoreClose) {
3510
+ this.ignoreClose = true;
3511
+ this.closeOverlay();
3512
+ this.ignoreClose = false;
3513
+ this.siDatepickerClose.emit(cause);
3514
+ }
3515
+ });
3516
+ const portal = new ComponentPortal(SiDatepickerOverlayComponent);
3517
+ this.datepickerRef = this.overlayRef.attach(portal);
3518
+ if (smallScreen) {
3519
+ this.datepickerRef.setInput('isMobile', true);
3520
+ }
3521
+ // Automatically close the overlay if we reach the small screen breakpoint
3522
+ // and the picker does not use the global position strategy.
3523
+ this.breakpointObserver
3524
+ .observe(this.smallScreenQuery)
3525
+ .pipe(takeUntilDestroyed(this.destroyRef), takeUntil(outputToObservable(this.siDatepickerClose)), skip(1))
3526
+ .subscribe(() => this.closeOverlay());
3527
+ return this;
3528
+ }
3529
+ createMobileOverlay() {
3530
+ this.overlayRef = this.overlay.create({
3531
+ positionStrategy: this.overlay.position().global().centerHorizontally().centerVertically(),
3532
+ direction: isRTL() ? 'rtl' : 'ltr',
3533
+ hasBackdrop: true,
3534
+ backdropClass: 'modal-backdrop'
3535
+ });
3536
+ }
3537
+ createDesktopOverlay() {
3538
+ const popoverPositions = getOverlayPositions(this.triggerElementRef, this.placement(), false);
3539
+ this.overlayRef = this.overlay.create({
3540
+ positionStrategy: this.overlay
3541
+ .position()
3542
+ .flexibleConnectedTo(this.triggerElementRef)
3543
+ .withPositions(popoverPositions)
3544
+ .withPush(true)
3545
+ .withGrowAfterOpen(true)
3546
+ .withFlexibleDimensions(true)
3547
+ .withViewportMargin(4),
3548
+ direction: isRTL() ? 'rtl' : 'ltr',
3549
+ hasBackdrop: true,
3550
+ backdropClass: 'cdk-overlay-transparent-backdrop'
3551
+ });
3552
+ }
3553
+ /**
3554
+ * Merge events which shall close the overlay
3555
+ * @param overlayRef - source for backdrop, detach or escape events.
3556
+ * @returns merged observable
3557
+ */
3558
+ closeStream(overlayRef) {
3559
+ return merge(this.autoCloseSelection.pipe(map(() => CloseCause.Select)), overlayRef.backdropClick().pipe(map(() => CloseCause.Backdrop)), overlayRef.detachments().pipe(map(() => CloseCause.Detach)), overlayRef.keydownEvents().pipe(filter(event => event.key === 'Escape'), tap(event => event.stopPropagation()), // ESC handled, prevent closing modal, etc.
3560
+ map(() => CloseCause.Escape)));
3561
+ }
3562
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiDatepickerOverlayDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
3563
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.6", type: SiDatepickerOverlayDirective, isStandalone: true, selector: "[siDatepickerOverlay]", outputs: { siDatepickerClose: "siDatepickerClose" }, exportAs: ["siDatepickerOverlay"], ngImport: i0 });
3564
+ }
3565
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiDatepickerOverlayDirective, decorators: [{
3566
+ type: Directive,
3567
+ args: [{
3568
+ selector: '[siDatepickerOverlay]',
3569
+ exportAs: 'siDatepickerOverlay'
3570
+ }]
3571
+ }] });
3572
+
3573
+ /**
3574
+ * Copyright Siemens 2016 - 2025.
3575
+ * SPDX-License-Identifier: MIT
3576
+ */
3577
+ class SiDatepickerDirective extends SiDateInputDirective {
3578
+ /**
3579
+ * Automatically close overlay on date selection.
3580
+ * Do not use this behavior with config showTime = true, because it
3581
+ * will close the overlay when the user change one of the time units.
3582
+ *
3583
+ * @defaultValue false
3584
+ */
3585
+ autoClose = input(false, { transform: booleanAttribute });
3586
+ /**
3587
+ * @deprecated Property has no effect and will be removed without replacement.
3588
+ *
3589
+ * @defaultValue inject(ElementRef)
3590
+ */
3591
+ triggeringInput = input(inject(ElementRef));
3592
+ /**
3593
+ * During focus on close the datepicker will not show since we recover the focus on element.
3594
+ * The focus on close is only relevant when the directive is configured without a calendar button.
3595
+ */
3596
+ overlaySubscriptions;
3597
+ externalTrigger;
3598
+ overlayToggle = inject(SiDatepickerOverlayDirective);
3599
+ ngAfterViewInit() {
3600
+ // Update datepicker with new date value
3601
+ this.dateChange.subscribe(date => this.overlayToggle.setInputs({ date }));
3602
+ }
3603
+ /** @internal */
3604
+ touch() {
3605
+ this.onTouched();
3606
+ }
3607
+ /**
3608
+ * On click shall show datepicker.
3609
+ */
3610
+ onClick() {
3611
+ if (!this.externalTrigger) {
3612
+ this.show();
3613
+ }
3614
+ }
3615
+ /**
3616
+ * Focus out shall close the datepicker except we are moving the focus to the datepicker.
3617
+ * @param event - focus out event with the related target
3618
+ */
3619
+ onBlur(event) {
3620
+ const target = event.relatedTarget;
3621
+ if (!this.externalTrigger && !this.overlayToggle.contains(target)) {
3622
+ this.overlayToggle.closeOverlay();
3623
+ this.onTouched();
3624
+ }
3625
+ }
3626
+ onTab() {
3627
+ if (this.overlayToggle.isShown()) {
3628
+ this.overlayToggle.closeOverlay();
3629
+ }
3630
+ }
3631
+ /**
3632
+ * @internal
3633
+ */
3634
+ show(initialFocus = false) {
3635
+ if (this.disabled() || this.readonly() || this.overlayToggle.isShown()) {
3636
+ return;
3637
+ }
3638
+ this.subscribeDateChanges(this.overlayToggle.showOverlay(initialFocus, {
3639
+ config: this.siDatepickerConfig(),
3640
+ date: this.date,
3641
+ time12h: this.getTime12h()
3642
+ }));
3643
+ }
3644
+ /**
3645
+ * @internal
3646
+ */
3647
+ useExternalTrigger(element) {
3648
+ this.externalTrigger = element;
3649
+ }
3650
+ focusChange() {
3651
+ if (!this.externalTrigger) {
3652
+ this.show();
3653
+ }
3654
+ }
3655
+ getTime12h() {
3656
+ const dateFormat = getDatepickerFormat(this.locale, this.siDatepickerConfig(), true);
3657
+ return dateFormat?.includes('a');
3658
+ }
3659
+ subscribeDateChanges(overlay) {
3660
+ this.overlaySubscriptions?.forEach(s => s.unsubscribe());
3661
+ overlay?.instance.date.subscribe(d => this.onDateChanged(d));
3662
+ overlay?.instance.disabledTimeChange.subscribe(d => this.onDisabledTime(d));
3663
+ }
3664
+ /**
3665
+ * Callback when the datepicker changes his value.
3666
+ * @param date - updated date
3667
+ */
3668
+ onDateChanged(date) {
3669
+ // While typing a date can be invalid and the datepicker component will automatically change the date to undefined.
3670
+ // Since we don't want to reset the current input value it is necessary to ignore those updates.
3671
+ if (!date) {
3672
+ return;
3673
+ }
3674
+ super.onDateChanged(date);
3675
+ if (this.autoClose()) {
3676
+ // a tick later so the event won't end on the wrong element
3677
+ setTimeout(() => this.overlayToggle.closeAfterSelection());
3678
+ }
3679
+ }
3680
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiDatepickerDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive });
3681
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.0.6", type: SiDatepickerDirective, isStandalone: true, selector: "[siDatepicker]", inputs: { autoClose: { classPropertyName: "autoClose", publicName: "autoClose", isSignal: true, isRequired: false, transformFunction: null }, triggeringInput: { classPropertyName: "triggeringInput", publicName: "triggeringInput", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "click": "onClick($event)", "keydown.tab": "onTab()", "focus": "focusChange()" } }, providers: [
3682
+ {
3683
+ provide: NG_VALUE_ACCESSOR,
3684
+ useExisting: SiDatepickerDirective,
3685
+ multi: true
3686
+ },
3687
+ {
3688
+ provide: NG_VALIDATORS,
3689
+ useExisting: SiDatepickerDirective,
3690
+ multi: true
3691
+ },
3692
+ {
3693
+ provide: SI_FORM_ITEM_CONTROL,
3694
+ useExisting: SiDatepickerDirective
3695
+ }
3696
+ ], exportAs: ["siDatepicker"], usesInheritance: true, hostDirectives: [{ directive: SiDatepickerOverlayDirective, outputs: ["siDatepickerClose", "siDatepickerClose"] }], ngImport: i0 });
3697
+ }
3698
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiDatepickerDirective, decorators: [{
3699
+ type: Directive,
3700
+ args: [{
3701
+ selector: '[siDatepicker]',
3702
+ exportAs: 'siDatepicker',
3703
+ providers: [
3704
+ {
3705
+ provide: NG_VALUE_ACCESSOR,
3706
+ useExisting: SiDatepickerDirective,
3707
+ multi: true
3708
+ },
3709
+ {
3710
+ provide: NG_VALIDATORS,
3711
+ useExisting: SiDatepickerDirective,
3712
+ multi: true
3713
+ },
3714
+ {
3715
+ provide: SI_FORM_ITEM_CONTROL,
3716
+ useExisting: SiDatepickerDirective
3717
+ }
3718
+ ],
3719
+ hostDirectives: [
3720
+ {
3721
+ directive: SiDatepickerOverlayDirective,
3722
+ outputs: ['siDatepickerClose']
3723
+ }
3724
+ ]
3725
+ }]
3726
+ }], propDecorators: { onClick: [{
3727
+ type: HostListener,
3728
+ args: ['click', ['$event']]
3729
+ }], onTab: [{
3730
+ type: HostListener,
3731
+ args: ['keydown.tab']
3732
+ }], focusChange: [{
3733
+ type: HostListener,
3734
+ args: ['focus']
3735
+ }] } });
3736
+
3737
+ /**
3738
+ * Copyright Siemens 2016 - 2025.
3739
+ * SPDX-License-Identifier: MIT
3740
+ */
3741
+ class SiDateRangeComponent {
3742
+ static idCounter = 0;
3743
+ inputDirectives = viewChildren(SiDateInputDirective);
3744
+ startInput = viewChild.required('startInput');
3745
+ endInput = viewChild.required('endInput');
3746
+ button = viewChild.required('button');
3747
+ /**
3748
+ * @defaultValue
3749
+ * ```
3750
+ * `__si-date-range-${SiDateRangeComponent.idCounter++}`
3751
+ * ```
3752
+ */
3753
+ id = input(`__si-date-range-${SiDateRangeComponent.idCounter++}`);
3754
+ labelledby = inject(new HostAttributeToken('aria-labelledby'), {
3755
+ optional: true
3756
+ }) ?? `${this.id()}-label`;
3757
+ /**
3758
+ * Date range component configuration.
3759
+ *
3760
+ * @defaultValue
3761
+ * ```
3762
+ * { enableDateRange: true }
3763
+ * ```
3764
+ */
3765
+ siDatepickerConfig = model({ enableDateRange: true });
3766
+ /**
3767
+ * Placeholder of the start date input.
3768
+ *
3769
+ * @defaultValue
3770
+ * ```
3771
+ * $localize`:@@SI_DATEPICKER.START_DATE_PLACEHOLDER:Start date`
3772
+ * ```
3773
+ */
3774
+ startDatePlaceholder = input($localize `:@@SI_DATEPICKER.START_DATE_PLACEHOLDER:Start date`);
3775
+ /**
3776
+ * Placeholder of the end date input.
3777
+ *
3778
+ * @defaultValue
3779
+ * ```
3780
+ * $localize`:@@SI_DATEPICKER.END_DATE_PLACEHOLDER:End date`
3781
+ * ```
3782
+ */
3783
+ endDatePlaceholder = input($localize `:@@SI_DATEPICKER.END_DATE_PLACEHOLDER:End date`);
3784
+ /**
3785
+ * Aria label of the date-range calendar toggle button.
3786
+ *
3787
+ * @defaultValue
3788
+ * ```
3789
+ * $localize`:@@SI_DATEPICKER.CALENDAR_TOGGLE_BUTTON:Open calendar`
3790
+ * ```
3791
+ */
3792
+ ariaLabelCalendarButton = input($localize `:@@SI_DATEPICKER.CALENDAR_TOGGLE_BUTTON:Open calendar`);
3793
+ /**
3794
+ * Form label of the start timepicker.
3795
+ *
3796
+ * @defaultValue
3797
+ * ```
3798
+ * $localize`:@@SI_DATEPICKER.START_TIME_LABEL:from`
3799
+ * ```
3800
+ */
3801
+ startTimeLabel = input($localize `:@@SI_DATEPICKER.START_TIME_LABEL:from`);
3802
+ /**
3803
+ * Form label of the start timepicker.
3804
+ *
3805
+ * @defaultValue
3806
+ * ```
3807
+ * $localize`:@@SI_DATEPICKER.END_TIME_LABEL:to`
3808
+ * ```
3809
+ */
3810
+ endTimeLabel = input($localize `:@@SI_DATEPICKER.END_TIME_LABEL:to`);
3811
+ /**
3812
+ * @deprecated Property has no effect and will be removed without a replacement.
3813
+ *
3814
+ * @defaultValue 200
3815
+ */
3816
+ debounceTime = input(200);
3817
+ /**
3818
+ * Automatically close overlay on date selection.
3819
+ *
3820
+ * @defaultValue false
3821
+ */
3822
+ autoClose = input(false, { transform: booleanAttribute });
3823
+ /** Emits on the date range value changes. */
3824
+ siDatepickerRangeChange = output();
3825
+ /**
3826
+ * Emits an event to notify about disabling the time from the range picker.
3827
+ * When time is disable, we construct a pure date objects in UTC 00:00:00 time.
3828
+ */
3829
+ disabledTimeChange = output();
3830
+ /**
3831
+ * Whether the date range input is disabled.
3832
+ *
3833
+ * @defaultValue false
3834
+ */
3835
+ // eslint-disable-next-line @angular-eslint/no-input-rename
3836
+ disabledInput = input(false, { alias: 'disabled' });
3837
+ /**
3838
+ * Whether the date range input is readonly.
3839
+ *
3840
+ * @defaultValue false
3841
+ */
3842
+ readonly = input(false, { transform: booleanAttribute });
3843
+ /**
3844
+ * Set the date-range object displayed in the control.
3845
+ * The input can be used if the control is used outside Angular forms.
3846
+ */
3847
+ value = model();
3848
+ /** @internal */
3849
+ errormessageId = `${this.id()}-errormessage`;
3850
+ validator;
3851
+ onChange = (val) => { };
3852
+ onTouch = () => { };
3853
+ icons = addIcons({ elementCalendar });
3854
+ disabled = computed(() => this.disabledInput() || this.disabledNgControl());
3855
+ disabledNgControl = signal(false);
3856
+ cdRef = inject(ChangeDetectorRef);
3857
+ overlayToggle = inject(SiDatepickerOverlayDirective);
3858
+ elementRef = inject(ElementRef);
3859
+ defaultPlacement = [
3860
+ positionBottomCenter,
3861
+ positionBottomStart,
3862
+ positionBottomEnd,
3863
+ positionTopCenter,
3864
+ positionTopStart,
3865
+ positionTopEnd
3866
+ ];
3867
+ ngOnChanges(changes) {
3868
+ if (changes.siDatepickerConfig) {
3869
+ this.siDatepickerConfig.set({
3870
+ ...changes.siDatepickerConfig.currentValue,
3871
+ enableDateRange: true,
3872
+ startTimeLabel: changes.siDatepickerConfig.currentValue.startTimeLabel ?? this.startTimeLabel(),
3873
+ endTimeLabel: changes.siDatepickerConfig.currentValue.endTimeLabel ?? this.endTimeLabel()
3874
+ });
3875
+ if (changes.value) {
3876
+ this.updateValue(this.value());
3877
+ }
3878
+ }
3879
+ this.overlayToggle.setInputs({ config: this.siDatepickerConfig(), dateRange: this.value() });
3880
+ }
3881
+ ngAfterViewInit() {
3882
+ this.validator = Validators.compose([
3883
+ () => this.endAfterStartValidator(),
3884
+ this.childValidation
3885
+ ]);
3886
+ this.overlayToggle.placement.set(this.defaultPlacement);
3887
+ this.overlayToggle.siDatepickerClose.subscribe(cause => {
3888
+ if ([CloseCause.Escape, CloseCause.Select].includes(cause)) {
3889
+ this.button().nativeElement.focus();
3890
+ }
3891
+ else {
3892
+ // Mark component as touch when the focus isn't recovered on input
3893
+ this.onTouch();
3894
+ this.cdRef.markForCheck();
3895
+ }
3896
+ });
3897
+ }
3898
+ writeValue(dateRange) {
3899
+ this.updateValue(dateRange);
3900
+ this.overlayToggle.setInputs({ dateRange });
3901
+ }
3902
+ registerOnChange(fn) {
3903
+ this.onChange = fn;
3904
+ }
3905
+ registerOnTouched(fn) {
3906
+ this.onTouch = fn;
3907
+ }
3908
+ setDisabledState(isDisabled) {
3909
+ this.disabledNgControl.set(isDisabled);
3910
+ }
3911
+ validate(c) {
3912
+ return this.validator ? this.validator(c) : null;
3913
+ }
3914
+ /**
3915
+ * Focus out shall close the datepicker except we are moving the focus to the datepicker or one of the input elements.
3916
+ * @param event - focus out event with the related target
3917
+ */
3918
+ onFocusOut(event) {
3919
+ const target = event.relatedTarget;
3920
+ if (!this.overlayToggle.contains(target)) {
3921
+ this.overlayToggle.closeOverlay();
3922
+ // Only mark the component as touched when the focus is not moved to the datepicker or one of the input elements.
3923
+ if (!this.elementRef.nativeElement.contains(target)) {
3924
+ this.onTouch();
3925
+ }
3926
+ }
3927
+ }
3928
+ /** Forward date range input changes to datepicker overlay */
3929
+ onInputChanged(dateRange) {
3930
+ this.updateValue(dateRange);
3931
+ this.onChange(this.value());
3932
+ this.siDatepickerRangeChange.emit(this.value());
3933
+ }
3934
+ show() {
3935
+ if (this.readonly() || this.disabled()) {
3936
+ return;
3937
+ }
3938
+ this.subscribeRangeChanges(this.overlayToggle.showOverlay(true, {
3939
+ config: this.siDatepickerConfig(),
3940
+ dateRange: this.value()
3941
+ }));
3942
+ }
3943
+ subscribeRangeChanges(overlay) {
3944
+ overlay?.instance.dateRange.subscribe(d => this.onRangeChanged(d));
3945
+ overlay?.instance.disabledTimeChange.subscribe(disabledTime => {
3946
+ this.inputDirectives().forEach(inputDirective => inputDirective.onDisabledTime(disabledTime));
3947
+ this.disabledTimeChange.emit(disabledTime);
3948
+ });
3949
+ }
3950
+ onRangeChanged(range) {
3951
+ this.updateValue(range);
3952
+ this.onChange(range);
3953
+ this.siDatepickerRangeChange.emit(range);
3954
+ this.validateChildren();
3955
+ if (this.autoClose() && this.value()?.start && this.value()?.end) {
3956
+ // We have to queue the close in the another cycle since other output event
3957
+ // emitters like rangeTypeChange can complete before we destroy the overlay.
3958
+ setTimeout(() => this.overlayToggle.closeAfterSelection());
3959
+ }
3960
+ }
3961
+ /** Run validators on the start/end inputs. */
3962
+ validateChildren() {
3963
+ this.inputDirectives().forEach(d => d.validatorOnChange());
3964
+ }
3965
+ /** The form control validator for the end date is greater equal start date. */
3966
+ endAfterStartValidator() {
3967
+ const endDate = this.endInput().value;
3968
+ const startDate = this.startInput().value;
3969
+ return !endDate || !startDate || endDate >= startDate
3970
+ ? null
3971
+ : {
3972
+ endBeforeStart: {
3973
+ start: startDate,
3974
+ end: endDate
3975
+ }
3976
+ };
3977
+ }
3978
+ childValidation = () => {
3979
+ const errors = {};
3980
+ this.readErrorsFromInnerControl(this.startInput(), 'Start', errors);
3981
+ this.readErrorsFromInnerControl(this.endInput(), 'End', errors);
3982
+ if (Object.keys(errors).length) {
3983
+ return errors;
3984
+ }
3985
+ return null;
3986
+ };
3987
+ readErrorsFromInnerControl(control, type, errors) {
3988
+ if (control.invalid) {
3989
+ const formatError = control.getError('dateFormat');
3990
+ if (formatError) {
3991
+ errors[`invalid${type}DateFormat`] = formatError;
3992
+ }
3993
+ const minError = control.getError('minDate');
3994
+ const siDatepickerConfig = this.siDatepickerConfig();
3995
+ if (minError) {
3996
+ errors.rangeBeforeMinDate = {
3997
+ min: getMinDate(siDatepickerConfig.minDate),
3998
+ start: this.startInput().value,
3999
+ end: this.endInput().value
4000
+ };
4001
+ }
4002
+ const maxError = control.getError('maxDate');
4003
+ if (maxError) {
4004
+ errors.rangeAfterMaxDate = {
4005
+ max: getMaxDate(siDatepickerConfig.maxDate),
4006
+ start: this.startInput().value,
4007
+ end: this.endInput().value
4008
+ };
4009
+ }
4010
+ }
4011
+ }
4012
+ updateValue(value) {
4013
+ // this allows angular's built in required validator to work correctly
4014
+ if (!value?.start && !value?.end) {
4015
+ this.value.set(undefined);
4016
+ }
4017
+ else {
4018
+ this.value.set(value);
4019
+ }
4020
+ }
4021
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiDateRangeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4022
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.0.6", type: SiDateRangeComponent, isStandalone: true, selector: "si-date-range", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, siDatepickerConfig: { classPropertyName: "siDatepickerConfig", publicName: "siDatepickerConfig", isSignal: true, isRequired: false, transformFunction: null }, startDatePlaceholder: { classPropertyName: "startDatePlaceholder", publicName: "startDatePlaceholder", isSignal: true, isRequired: false, transformFunction: null }, endDatePlaceholder: { classPropertyName: "endDatePlaceholder", publicName: "endDatePlaceholder", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelCalendarButton: { classPropertyName: "ariaLabelCalendarButton", publicName: "ariaLabelCalendarButton", isSignal: true, isRequired: false, transformFunction: null }, startTimeLabel: { classPropertyName: "startTimeLabel", publicName: "startTimeLabel", isSignal: true, isRequired: false, transformFunction: null }, endTimeLabel: { classPropertyName: "endTimeLabel", publicName: "endTimeLabel", isSignal: true, isRequired: false, transformFunction: null }, debounceTime: { classPropertyName: "debounceTime", publicName: "debounceTime", isSignal: true, isRequired: false, transformFunction: null }, autoClose: { classPropertyName: "autoClose", publicName: "autoClose", 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 }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { siDatepickerConfig: "siDatepickerConfigChange", siDatepickerRangeChange: "siDatepickerRangeChange", disabledTimeChange: "disabledTimeChange", value: "valueChange" }, host: { attributes: { "role": "group" }, listeners: { "focusout": "onFocusOut($event)" }, properties: { "class.disabled": "disabled()", "class.readonly": "readonly()", "attr.aria-labelledby": "labelledby" }, classAttribute: "form-control d-flex align-items-center pe-2" }, providers: [
4023
+ {
4024
+ provide: NG_VALUE_ACCESSOR,
4025
+ useExisting: SiDateRangeComponent,
4026
+ multi: true
4027
+ },
4028
+ {
4029
+ provide: NG_VALIDATORS,
4030
+ useExisting: SiDateRangeComponent,
4031
+ multi: true
4032
+ },
4033
+ {
4034
+ provide: SI_FORM_ITEM_CONTROL,
4035
+ useExisting: SiDateRangeComponent
4036
+ }
4037
+ ], viewQueries: [{ propertyName: "inputDirectives", predicate: SiDateInputDirective, descendants: true, isSignal: true }, { propertyName: "startInput", first: true, predicate: ["startInput"], descendants: true, isSignal: true }, { propertyName: "endInput", first: true, predicate: ["endInput"], descendants: true, isSignal: true }, { propertyName: "button", first: true, predicate: ["button"], descendants: true, isSignal: true }], usesOnChanges: true, hostDirectives: [{ directive: SiDatepickerOverlayDirective, outputs: ["siDatepickerClose", "siDatepickerClose"] }], ngImport: i0, template: "<input\n #startInput=\"ngModel\"\n type=\"text\"\n class=\"border-0 p-0 focus-none\"\n siDateInput\n [ngModel]=\"value()?.start ?? null\"\n [siDatepickerConfig]=\"siDatepickerConfig()\"\n [placeholder]=\"startDatePlaceholder() | translate\"\n [attr.aria-label]=\"startDatePlaceholder() | translate\"\n [errormessageId]=\"errormessageId\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (ngModelChange)=\"onInputChanged({ start: $event, end: value()?.end })\"\n/>\n<span class=\"mx-3\">-</span>\n<input\n #endInput=\"ngModel\"\n type=\"text\"\n class=\"border-0 p-0 focus-none text-end\"\n siDateInput\n [ngModel]=\"value()?.end ?? null\"\n [siDatepickerConfig]=\"siDatepickerConfig()\"\n [placeholder]=\"endDatePlaceholder() | translate\"\n [attr.aria-label]=\"endDatePlaceholder() | translate\"\n [errormessageId]=\"errormessageId\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (ngModelChange)=\"onInputChanged({ start: value()?.start, end: $event })\"\n/>\n<button\n #button\n type=\"button\"\n class=\"btn btn-circle btn-tertiary btn-xs\"\n [attr.aria-label]=\"ariaLabelCalendarButton() | translate\"\n [disabled]=\"disabled() || readonly()\"\n (click)=\"show()\"\n>\n <si-icon-next [icon]=\"icons.elementCalendar\" />\n</button>\n", styles: [":host{display:block;min-inline-size:237px;--si-action-icon-offset: 22px}:host(:focus-within){outline:var(--element-button-focus-width) solid var(--element-focus-default);outline-offset:var(--element-button-focus-overlay-width)}input{flex-grow:1;background-color:transparent;min-inline-size:80px}input::placeholder{opacity:1;color:var(--element-text-secondary)}input:disabled,input[readonly]{background-color:var(--element-base-1);opacity:1}input:disabled::placeholder{color:transparent}input:not([readonly]):focus::placeholder,input:focus:not([readonly]):focus::placeholder{color:transparent}.disabled,.disabled:hover,.disabled:focus{--border-color: var(--element-ui-3);color:var(--element-text-disabled)}.btn-circle{margin-inline-start:var(--si-feedback-icon-offset, 4px)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: SiDateInputDirective, selector: "[siDateInput]", inputs: ["id", "siDatepickerConfig", "dateInputDebounceTime", "disabled", "readonly", "errormessageId"], outputs: ["siDatepickerConfigChange", "siDatepickerDisabledTime", "stateChange", "dateChange"], exportAs: ["siDateInput"] }, { kind: "component", type: SiIconNextComponent, selector: "si-icon-next", inputs: ["icon"] }, { kind: "ngmodule", type: SiTranslateModule }, { kind: "pipe", type: i2.SiTranslatePipe, name: "translate" }, { kind: "ngmodule", type: A11yModule }] });
4038
+ }
4039
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiDateRangeComponent, decorators: [{
4040
+ type: Component,
4041
+ args: [{ selector: 'si-date-range', host: {
4042
+ class: 'form-control d-flex align-items-center pe-2',
4043
+ role: 'group',
4044
+ '[class.disabled]': 'disabled()',
4045
+ '[class.readonly]': 'readonly()',
4046
+ '[attr.aria-labelledby]': 'labelledby'
4047
+ }, providers: [
4048
+ {
4049
+ provide: NG_VALUE_ACCESSOR,
4050
+ useExisting: SiDateRangeComponent,
4051
+ multi: true
4052
+ },
4053
+ {
4054
+ provide: NG_VALIDATORS,
4055
+ useExisting: SiDateRangeComponent,
4056
+ multi: true
4057
+ },
4058
+ {
4059
+ provide: SI_FORM_ITEM_CONTROL,
4060
+ useExisting: SiDateRangeComponent
4061
+ }
4062
+ ], hostDirectives: [
4063
+ {
4064
+ directive: SiDatepickerOverlayDirective,
4065
+ outputs: ['siDatepickerClose']
4066
+ }
4067
+ ], imports: [FormsModule, SiDateInputDirective, SiIconNextComponent, SiTranslateModule, A11yModule], template: "<input\n #startInput=\"ngModel\"\n type=\"text\"\n class=\"border-0 p-0 focus-none\"\n siDateInput\n [ngModel]=\"value()?.start ?? null\"\n [siDatepickerConfig]=\"siDatepickerConfig()\"\n [placeholder]=\"startDatePlaceholder() | translate\"\n [attr.aria-label]=\"startDatePlaceholder() | translate\"\n [errormessageId]=\"errormessageId\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (ngModelChange)=\"onInputChanged({ start: $event, end: value()?.end })\"\n/>\n<span class=\"mx-3\">-</span>\n<input\n #endInput=\"ngModel\"\n type=\"text\"\n class=\"border-0 p-0 focus-none text-end\"\n siDateInput\n [ngModel]=\"value()?.end ?? null\"\n [siDatepickerConfig]=\"siDatepickerConfig()\"\n [placeholder]=\"endDatePlaceholder() | translate\"\n [attr.aria-label]=\"endDatePlaceholder() | translate\"\n [errormessageId]=\"errormessageId\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (ngModelChange)=\"onInputChanged({ start: value()?.start, end: $event })\"\n/>\n<button\n #button\n type=\"button\"\n class=\"btn btn-circle btn-tertiary btn-xs\"\n [attr.aria-label]=\"ariaLabelCalendarButton() | translate\"\n [disabled]=\"disabled() || readonly()\"\n (click)=\"show()\"\n>\n <si-icon-next [icon]=\"icons.elementCalendar\" />\n</button>\n", styles: [":host{display:block;min-inline-size:237px;--si-action-icon-offset: 22px}:host(:focus-within){outline:var(--element-button-focus-width) solid var(--element-focus-default);outline-offset:var(--element-button-focus-overlay-width)}input{flex-grow:1;background-color:transparent;min-inline-size:80px}input::placeholder{opacity:1;color:var(--element-text-secondary)}input:disabled,input[readonly]{background-color:var(--element-base-1);opacity:1}input:disabled::placeholder{color:transparent}input:not([readonly]):focus::placeholder,input:focus:not([readonly]):focus::placeholder{color:transparent}.disabled,.disabled:hover,.disabled:focus{--border-color: var(--element-ui-3);color:var(--element-text-disabled)}.btn-circle{margin-inline-start:var(--si-feedback-icon-offset, 4px)}\n"] }]
4068
+ }], propDecorators: { onFocusOut: [{
4069
+ type: HostListener,
4070
+ args: ['focusout', ['$event']]
4071
+ }] } });
4072
+
4073
+ /**
4074
+ * Copyright Siemens 2016 - 2025.
4075
+ * SPDX-License-Identifier: MIT
4076
+ */
4077
+ /**
4078
+ * Calendar toggle button used in combination with a datepicker directive.
4079
+ *
4080
+ * @example
4081
+ * ```
4082
+ * <si-calendar-button class="w-100">
4083
+ * <input
4084
+ * class="form-control"
4085
+ * type="text"
4086
+ * siDatepicker
4087
+ * [siDatepickerConfig]="config"
4088
+ * />
4089
+ * </si-calendar-button>
4090
+ * ```
4091
+ */
4092
+ class SiCalendarButtonComponent {
4093
+ /**
4094
+ * Aria label for the calendar toggle button.
4095
+ *
4096
+ * @defaultValue
4097
+ * ```
4098
+ * $localize`:@@SI_DATEPICKER.CALENDAR_TOGGLE_BUTTON:Open calendar`
4099
+ * ```
4100
+ */
4101
+ ariaLabel = input($localize `:@@SI_DATEPICKER.CALENDAR_TOGGLE_BUTTON:Open calendar`);
4102
+ button = viewChild.required('calendarButton');
4103
+ /** Datepicker input directive instance used to watch for state changes and required to open the calendar. */
4104
+ datepicker = contentChild.required(SiDatepickerDirective);
4105
+ datepickerOverlay = contentChild.required(SiDatepickerOverlayDirective);
4106
+ ngControl = contentChild(NgControl);
4107
+ disabled = signal(false);
4108
+ icons = addIcons({ elementCalendar });
4109
+ destroyerRef = inject(DestroyRef);
4110
+ focusMonitor = inject(FocusMonitor);
4111
+ elementRef = inject(ElementRef);
4112
+ // Add classes here to enable error messages in si-form-item
4113
+ showValidationMessages = signal(false);
4114
+ ngOnInit() {
4115
+ // Monitor input state changes and update the button accordingly
4116
+ this.datepicker().stateChange.subscribe(() => this.updateState());
4117
+ this.focusMonitor
4118
+ .monitor(this.elementRef, true)
4119
+ .pipe(takeUntilDestroyed(this.destroyerRef))
4120
+ .subscribe(origin => {
4121
+ setTimeout(() => {
4122
+ if (origin === null && !this.datepickerOverlay().isShown()) {
4123
+ this.datepicker().touch();
4124
+ }
4125
+ });
4126
+ });
4127
+ }
4128
+ ngDoCheck() {
4129
+ const control = this.ngControl()?.control;
4130
+ this.showValidationMessages.set(!!control?.touched && !!control?.invalid);
4131
+ }
4132
+ ngAfterContentInit() {
4133
+ this.datepicker().useExternalTrigger(this.button());
4134
+ this.updateState();
4135
+ }
4136
+ show() {
4137
+ this.datepicker().show(true);
4138
+ }
4139
+ updateState() {
4140
+ const datepicker = this.datepicker();
4141
+ this.disabled.set(datepicker.disabled() || datepicker.readonly());
4142
+ }
4143
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiCalendarButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4144
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.0.6", type: SiCalendarButtonComponent, isStandalone: true, selector: "si-calendar-button", inputs: { ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.ng-invalid": "showValidationMessages()", "class.ng-touched": "showValidationMessages()" }, classAttribute: "d-inline-block position-relative form-control-wrapper" }, queries: [{ propertyName: "datepicker", first: true, predicate: SiDatepickerDirective, descendants: true, isSignal: true }, { propertyName: "datepickerOverlay", first: true, predicate: SiDatepickerOverlayDirective, descendants: true, isSignal: true }, { propertyName: "ngControl", first: true, predicate: NgControl, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "button", first: true, predicate: ["calendarButton"], descendants: true, isSignal: true }], ngImport: i0, template: `<ng-content />
4145
+ <button
4146
+ #calendarButton
4147
+ name="open-calendar"
4148
+ type="button"
4149
+ class="btn btn-circle btn-tertiary btn-xs position-absolute end-0 top-0 me-2 mt-2"
4150
+ [attr.aria-label]="ariaLabel() | translate"
4151
+ [disabled]="disabled()"
4152
+ (click)="show()"
4153
+ >
4154
+ <si-icon-next [icon]="icons.elementCalendar" />
4155
+ </button>`, isInline: true, styles: [":host{--si-action-icon-offset: 24px}\n"], dependencies: [{ kind: "component", type: SiIconNextComponent, selector: "si-icon-next", inputs: ["icon"] }, { kind: "ngmodule", type: SiTranslateModule }, { kind: "pipe", type: i2.SiTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4156
+ }
4157
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiCalendarButtonComponent, decorators: [{
4158
+ type: Component,
4159
+ args: [{ selector: 'si-calendar-button', template: `<ng-content />
4160
+ <button
4161
+ #calendarButton
4162
+ name="open-calendar"
4163
+ type="button"
4164
+ class="btn btn-circle btn-tertiary btn-xs position-absolute end-0 top-0 me-2 mt-2"
4165
+ [attr.aria-label]="ariaLabel() | translate"
4166
+ [disabled]="disabled()"
4167
+ (click)="show()"
4168
+ >
4169
+ <si-icon-next [icon]="icons.elementCalendar" />
4170
+ </button>`, host: {
4171
+ class: 'd-inline-block position-relative form-control-wrapper',
4172
+ '[class.ng-invalid]': 'showValidationMessages()',
4173
+ '[class.ng-touched]': 'showValidationMessages()'
4174
+ }, changeDetection: ChangeDetectionStrategy.OnPush, imports: [SiIconNextComponent, SiTranslateModule], styles: [":host{--si-action-icon-offset: 24px}\n"] }]
4175
+ }] });
4176
+
4177
+ /**
4178
+ * Copyright Siemens 2016 - 2025.
4179
+ * SPDX-License-Identifier: MIT
4180
+ */
4181
+ class SiDatepickerModule {
4182
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiDatepickerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
4183
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.6", ngImport: i0, type: SiDatepickerModule, imports: [SiCalendarButtonComponent,
4184
+ SiDateInputDirective,
4185
+ SiDatepickerComponent,
4186
+ SiDatepickerDirective,
4187
+ SiDateRangeComponent,
4188
+ SiTimepickerComponent], exports: [SiCalendarButtonComponent,
4189
+ SiDateInputDirective,
4190
+ SiDatepickerComponent,
4191
+ SiDatepickerDirective,
4192
+ SiDateRangeComponent,
4193
+ SiTimepickerComponent] });
4194
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiDatepickerModule, imports: [SiCalendarButtonComponent,
4195
+ SiDatepickerComponent,
4196
+ SiDateRangeComponent,
4197
+ SiTimepickerComponent] });
4198
+ }
4199
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: SiDatepickerModule, decorators: [{
4200
+ type: NgModule,
4201
+ args: [{
4202
+ imports: [
4203
+ SiCalendarButtonComponent,
4204
+ SiDateInputDirective,
4205
+ SiDatepickerComponent,
4206
+ SiDatepickerDirective,
4207
+ SiDateRangeComponent,
4208
+ SiTimepickerComponent
4209
+ ],
4210
+ exports: [
4211
+ SiCalendarButtonComponent,
4212
+ SiDateInputDirective,
4213
+ SiDatepickerComponent,
4214
+ SiDatepickerDirective,
4215
+ SiDateRangeComponent,
4216
+ SiTimepickerComponent
4217
+ ]
4218
+ }]
4219
+ }] });
4220
+
4221
+ /**
4222
+ * Copyright Siemens 2016 - 2025.
4223
+ * SPDX-License-Identifier: MIT
4224
+ */
4225
+
4226
+ /**
4227
+ * Generated bundle index. Do not edit.
4228
+ */
4229
+
4230
+ export { CloseCause, SiCalendarButtonComponent, SiDateInputDirective, SiDateRangeComponent, SiDatepickerComponent, SiDatepickerDirective, SiDatepickerModule, SiDatepickerOverlayComponent, SiDatepickerOverlayDirective, SiTimepickerComponent, WEEK_START_OFFSET, addDays, addDaysInRange, addMonthsInRange, addYearsInRange, changeDay, compareDate, compareMonth, compareYear, createDate, daysInMonth, getDateSameOrBetween, getDateWithoutTime, getDatepickerFormat, getDayStrings, getDaysOfWeek, getFirstDateInMonth, getFirstDateInYear, getFirstDayInMonth, getLastDateInMonth, getLocaleMonthNames, getMaxDate, getMinDate, getNamedFormat, getStringforDate, getWeekDayOffset, getWeekEndDate, getWeekOfYear, getWeekStartDate, isAfter, isAfterMonth, isAfterYear, isAnotherMonth, isAnotherMonthOrYear, isAnotherYear, isBetween, isBetweenMonth, isBetweenYears, isSameDate, isSameMonth, isSameOrBefore, isSameOrBeforeMonth, isSameOrBeforeYear, isSameOrBetween, isSameOrBetweenMonth, isSameOrBetweenYears, isSameYear, isValid, maxDate, minDate, nextMonth, parseDate, previousMonth, today };
4231
+ //# sourceMappingURL=siemens-element-ng-datepicker.mjs.map