@seniorsistemas/angular-components 19.9.7 → 19.9.8-develop-5d2dfb27

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 (166) hide show
  1. package/card/lib/card/card.component.d.ts +6 -2
  2. package/country-phone-picker/lib/country-phone-picker/country-phone-picker.component.d.ts +0 -1
  3. package/datepicker/README.md +6 -2
  4. package/datepicker/lib/datepicker/date-segment-input.d.ts +7 -1
  5. package/datepicker/lib/datepicker/datepicker.component.d.ts +137 -3
  6. package/dialog/lib/src/dialog/services/dialog.service.d.ts +2 -0
  7. package/esm2022/accordion/lib/accordion/components/accordion-panel/accordion-panel.component.mjs +3 -3
  8. package/esm2022/autocomplete/lib/autocomplete/autocomplete.component.mjs +8 -3
  9. package/esm2022/autocomplete/lib/autocomplete/components/autocomplete-chip/autocomplete-chip.component.mjs +4 -3
  10. package/esm2022/breadcrumb/lib/breadcrumb/breadcrumb.component.mjs +3 -3
  11. package/esm2022/breadcrumb/lib/dynamic-breadcrumb/dynamic-breadcrumb.component.mjs +4 -2
  12. package/esm2022/button/lib/button/button.component.mjs +3 -3
  13. package/esm2022/card/lib/card/card.component.mjs +13 -5
  14. package/esm2022/checkbox/lib/checkbox/checkbox.component.mjs +3 -3
  15. package/esm2022/checkbox-list/lib/checkbox-list/checkbox-list.component.mjs +3 -3
  16. package/esm2022/chips/lib/chips/chip-item/chip-item.component.mjs +3 -3
  17. package/esm2022/chips/lib/chips/chips/chips.component.mjs +3 -3
  18. package/esm2022/code-editor/lib/code-editor/infra/cores/codemirror-6/themes/sds-light/sds-light-style.mjs +3 -2
  19. package/esm2022/collapse-link/lib/collapse-link/collapse-link.component.mjs +3 -3
  20. package/esm2022/country-phone-picker/lib/country-phone-picker/country-phone-picker.component.mjs +14 -9
  21. package/esm2022/datepicker/lib/datepicker/date-segment-input.mjs +19 -2
  22. package/esm2022/datepicker/lib/datepicker/datepicker.component.mjs +405 -38
  23. package/esm2022/dialog/lib/src/dialog/dialog.component.mjs +3 -3
  24. package/esm2022/dialog/lib/src/dialog/services/dialog.service.mjs +13 -1
  25. package/esm2022/drawer/lib/drawer/drawer.component.mjs +3 -3
  26. package/esm2022/dynamic-form/dynamic-form/components/lookup/lookup.component.mjs +3 -3
  27. package/esm2022/dynamic-form/dynamic-form/form-field/fields/bignumber/bignumber-field.component.mjs +3 -3
  28. package/esm2022/dynamic-form/dynamic-form/form-field/fields/currency/currency-field.component.mjs +6 -4
  29. package/esm2022/dynamic-form/dynamic-form/form-field/fields/number/number-field.component.mjs +3 -3
  30. package/esm2022/dynamic-form/dynamic-form/form-field/fields/password/password-field.component.mjs +3 -3
  31. package/esm2022/dynamic-form/dynamic-form/form-field/fields/text/text-field.component.mjs +3 -3
  32. package/esm2022/editor/lib/editor/editor.component.mjs +3 -3
  33. package/esm2022/editor/lib/editor/toolbar-button/editor-toolbar-button.component.mjs +3 -3
  34. package/esm2022/fieldset/lib/fieldset/fieldset.component.mjs +3 -3
  35. package/esm2022/file-picker/lib/file-picker/file-picker.component.mjs +3 -3
  36. package/esm2022/gantt/lib/gantt/components/gantt/bar.mjs +2 -1
  37. package/esm2022/gantt/lib/gantt/gantt.component.mjs +3 -3
  38. package/esm2022/global-search/lib/global-search/global-search.component.mjs +16 -25
  39. package/esm2022/grid-menu/lib/grid-menu/components/grid-menu-item/grid-menu-item.component.mjs +3 -3
  40. package/esm2022/input-text/lib/input-text/input-text.directive.mjs +3 -3
  41. package/esm2022/lib/locale/fallback.mjs +40 -13
  42. package/esm2022/navigation-button/lib/navigation-button/navigation-button.component.mjs +3 -3
  43. package/esm2022/object-card/lib/object-card/object-card.component.mjs +3 -3
  44. package/esm2022/paginator/lib/paginator/paginator.component.mjs +3 -3
  45. package/esm2022/pin-code-field/lib/pin-code-field/pin-code-field.component.mjs +3 -3
  46. package/esm2022/radio-button/lib/radio-button/radio-button.component.mjs +4 -10
  47. package/esm2022/rating-scale/lib/rating-scale/rating-scale.component.mjs +3 -3
  48. package/esm2022/select/lib/select/select.component.mjs +3 -3
  49. package/esm2022/select-button/lib/select-button/components/select-button-item/select-button-item.component.mjs +3 -3
  50. package/esm2022/shared/lib/accessibility/datepicker-no-period-tab.directive.mjs +6 -6
  51. package/esm2022/side-sheet/lib/side-sheet/side-sheet.component.mjs +3 -3
  52. package/esm2022/slider/lib/slider/slider.component.mjs +67 -65
  53. package/esm2022/slider/lib/slider/slider.module.mjs +2 -2
  54. package/esm2022/split-button/lib/split-button/split-button.component.mjs +3 -3
  55. package/esm2022/star-rating/star-rating/star-rating.component.mjs +3 -3
  56. package/esm2022/stepper/lib/stepper/stepper.component.mjs +3 -3
  57. package/esm2022/switch/lib/switch/switch.component.mjs +5 -19
  58. package/esm2022/tabs/lib/tabs/tabs.component.mjs +3 -3
  59. package/esm2022/text-area/lib/text-area/text-area.component.mjs +3 -3
  60. package/esm2022/thumbnail/lib/thumbnail/thumbnail.component.mjs +10 -3
  61. package/esm2022/thumbnails/lib/thumbnails/components/thumbnail-item/thumbnail-item.component.mjs +3 -3
  62. package/esm2022/tiered-menu/lib/tiered-menu/components/tiered-menu-item/tiered-menu-item.component.mjs +3 -3
  63. package/esm2022/tiered-menu/lib/tiered-menu/services/tiered-menu.global.service.mjs +4 -3
  64. package/esm2022/tile/lib/tile/tile.component.mjs +3 -3
  65. package/esm2022/tree/lib/tree/components/tree-node-item/tree-node-item.component.mjs +20 -3
  66. package/esm2022/workspace-switch/lib/workspace-switch/workspace-switch.component.mjs +3 -3
  67. package/fesm2022/seniorsistemas-angular-components-accordion.mjs +2 -2
  68. package/fesm2022/seniorsistemas-angular-components-accordion.mjs.map +1 -1
  69. package/fesm2022/seniorsistemas-angular-components-autocomplete.mjs +10 -5
  70. package/fesm2022/seniorsistemas-angular-components-autocomplete.mjs.map +1 -1
  71. package/fesm2022/seniorsistemas-angular-components-breadcrumb.mjs +5 -3
  72. package/fesm2022/seniorsistemas-angular-components-breadcrumb.mjs.map +1 -1
  73. package/fesm2022/seniorsistemas-angular-components-button.mjs +2 -2
  74. package/fesm2022/seniorsistemas-angular-components-button.mjs.map +1 -1
  75. package/fesm2022/seniorsistemas-angular-components-card.mjs +12 -4
  76. package/fesm2022/seniorsistemas-angular-components-card.mjs.map +1 -1
  77. package/fesm2022/seniorsistemas-angular-components-checkbox-list.mjs +2 -2
  78. package/fesm2022/seniorsistemas-angular-components-checkbox-list.mjs.map +1 -1
  79. package/fesm2022/seniorsistemas-angular-components-checkbox.mjs +2 -2
  80. package/fesm2022/seniorsistemas-angular-components-checkbox.mjs.map +1 -1
  81. package/fesm2022/seniorsistemas-angular-components-chips.mjs +4 -4
  82. package/fesm2022/seniorsistemas-angular-components-chips.mjs.map +1 -1
  83. package/fesm2022/seniorsistemas-angular-components-code-editor.mjs +2 -1
  84. package/fesm2022/seniorsistemas-angular-components-code-editor.mjs.map +1 -1
  85. package/fesm2022/seniorsistemas-angular-components-collapse-link.mjs +2 -2
  86. package/fesm2022/seniorsistemas-angular-components-collapse-link.mjs.map +1 -1
  87. package/fesm2022/seniorsistemas-angular-components-country-phone-picker.mjs +13 -8
  88. package/fesm2022/seniorsistemas-angular-components-country-phone-picker.mjs.map +1 -1
  89. package/fesm2022/seniorsistemas-angular-components-datepicker.mjs +422 -38
  90. package/fesm2022/seniorsistemas-angular-components-datepicker.mjs.map +1 -1
  91. package/fesm2022/seniorsistemas-angular-components-dialog.mjs +14 -2
  92. package/fesm2022/seniorsistemas-angular-components-dialog.mjs.map +1 -1
  93. package/fesm2022/seniorsistemas-angular-components-drawer.mjs +2 -2
  94. package/fesm2022/seniorsistemas-angular-components-drawer.mjs.map +1 -1
  95. package/fesm2022/seniorsistemas-angular-components-dynamic-form.mjs +13 -12
  96. package/fesm2022/seniorsistemas-angular-components-dynamic-form.mjs.map +1 -1
  97. package/fesm2022/seniorsistemas-angular-components-editor.mjs +4 -4
  98. package/fesm2022/seniorsistemas-angular-components-editor.mjs.map +1 -1
  99. package/fesm2022/seniorsistemas-angular-components-fieldset.mjs +2 -2
  100. package/fesm2022/seniorsistemas-angular-components-fieldset.mjs.map +1 -1
  101. package/fesm2022/seniorsistemas-angular-components-file-picker.mjs +2 -2
  102. package/fesm2022/seniorsistemas-angular-components-file-picker.mjs.map +1 -1
  103. package/fesm2022/seniorsistemas-angular-components-gantt.mjs +3 -2
  104. package/fesm2022/seniorsistemas-angular-components-gantt.mjs.map +1 -1
  105. package/fesm2022/seniorsistemas-angular-components-global-search.mjs +14 -23
  106. package/fesm2022/seniorsistemas-angular-components-global-search.mjs.map +1 -1
  107. package/fesm2022/seniorsistemas-angular-components-grid-menu.mjs +2 -2
  108. package/fesm2022/seniorsistemas-angular-components-grid-menu.mjs.map +1 -1
  109. package/fesm2022/seniorsistemas-angular-components-input-text.mjs +2 -2
  110. package/fesm2022/seniorsistemas-angular-components-input-text.mjs.map +1 -1
  111. package/fesm2022/seniorsistemas-angular-components-navigation-button.mjs +2 -2
  112. package/fesm2022/seniorsistemas-angular-components-navigation-button.mjs.map +1 -1
  113. package/fesm2022/seniorsistemas-angular-components-object-card.mjs +2 -2
  114. package/fesm2022/seniorsistemas-angular-components-object-card.mjs.map +1 -1
  115. package/fesm2022/seniorsistemas-angular-components-paginator.mjs +2 -2
  116. package/fesm2022/seniorsistemas-angular-components-paginator.mjs.map +1 -1
  117. package/fesm2022/seniorsistemas-angular-components-pin-code-field.mjs +2 -2
  118. package/fesm2022/seniorsistemas-angular-components-pin-code-field.mjs.map +1 -1
  119. package/fesm2022/seniorsistemas-angular-components-radio-button.mjs +3 -9
  120. package/fesm2022/seniorsistemas-angular-components-radio-button.mjs.map +1 -1
  121. package/fesm2022/seniorsistemas-angular-components-rating-scale.mjs +2 -2
  122. package/fesm2022/seniorsistemas-angular-components-rating-scale.mjs.map +1 -1
  123. package/fesm2022/seniorsistemas-angular-components-select-button.mjs +2 -2
  124. package/fesm2022/seniorsistemas-angular-components-select-button.mjs.map +1 -1
  125. package/fesm2022/seniorsistemas-angular-components-select.mjs +2 -2
  126. package/fesm2022/seniorsistemas-angular-components-select.mjs.map +1 -1
  127. package/fesm2022/seniorsistemas-angular-components-shared.mjs +5 -5
  128. package/fesm2022/seniorsistemas-angular-components-shared.mjs.map +1 -1
  129. package/fesm2022/seniorsistemas-angular-components-side-sheet.mjs +2 -2
  130. package/fesm2022/seniorsistemas-angular-components-side-sheet.mjs.map +1 -1
  131. package/fesm2022/seniorsistemas-angular-components-slider.mjs +67 -65
  132. package/fesm2022/seniorsistemas-angular-components-slider.mjs.map +1 -1
  133. package/fesm2022/seniorsistemas-angular-components-split-button.mjs +2 -2
  134. package/fesm2022/seniorsistemas-angular-components-split-button.mjs.map +1 -1
  135. package/fesm2022/seniorsistemas-angular-components-star-rating.mjs +2 -2
  136. package/fesm2022/seniorsistemas-angular-components-star-rating.mjs.map +1 -1
  137. package/fesm2022/seniorsistemas-angular-components-stepper.mjs +2 -2
  138. package/fesm2022/seniorsistemas-angular-components-stepper.mjs.map +1 -1
  139. package/fesm2022/seniorsistemas-angular-components-switch.mjs +4 -18
  140. package/fesm2022/seniorsistemas-angular-components-switch.mjs.map +1 -1
  141. package/fesm2022/seniorsistemas-angular-components-tabs.mjs +2 -2
  142. package/fesm2022/seniorsistemas-angular-components-tabs.mjs.map +1 -1
  143. package/fesm2022/seniorsistemas-angular-components-text-area.mjs +2 -2
  144. package/fesm2022/seniorsistemas-angular-components-text-area.mjs.map +1 -1
  145. package/fesm2022/seniorsistemas-angular-components-thumbnail.mjs +9 -2
  146. package/fesm2022/seniorsistemas-angular-components-thumbnail.mjs.map +1 -1
  147. package/fesm2022/seniorsistemas-angular-components-thumbnails.mjs +2 -2
  148. package/fesm2022/seniorsistemas-angular-components-thumbnails.mjs.map +1 -1
  149. package/fesm2022/seniorsistemas-angular-components-tiered-menu.mjs +5 -4
  150. package/fesm2022/seniorsistemas-angular-components-tiered-menu.mjs.map +1 -1
  151. package/fesm2022/seniorsistemas-angular-components-tile.mjs +2 -2
  152. package/fesm2022/seniorsistemas-angular-components-tile.mjs.map +1 -1
  153. package/fesm2022/seniorsistemas-angular-components-tree.mjs +20 -3
  154. package/fesm2022/seniorsistemas-angular-components-tree.mjs.map +1 -1
  155. package/fesm2022/seniorsistemas-angular-components-workspace-switch.mjs +2 -2
  156. package/fesm2022/seniorsistemas-angular-components-workspace-switch.mjs.map +1 -1
  157. package/fesm2022/seniorsistemas-angular-components.mjs +39 -12
  158. package/fesm2022/seniorsistemas-angular-components.mjs.map +1 -1
  159. package/global-search/lib/global-search/global-search.component.d.ts +7 -3
  160. package/package.json +1 -1
  161. package/radio-button/lib/radio-button/radio-button.component.d.ts +0 -1
  162. package/slider/lib/slider/slider.component.d.ts +25 -7
  163. package/styles.css +5 -0
  164. package/switch/lib/switch/switch.component.d.ts +0 -2
  165. package/thumbnail/lib/thumbnail/thumbnail.component.d.ts +1 -0
  166. package/tree/lib/tree/components/tree-node-item/tree-node-item.component.d.ts +4 -0
@@ -1,5 +1,5 @@
1
1
  import { __decorate } from 'tslib';
2
- import { CdkTrapFocus } from '@angular/cdk/a11y';
2
+ import { LiveAnnouncer, CdkTrapFocus } from '@angular/cdk/a11y';
3
3
  import { CdkOverlayOrigin, CdkConnectedOverlay } from '@angular/cdk/overlay';
4
4
  import { NgClass } from '@angular/common';
5
5
  import * as i0 from '@angular/core';
@@ -150,6 +150,13 @@ class DateSegmentEngine {
150
150
  const segment = this.segments[this.activeIndex];
151
151
  return isEditableSegment(segment) ? segment.kind : null;
152
152
  }
153
+ /** Texto bruto (sem padding de sublinhado) do segmento ativo — usado pelo anúncio de acessibilidade. */
154
+ getActiveSegmentText() {
155
+ if (this.activeIndex === null)
156
+ return null;
157
+ const segment = this.segments[this.activeIndex];
158
+ return isEditableSegment(segment) ? segment.text : null;
159
+ }
153
160
  selectSegmentAt(charIndex) {
154
161
  let acc = 0;
155
162
  for (let i = 0; i < this.segments.length; i++) {
@@ -262,7 +269,11 @@ class DateSegmentEngine {
262
269
  this.activeIndex = this.getFirstEditableIndex();
263
270
  this.freshEntry = true;
264
271
  }
265
- /** Incrementa/decrementa o segmento ativo, dando a volta (wrap) dentro do range válido. */
272
+ /**
273
+ * Incrementa/decrementa o segmento ativo, dando a volta (wrap) dentro do range válido.
274
+ * Exceção: ano vazio sempre pousa no ano atual do sistema na primeira seta (up ou down),
275
+ * em vez de 0000/9999 — só passa a incrementar/decrementar a partir da segunda seta.
276
+ */
266
277
  incrementActiveSegment(delta) {
267
278
  if (this.activeIndex === null)
268
279
  return;
@@ -273,6 +284,12 @@ class DateSegmentEngine {
273
284
  this.setAmPm(segment.text === 'PM' ? 0 : 1);
274
285
  return;
275
286
  }
287
+ if (segment.kind === 'year' && !segment.text) {
288
+ segment.text = String(new Date().getFullYear()).padStart(segment.length, '0');
289
+ this.freshEntry = true;
290
+ this.reconcileDayIfNeeded(segment.kind);
291
+ return;
292
+ }
276
293
  const { min, max } = this.boundsFor(segment.kind);
277
294
  const range = max - min + 1;
278
295
  const current = segment.text ? parseInt(segment.text, 10) : delta > 0 ? min - 1 : min;
@@ -704,12 +721,20 @@ class DatepickerComponent {
704
721
  hostElement = inject(ElementRef);
705
722
  translateService = inject(TranslateService);
706
723
  destroyRef = inject(DestroyRef);
724
+ liveAnnouncer = inject(LiveAnnouncer);
707
725
  currentLang = signal(this.translateService.currentLang);
708
726
  /** Reflete `(pointer: coarse)` — dispositivos touch preferem o popup do calendário ao teclado. */
709
727
  isTouchDevice = signal(typeof window !== 'undefined' && typeof window.matchMedia === 'function'
710
728
  ? window.matchMedia('(pointer: coarse)').matches
711
729
  : false);
712
730
  segmentEngine = new DateSegmentEngine();
731
+ /** Elemento que tinha foco antes do painel abrir — ver `captureFocusOrigin`/`closePanel`. */
732
+ elementToRestoreFocusTo = null;
733
+ /** `true` só durante o `.focus()` programático de restauração em `closePanel()` — evita que
734
+ * `handleInputFocus` interprete esse foco como um foco genuíno do usuário e reabra o painel
735
+ * na hora via `showOnFocus` (ex.: selecionar uma data devolve o foco pro input, que senão
736
+ * reabriria o painel imediatamente depois de fechá-lo). */
737
+ isRestoringFocusOnClose = false;
713
738
  lastSegmentConfig = null;
714
739
  measureCanvas;
715
740
  /** Incrementado a cada mutação do usuário — invalida callbacks de clique/foco adiados que ficaram obsoletos. */
@@ -744,6 +769,15 @@ class DatepickerComponent {
744
769
  const translated = this.resolveTranslatedOrDefault('platform.angular_components.hour_format', '24');
745
770
  return translated === '12' ? '12' : '24';
746
771
  });
772
+ static SEGMENT_LABEL_KEYS = {
773
+ day: 'platform.angular_components.datepicker_segment_day',
774
+ month: 'platform.angular_components.datepicker_segment_month',
775
+ year: 'platform.angular_components.datepicker_segment_year',
776
+ hour: 'platform.angular_components.datepicker_hour',
777
+ minute: 'platform.angular_components.datepicker_minute',
778
+ second: 'platform.angular_components.datepicker_second',
779
+ ampm: 'platform.angular_components.datepicker_segment_ampm',
780
+ };
747
781
  /** Modos cujo formato de exibição é resolvido pela engine de segmentos (independente de touch/readonly). */
748
782
  isSegmentModeCandidate = computed(() => {
749
783
  if (this.isMultipleMode())
@@ -756,14 +790,33 @@ class DatepickerComponent {
756
790
  /** Indica se o time picker deve usar o formato de 12 horas com seletor AM/PM. */
757
791
  is12HourFormat = computed(() => this.resolvedHourFormat() === '12');
758
792
  /** Hora exibida no time picker: 1–12 no formato 12h, 0–23 no formato 24h. */
759
- displayHours = computed(() => {
793
+ displayHours = computed(() => this.displayHourFor(this.hours()));
794
+ /** Meridiano atual derivado da hora interna (0–23). */
795
+ amPm = computed(() => this.meridiemFor(this.hours()));
796
+ displayHourFor(hours24) {
760
797
  if (!this.is12HourFormat())
761
- return this.hours();
762
- const h12 = this.hours() % DatepickerComponent.HOURS_PER_MERIDIEM;
798
+ return hours24;
799
+ const h12 = hours24 % DatepickerComponent.HOURS_PER_MERIDIEM;
763
800
  return h12 === 0 ? DatepickerComponent.HOURS_PER_MERIDIEM : h12;
764
- });
765
- /** Meridiano atual derivado da hora interna (0–23). */
766
- amPm = computed(() => this.hours() < DatepickerComponent.HOURS_PER_MERIDIEM ? 'AM' : 'PM');
801
+ }
802
+ meridiemFor(hours24) {
803
+ return hours24 < DatepickerComponent.HOURS_PER_MERIDIEM ? 'AM' : 'PM';
804
+ }
805
+ /** Texto (com AM/PM quando aplicável) da hora de destino do botão "aumentar"/"diminuir hora"
806
+ * — mesma motivação de `prevMonthTarget`/`nextMonthTarget`/`prevYearTarget`/`nextYearTarget`:
807
+ * sem isso, o botão só diz "aumentar hora", sem dizer qual hora vai resultar. */
808
+ formatHourTarget(hours24) {
809
+ const padded = this.padTime(this.displayHourFor(hours24));
810
+ return this.is12HourFormat() ? `${padded} ${this.meridiemFor(hours24)}` : padded;
811
+ }
812
+ prevHourTarget = computed(() => this.formatHourTarget((this.hours() - this.stepHour() + this.maxHours) % this.maxHours));
813
+ nextHourTarget = computed(() => this.formatHourTarget((this.hours() + this.stepHour()) % this.maxHours));
814
+ /** Mesma motivação, para os botões de minuto/segundo/AM-PM. */
815
+ prevMinuteTarget = computed(() => this.padTime((this.minutes() - this.minuteStep() + this.maxMinutes) % this.maxMinutes));
816
+ nextMinuteTarget = computed(() => this.padTime((this.minutes() + this.minuteStep()) % this.maxMinutes));
817
+ prevSecondTarget = computed(() => this.padTime((this.seconds() - this.stepSecond() + 60) % 60));
818
+ nextSecondTarget = computed(() => this.padTime((this.seconds() + this.stepSecond()) % 60));
819
+ nextMeridiemTarget = computed(() => (this.amPm() === 'AM' ? 'PM' : 'AM'));
767
820
  positions = [
768
821
  { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },
769
822
  { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },
@@ -772,17 +825,74 @@ class DatepickerComponent {
772
825
  currentMonthIndex = computed(() => this.viewDate().getMonth());
773
826
  currentYear = computed(() => this.viewDate().getFullYear());
774
827
  currentMonthKey = computed(() => this.monthKeys[this.currentMonthIndex()]);
828
+ /** Ano de destino do botão "ano anterior"/"próximo ano" (view de meses) — pro aria-label
829
+ * anunciar pra onde o botão vai, já que "Ano anterior" sozinho não diz qual ano é esse. */
830
+ prevYearTarget = computed(() => this.currentYear() - 1);
831
+ nextYearTarget = computed(() => this.currentYear() + 1);
832
+ /** Mês/ano de destino do botão "mês anterior"/"próximo mês" (view de calendário) — mesma
833
+ * motivação de `prevYearTarget`/`nextYearTarget`: "Mês anterior" sozinho não diz qual mês é
834
+ * esse, e cruzar a fronteira do ano (ex.: janeiro → dezembro do ano anterior) tornaria essa
835
+ * falta de contexto ainda mais confusa sem o ano junto. */
836
+ prevMonthTarget = computed(() => {
837
+ const view = this.viewDate();
838
+ const target = new Date(view.getFullYear(), view.getMonth() - 1, 1);
839
+ return target.toLocaleDateString(this.currentLang(), { month: 'long', year: 'numeric' });
840
+ });
841
+ nextMonthTarget = computed(() => {
842
+ const view = this.viewDate();
843
+ const target = new Date(view.getFullYear(), view.getMonth() + 1, 1);
844
+ return target.toLocaleDateString(this.currentLang(), { month: 'long', year: 'numeric' });
845
+ });
775
846
  showCalendar = computed(() => this.mode() !== 'time');
776
847
  showTimePicker = computed(() => this.mode() === 'datetime' || this.mode() === 'time');
777
848
  /** Seleção múltipla ativa: apenas no modo `date` com `selectionMode = 'multiple'`. */
778
849
  isMultipleMode = computed(() => this.selectionMode() === 'multiple' && this.mode() === 'date');
850
+ /** Instrução lida junto do rótulo da grade de dias — cada modo com semântica de seleção não
851
+ * óbvia (múltipla, intervalo) ganha uma frase própria; `range` ainda se divide em duas fases
852
+ * (escolhendo início vs. já com `pendingRangeStart`, escolhendo fim). */
853
+ calendarGridAriaLabelKey = computed(() => {
854
+ if (this.isMultipleMode())
855
+ return 'platform.angular_components.datepicker_calendar_label_multiple';
856
+ if (this.mode() === 'range') {
857
+ return this.pendingRangeStart()
858
+ ? 'platform.angular_components.datepicker_calendar_label_range_pending'
859
+ : 'platform.angular_components.datepicker_calendar_label_range';
860
+ }
861
+ return 'platform.angular_components.datepicker_calendar_label';
862
+ });
779
863
  orderedWeekDayKeys = computed(() => {
780
864
  const start = this.firstDayOfWeek();
781
865
  return [...this.weekDayKeys.slice(start), ...this.weekDayKeys.slice(0, start)];
782
866
  });
783
- dialogAriaLabelKey = computed(() => this.mode() === 'range'
784
- ? 'platform.angular_components.datepicker_select_range'
785
- : 'platform.angular_components.datepicker_select_date');
867
+ /** Ciente da fase de seleção em `range`: enquanto não há `pendingRangeStart`, é a mesma chave
868
+ * de sempre ("selecionar intervalo"); depois do primeiro clique, muda pra uma chave que cita
869
+ * a data inicial já escolhida, já que reabrir/reentrar no diálogo nesse meio-tempo não dava
870
+ * nenhuma pista de que a segunda metade do fluxo era a que faltava. */
871
+ dialogAriaLabelKey = computed(() => {
872
+ if (this.mode() !== 'range')
873
+ return 'platform.angular_components.datepicker_select_date';
874
+ return this.pendingRangeStart()
875
+ ? 'platform.angular_components.datepicker_select_range_end'
876
+ : 'platform.angular_components.datepicker_select_range';
877
+ });
878
+ dialogAriaLabelParams = computed(() => {
879
+ const pending = this.pendingRangeStart();
880
+ return pending ? { date: this.formatDayAriaLabel(pending) } : {};
881
+ });
882
+ rangeStatusElementId = computed(() => `${this.inputId()}-range-status`);
883
+ /** Texto do `<span>` `sr-only` referenciado por `aria-describedby` no `<input>` — dá ao campo
884
+ * um conteúdo persistente e acessível enquanto só a data inicial do intervalo foi escolhida,
885
+ * já que `inputDate` só reflete o valor completo depois da segunda escolha (a atualização
886
+ * parcial em `selectDate()` cobre o texto visível; isto cobre o que um leitor de tela lê ao
887
+ * focar/reler o campo). Usa `aria-describedby`, não `aria-label`, pra só ACRESCENTAR
888
+ * informação sem sobrescrever o nome acessível que integrações (dynamic-form, showcase)
889
+ * já controlam por fora do componente. */
890
+ rangePendingStatusText = computed(() => {
891
+ if (this.mode() !== 'range')
892
+ return '';
893
+ const pending = this.pendingRangeStart();
894
+ return pending ? this.buildRangeStartSelectedText(pending) : '';
895
+ });
786
896
  placeholderKey = computed(() => {
787
897
  const mode = this.mode();
788
898
  return `platform.angular_components.datepicker_placeholder_${mode}`;
@@ -846,6 +956,19 @@ class DatepickerComponent {
846
956
  return rows;
847
957
  });
848
958
  currentDecadeStart = computed(() => Math.floor(this.currentYear() / 10) * 10);
959
+ /** Intervalo de destino do botão "década anterior"/"próxima década" (view de anos) — mesma
960
+ * motivação de `prevYearTarget`/`nextYearTarget`. `navigatePrev`/`navigateNext` deslocam
961
+ * `viewDate` em ±10 anos (não ±12) nessa view; o grid exibido é que mostra 12 anos por
962
+ * página (ver `yearsGrid`) — daí o intervalo ir de `currentDecadeStart() ± 10` até
963
+ * `+ 11` pra bater exatamente com a página que o clique realmente abre. */
964
+ prevDecadeRange = computed(() => {
965
+ const start = this.currentDecadeStart() - 10;
966
+ return { startYear: start, endYear: start + 11 };
967
+ });
968
+ nextDecadeRange = computed(() => {
969
+ const start = this.currentDecadeStart() + 10;
970
+ return { startYear: start, endYear: start + 11 };
971
+ });
849
972
  yearsGrid = computed(() => {
850
973
  const start = this.currentDecadeStart();
851
974
  const rows = [];
@@ -982,33 +1105,58 @@ class DatepickerComponent {
982
1105
  open() {
983
1106
  if (this.disabled())
984
1107
  return;
1108
+ this.captureFocusOrigin();
985
1109
  this.isOpen.set(true);
986
1110
  this.prepareOpenView();
987
1111
  this.show.emit();
988
- if (this.mode() === 'time') {
989
- afterNextRender(() => this.increaseHourButton()?.nativeElement.focus(), { injector: this.injector });
990
- }
991
- else {
992
- this.focusBestCalendarTarget();
993
- }
1112
+ this.focusPanelAfterOpen();
994
1113
  }
995
- /** Abre o painel sem transferir o foco para o dropdown (usado pelo showOnFocus). */
1114
+ /** Abre o painel sem transferir o foco por padrão (usado pelo showOnFocus). Em modos sem
1115
+ * digitação por segmento (multiple/range/year/touch) o foco segue pro calendário igual em
1116
+ * open(); em modo segmentado o foco permanece no input pra continuar digitando. */
996
1117
  openOnFocus() {
997
1118
  if (this.disabled() || this.isOpen())
998
1119
  return;
1120
+ this.captureFocusOrigin();
999
1121
  this.isOpen.set(true);
1000
1122
  this.prepareOpenView();
1001
1123
  this.show.emit();
1002
- // Foco permanece no input — não chama focusBestCalendarTarget()
1124
+ if (!this.isSegmentedMode()) {
1125
+ this.focusPanelAfterOpen();
1126
+ }
1127
+ }
1128
+ focusPanelAfterOpen() {
1129
+ if (this.mode() === 'time') {
1130
+ afterNextRender(() => this.increaseHourButton()?.nativeElement.focus(), { injector: this.injector });
1131
+ }
1132
+ else {
1133
+ this.focusBestCalendarTarget();
1134
+ }
1135
+ }
1136
+ /** Guarda o elemento focado no momento em que o painel abre, pra devolver o foco pra lá ao
1137
+ * fechar em vez de sempre forçar pro botão do ícone — ver `closePanel()`. */
1138
+ captureFocusOrigin() {
1139
+ this.elementToRestoreFocusTo = document.activeElement instanceof HTMLElement ? document.activeElement : null;
1003
1140
  }
1004
1141
  /**
1005
1142
  * Define a view inicial do painel e posiciona o calendário no `defaultDate`
1006
1143
  * quando nenhum valor está selecionado.
1007
1144
  */
1008
1145
  prepareOpenView() {
1009
- const defaultDate = this.defaultDate();
1010
- if (defaultDate && !this.value() && !this.rangeValue()) {
1011
- this.viewDate.set(new Date(defaultDate.getFullYear(), defaultDate.getMonth(), 1));
1146
+ const range = this.rangeValue();
1147
+ if (this.mode() === 'range' && range?.start) {
1148
+ // Reabrir um intervalo já definido precisa cair sempre no mês do início — senão
1149
+ // `viewDate` fica onde uma navegação anterior parou por acaso (ex.: cruzar mês ao
1150
+ // escolher o fim), e `focusBestCalendarTarget()` (primeiro `[data-focus="selected"]`
1151
+ // em ordem de DOM) acaba focando o fim ou nenhuma célula, dependendo de qual mês
1152
+ // calha de estar em exibição.
1153
+ this.viewDate.set(new Date(range.start.getFullYear(), range.start.getMonth(), 1));
1154
+ }
1155
+ else {
1156
+ const defaultDate = this.defaultDate();
1157
+ if (defaultDate && !this.value() && !this.rangeValue()) {
1158
+ this.viewDate.set(new Date(defaultDate.getFullYear(), defaultDate.getMonth(), 1));
1159
+ }
1012
1160
  }
1013
1161
  if (this.mode() === 'month') {
1014
1162
  this.pickerView.set('months');
@@ -1025,21 +1173,64 @@ class DatepickerComponent {
1025
1173
  const panel = this.popupPanel()?.nativeElement;
1026
1174
  if (!panel)
1027
1175
  return;
1028
- const target = panel.querySelector('[data-focus="selected"]') ??
1176
+ const navHeaderTarget = this.pickerView() === 'calendar'
1177
+ ? null
1178
+ : panel.querySelector('[data-nav-header] button:not([disabled])');
1179
+ const target = navHeaderTarget ??
1180
+ panel.querySelector('[data-focus="selected"]') ??
1029
1181
  panel.querySelector('[data-focus="today"]') ??
1030
1182
  panel.querySelector('button:not([disabled])');
1031
1183
  target?.focus();
1032
1184
  }, { injector: this.injector });
1033
1185
  }
1034
- closePanel() {
1035
- const panel = (this.popupPanel()?.nativeElement ?? this.hostElement.nativeElement);
1036
- this.isOpen.set(false);
1186
+ /** Zera o estado de intervalo em andamento — usado tanto pelo fechamento total do painel
1187
+ * (`closePanel`, onde não faz sentido anunciar nada porque o diálogo inteiro está sumindo)
1188
+ * quanto pelo cancelamento leve via Escape dentro da grade (`cancelPendingRangeStart`), que
1189
+ * mantém o painel aberto e por isso anuncia a mudança separadamente. */
1190
+ resetPendingRangeSelection() {
1037
1191
  this.pendingRangeStart.set(null);
1038
1192
  this.hoverDate.set(null);
1193
+ }
1194
+ /** Cancelamento leve de uma seleção de intervalo em andamento (ver `handleCalendarGridKeydown`,
1195
+ * tecla Escape) — ao contrário de `closePanel`, o painel continua aberto, então aqui faz
1196
+ * sentido anunciar a mudança de estado. */
1197
+ cancelPendingRangeStart() {
1198
+ this.resetPendingRangeSelection();
1199
+ // A escolha do início (ramo `!pending` de selectDate()) grava o início pendente em
1200
+ // `inputDate` pra não deixar o campo obsoleto durante a seleção parcial (ver selectDate())
1201
+ // — cancelar essa escolha precisa desfazer isso também, voltando pro intervalo já
1202
+ // confirmado (ou vazio, se nenhum) — testado manualmente via devtools: sem esta linha, o
1203
+ // campo ficava preso mostrando a data pendente descartada mesmo com o intervalo antigo
1204
+ // ainda destacado no calendário.
1205
+ this.inputDate = this.formatForDisplay(this.rangeValue());
1206
+ void this.liveAnnouncer.announce(this.translateService.instant('platform.angular_components.datepicker_range_selection_cancelled'), 'polite');
1207
+ }
1208
+ closePanel() {
1209
+ const panelElement = this.popupPanel()?.nativeElement;
1210
+ this.isOpen.set(false);
1211
+ this.resetPendingRangeSelection();
1039
1212
  this._onTouched();
1040
- this.closed.emit(panel);
1213
+ this.closed.emit(panelElement ?? this.hostElement.nativeElement);
1214
+ // Só força o foco pra outro lugar se ele estiver dentro do painel que está sendo fechado
1215
+ // (senão o usuário ficaria com foco "preso" num elemento que está prestes a sumir do DOM).
1216
+ // Se o foco já está em outro lugar — ex.: o próprio input segmentado, que abriu o painel
1217
+ // via `openOnFocus` e nunca chegou a perder o foco — deixamos como está, em vez de puxar
1218
+ // o foco pro botão do ícone sem nenhum motivo (bug relatado via GNOME Orca: fechar o
1219
+ // painel clicando fora, com o foco ainda no input, fazia o foco pular pro ícone).
1220
+ const focusIsInsidePanel = panelElement != null && document.activeElement instanceof Node && panelElement.contains(document.activeElement);
1221
+ if (!focusIsInsidePanel)
1222
+ return;
1223
+ const restoreTarget = this.elementToRestoreFocusTo;
1224
+ this.elementToRestoreFocusTo = null;
1041
1225
  afterNextRender(() => {
1042
- this.iconButton()?.nativeElement.focus();
1226
+ this.isRestoringFocusOnClose = true;
1227
+ if (restoreTarget && document.contains(restoreTarget)) {
1228
+ restoreTarget.focus();
1229
+ }
1230
+ else {
1231
+ this.iconButton()?.nativeElement.focus();
1232
+ }
1233
+ this.isRestoringFocusOnClose = false;
1043
1234
  }, { injector: this.injector });
1044
1235
  }
1045
1236
  /**
@@ -1154,6 +1345,7 @@ class DatepickerComponent {
1154
1345
  this.segmentEngine.selectSegment(index);
1155
1346
  input.focus();
1156
1347
  this.selectActiveSegmentRange(input);
1348
+ this.announceActiveSegment();
1157
1349
  };
1158
1350
  focusAndSelect();
1159
1351
  setTimeout(focusAndSelect, 0);
@@ -1211,6 +1403,7 @@ class DatepickerComponent {
1211
1403
  const generation = ++this.interactionGeneration;
1212
1404
  this.segmentEngine.selectFirstSegment();
1213
1405
  this.selectActiveSegmentRange(input);
1406
+ this.announceGenuineFocus();
1214
1407
  setTimeout(() => {
1215
1408
  if (generation !== this.interactionGeneration)
1216
1409
  return;
@@ -1223,11 +1416,13 @@ class DatepickerComponent {
1223
1416
  // Já existe um segmento ativo — por exemplo, handleInputClick acabou de
1224
1417
  // defini-lo e está refocando o input programaticamente após um blur espúrio.
1225
1418
  // Não reinicia para o primeiro segmento; só garante que a seleção visual bata
1226
- // com o estado atual.
1419
+ // com o estado atual, e anuncia só o segmento (o resumo do valor inteiro é
1420
+ // reservado ao primeiro foco genuíno).
1227
1421
  this.selectActiveSegmentRange(input);
1422
+ this.announceActiveSegment();
1228
1423
  }
1229
1424
  }
1230
- if (this.showOnFocus()) {
1425
+ if (this.showOnFocus() && !this.isRestoringFocusOnClose) {
1231
1426
  this.openOnFocus();
1232
1427
  }
1233
1428
  }
@@ -1265,6 +1460,7 @@ class DatepickerComponent {
1265
1460
  if (wasSegmented) {
1266
1461
  this.ensureSegmentEngineConfigured();
1267
1462
  this.segmentEngine.deactivate();
1463
+ this.liveAnnouncer.clear();
1268
1464
  this.commitSegmentedValueIfComplete();
1269
1465
  this.inputDate = this.segmentEngine.isEmpty() ? '' : this.segmentEngine.getDisplayString();
1270
1466
  input.value = this.inputDate;
@@ -1407,6 +1603,7 @@ class DatepickerComponent {
1407
1603
  this.inputDate = this.segmentEngine.getDisplayString();
1408
1604
  input.value = this.inputDate;
1409
1605
  this.selectActiveSegmentRange(input);
1606
+ this.announceActiveSegment();
1410
1607
  input.dispatchEvent(new Event('input', { bubbles: true }));
1411
1608
  this.commitSegmentedValueIfComplete();
1412
1609
  }
@@ -1417,6 +1614,67 @@ class DatepickerComponent {
1417
1614
  const [start, end] = this.segmentEngine.getSegmentRange(index);
1418
1615
  input.setSelectionRange(start, end);
1419
1616
  }
1617
+ /** "{rótulo do segmento}, {valor}" (ex.: "Dia, 03") — texto do anúncio de nível de segmento. */
1618
+ buildSegmentAnnouncementText() {
1619
+ const kind = this.segmentEngine.activeKind();
1620
+ if (kind === null)
1621
+ return '';
1622
+ const label = this.translateService.instant(DatepickerComponent.SEGMENT_LABEL_KEYS[kind]);
1623
+ const text = this.segmentEngine.getActiveSegmentText();
1624
+ const value = text || this.translateService.instant('platform.angular_components.datepicker_segment_empty');
1625
+ return `${label}, ${value}`;
1626
+ }
1627
+ /** Anuncia via LiveAnnouncer o segmento ativo — chamado em todo ponto que muda o segmento ativo/seu
1628
+ * valor DEPOIS do primeiro foco genuíno (que já recebe esse mesmo texto embutido em `announceGenuineFocus`). */
1629
+ announceActiveSegment() {
1630
+ const text = this.buildSegmentAnnouncementText();
1631
+ if (text)
1632
+ void this.liveAnnouncer.announce(text, 'polite');
1633
+ }
1634
+ /** Resumo humanizado do valor inteiro (ex.: "10 de outubro de 2020", ou a frase genérica de campo
1635
+ * vazio) — complementa o `<input>` segmentado, que o leitor de tela lê de forma literal/pouco
1636
+ * natural (esqueleto de sublinhados quando vazio, dígitos separados por barra quando completo).
1637
+ * Formatação pura via `Intl`, sem chaves de tradução novas (exceto a frase de campo vazio).
1638
+ * Espelha `formatDayAriaLabel` pro modo `date`. */
1639
+ describeWholeValue() {
1640
+ if (this.segmentEngine.isEmpty()) {
1641
+ return this.translateService.instant('platform.angular_components.datepicker_no_value_selected');
1642
+ }
1643
+ const date = this.value();
1644
+ if (!date)
1645
+ return ''; // valor parcialmente digitado (incompleto) — nada humanizável ainda.
1646
+ const lang = this.currentLang();
1647
+ switch (this.mode()) {
1648
+ case 'date':
1649
+ return this.formatDayAriaLabel(date);
1650
+ case 'month':
1651
+ return date.toLocaleDateString(lang, { month: 'long', year: 'numeric' });
1652
+ case 'time':
1653
+ return date.toLocaleTimeString(lang, {
1654
+ hour: 'numeric',
1655
+ minute: '2-digit',
1656
+ second: this.showSeconds() ? '2-digit' : undefined,
1657
+ hour12: this.resolvedHourFormat() === '12',
1658
+ });
1659
+ case 'datetime':
1660
+ return date.toLocaleString(lang, {
1661
+ dateStyle: 'long',
1662
+ timeStyle: this.showSeconds() ? 'medium' : 'short',
1663
+ hour12: this.resolvedHourFormat() === '12',
1664
+ });
1665
+ default:
1666
+ return ''; // isSegmentedMode() já restringe a date/month/time/datetime
1667
+ }
1668
+ }
1669
+ /** Anúncio combinado no primeiro foco genuíno do campo: resumo do valor inteiro + segmento ativo,
1670
+ * numa ÚNICA chamada a `announce` (evita duas regiões concorrentes/uma cortando a outra). */
1671
+ announceGenuineFocus() {
1672
+ const summary = this.describeWholeValue();
1673
+ const segmentText = this.buildSegmentAnnouncementText();
1674
+ const combined = summary ? `${summary}. ${segmentText}` : segmentText;
1675
+ if (combined)
1676
+ void this.liveAnnouncer.announce(combined, 'polite');
1677
+ }
1420
1678
  /** Propaga o valor da engine para o modelo (CVA) assim que todos os segmentos estiverem completos. */
1421
1679
  commitSegmentedValueIfComplete() {
1422
1680
  if (!this.segmentEngine.isComplete()) {
@@ -1448,15 +1706,19 @@ class DatepickerComponent {
1448
1706
  if (this.pickerView() === 'years') {
1449
1707
  this.viewDate.set(new Date(view.getFullYear() - 10, view.getMonth(), 1));
1450
1708
  this.yearChange.emit({ month: view.getMonth(), year: view.getFullYear() - 10 });
1709
+ this.announceDecadeChange();
1451
1710
  }
1452
1711
  else if (this.pickerView() === 'months') {
1453
- this.viewDate.set(new Date(view.getFullYear() - 1, view.getMonth(), 1));
1454
- this.yearChange.emit({ month: view.getMonth(), year: view.getFullYear() - 1 });
1712
+ const newDate = new Date(view.getFullYear() - 1, view.getMonth(), 1);
1713
+ this.viewDate.set(newDate);
1714
+ this.yearChange.emit({ month: view.getMonth(), year: newDate.getFullYear() });
1715
+ this.announceYearChange(newDate);
1455
1716
  }
1456
1717
  else {
1457
1718
  const newDate = new Date(view.getFullYear(), view.getMonth() - 1, 1);
1458
1719
  this.viewDate.set(newDate);
1459
1720
  this.monthChange.emit({ month: newDate.getMonth(), year: newDate.getFullYear() });
1721
+ this.announceMonthChange(newDate);
1460
1722
  }
1461
1723
  }
1462
1724
  navigateNext() {
@@ -1464,18 +1726,55 @@ class DatepickerComponent {
1464
1726
  if (this.pickerView() === 'years') {
1465
1727
  this.viewDate.set(new Date(view.getFullYear() + 10, view.getMonth(), 1));
1466
1728
  this.yearChange.emit({ month: view.getMonth(), year: view.getFullYear() + 10 });
1729
+ this.announceDecadeChange();
1467
1730
  }
1468
1731
  else if (this.pickerView() === 'months') {
1469
- this.viewDate.set(new Date(view.getFullYear() + 1, view.getMonth(), 1));
1470
- this.yearChange.emit({ month: view.getMonth(), year: view.getFullYear() + 1 });
1732
+ const newDate = new Date(view.getFullYear() + 1, view.getMonth(), 1);
1733
+ this.viewDate.set(newDate);
1734
+ this.yearChange.emit({ month: view.getMonth(), year: newDate.getFullYear() });
1735
+ this.announceYearChange(newDate);
1471
1736
  }
1472
1737
  else {
1473
1738
  const newDate = new Date(view.getFullYear(), view.getMonth() + 1, 1);
1474
1739
  this.viewDate.set(newDate);
1475
1740
  this.monthChange.emit({ month: newDate.getMonth(), year: newDate.getFullYear() });
1741
+ this.announceMonthChange(newDate);
1476
1742
  }
1477
1743
  }
1744
+ /** Anuncia só "{mês} de {ano}" (ex.: "outubro de 2026") ao cruzar fronteira de mês na grade de dias.
1745
+ * O novo foco (button[role="gridcell"]) já carrega essa info dentro do aria-label longo de
1746
+ * `formatDayAriaLabel`, mas o nome do mês fica "enterrado" no meio da frase e passa despercebido
1747
+ * (confirmado com teste manual via Orca). Sem prefixo tipo "agora exibindo", mesma convenção
1748
+ * adotada por outros calendários acessíveis (ex.: react-aria). */
1749
+ announceMonthChange(newDate) {
1750
+ void this.liveAnnouncer.announce(newDate.toLocaleDateString(this.currentLang(), { month: 'long', year: 'numeric' }), 'polite');
1751
+ }
1752
+ /** Anuncia o ano atualmente exibido ao paginar a view 'months' (ex.: "2025"). O `<span>` central
1753
+ * que mostra esse ano no cabeçalho não é focável, e o aria-label dos botões de navegação só
1754
+ * fala o ano de DESTINO ("Ano anterior, 2025") — sem isso, o leitor de tela nunca confirma o
1755
+ * ano que passou a estar em exibição, só os alvos "anterior"/"próximo". */
1756
+ announceYearChange(newDate) {
1757
+ void this.liveAnnouncer.announce(newDate.toLocaleDateString(this.currentLang(), { year: 'numeric' }), 'polite');
1758
+ }
1759
+ /** Mesma motivação de `announceYearChange`, para a view 'years' (paginação de década) — anuncia
1760
+ * o intervalo atualmente exibido (ex.: "2020 – 2031"), espelhando o texto do `<span>` central. */
1761
+ announceDecadeChange() {
1762
+ void this.liveAnnouncer.announce(`${this.currentDecadeStart()} – ${this.currentDecadeStart() + 11}`, 'polite');
1763
+ }
1478
1764
  handleCalendarGridKeydown(event) {
1765
+ if (event.key === 'Escape' && this.mode() === 'range' && this.pendingRangeStart() !== null) {
1766
+ event.preventDefault();
1767
+ // Cancelamento leve: desiste só da data inicial pendente, mantendo o painel aberto,
1768
+ // em vez de fechar o diálogo inteiro (o único caminho antes disso). `stopPropagation`
1769
+ // impede esse mesmo Escape de borbulhar até `document.body`, onde o
1770
+ // `OverlayKeyboardDispatcher` do CDK escuta `keydown` (fase de bubble, sem capture) e
1771
+ // dispararia `handleOverlayKeydown`/`closePanel()` — sem isso, o cancelamento leve e o
1772
+ // fechamento total aconteceriam nesse mesmo Escape. Sem `pendingRangeStart`, esse `if`
1773
+ // é falso e o Escape segue intocado até `document.body`, fechando o painel como sempre.
1774
+ event.stopPropagation();
1775
+ this.cancelPendingRangeStart();
1776
+ return;
1777
+ }
1479
1778
  const ARROWS = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
1480
1779
  if (!ARROWS.includes(event.key))
1481
1780
  return;
@@ -1554,6 +1853,11 @@ class DatepickerComponent {
1554
1853
  const pending = this.pendingRangeStart();
1555
1854
  if (!pending) {
1556
1855
  this.pendingRangeStart.set(day.date);
1856
+ // Sem isso o <input> ficava com o valor anterior (ou vazio) enquanto só a data
1857
+ // inicial estava escolhida — tanto o texto visível quanto o que um leitor de tela
1858
+ // lê ao focar o campo ficavam obsoletos até a segunda escolha.
1859
+ this.inputDate = this.formatForDisplay({ start: day.date, end: null });
1860
+ this.announceRangeStartSelected(day.date);
1557
1861
  }
1558
1862
  else {
1559
1863
  const [start, end] = pending.getTime() <= day.date.getTime() ? [pending, day.date] : [day.date, pending];
@@ -1562,6 +1866,7 @@ class DatepickerComponent {
1562
1866
  this.inputDate = this.formatForDisplay(range);
1563
1867
  this._onChange(range);
1564
1868
  this.selected.emit(range);
1869
+ this.announceRangeCompleted(range);
1565
1870
  this.closePanel();
1566
1871
  }
1567
1872
  return;
@@ -1597,6 +1902,44 @@ class DatepickerComponent {
1597
1902
  this.onValidatorChange();
1598
1903
  this._onChange(emitValue);
1599
1904
  this.selected.emit(emitValue);
1905
+ this.announceMultipleDateToggle(normalized, index < 0);
1906
+ }
1907
+ /** Anuncia via LiveAnnouncer a data completa (dia da semana, dia, mês, ano) e se ela acabou
1908
+ * de ser selecionada ou desmarcada — pro usuário de leitor de tela saber exatamente o que
1909
+ * mudou antes de seguir escolhendo a próxima data. */
1910
+ announceMultipleDateToggle(date, isNowSelected) {
1911
+ const dateText = this.formatDayAriaLabel(date);
1912
+ const key = isNowSelected
1913
+ ? 'platform.angular_components.datepicker_date_selected'
1914
+ : 'platform.angular_components.datepicker_date_deselected';
1915
+ void this.liveAnnouncer.announce(this.translateService.instant(key, { date: dateText }), 'polite');
1916
+ }
1917
+ /** Texto compartilhado entre o anúncio transitório de início de intervalo escolhido
1918
+ * (`announceRangeStartSelected`) e o status persistente exposto via `aria-describedby` no
1919
+ * `<input>` (`rangePendingStatusText`) — mesma redação nos dois lugares de propósito, pra não
1920
+ * soarem como dois estados diferentes pro mesmo momento. */
1921
+ buildRangeStartSelectedText(date) {
1922
+ return this.translateService.instant('platform.angular_components.datepicker_range_start_selected', {
1923
+ date: this.formatDayAriaLabel(date),
1924
+ });
1925
+ }
1926
+ /** Anuncia que a data INICIAL do intervalo foi escolhida — o primeiro clique em `range` era
1927
+ * mudo (ao contrário do toggle em modo `multiple`, sempre anunciado). Recebe um `Date` puro,
1928
+ * não um clique: `selectToday()` chama `selectDate()` internamente e herda este anúncio de
1929
+ * graça, sem precisar de uma segunda chamada. */
1930
+ announceRangeStartSelected(date) {
1931
+ void this.liveAnnouncer.announce(this.buildRangeStartSelectedText(date), 'polite');
1932
+ }
1933
+ /** Anuncia o intervalo concluído, chamado antes de `closePanel()` — o `LiveAnnouncer` escreve
1934
+ * numa região `aria-live` própria e desacoplada do foco, então não é cortado pela restauração
1935
+ * de foco que `closePanel()` agenda um tick depois via `afterNextRender`. */
1936
+ announceRangeCompleted(range) {
1937
+ if (!range.start || !range.end)
1938
+ return;
1939
+ void this.liveAnnouncer.announce(this.translateService.instant('platform.angular_components.datepicker_range_selected', {
1940
+ start: this.formatDayAriaLabel(range.start),
1941
+ end: this.formatDayAriaLabel(range.end),
1942
+ }), 'polite');
1600
1943
  }
1601
1944
  selectYear(year) {
1602
1945
  if (this.isYearDisabled(year))
@@ -1642,9 +1985,20 @@ class DatepickerComponent {
1642
1985
  };
1643
1986
  this.selectDate(calDay);
1644
1987
  this.todayClick.emit(today);
1988
+ if (this.mode() === 'range' && this.isOpen()) {
1989
+ // Em range, selectDate() só fecha o painel na segunda escolha (ver seu ramo
1990
+ // 'range'); na primeira, o foco fica parado no botão "Hoje" do rodapé, fora da
1991
+ // grade — sem isso o usuário não tinha nenhuma pista de que precisava voltar pra
1992
+ // grade pra escolher a data final. A célula de hoje já carrega
1993
+ // `data-focus="selected"` (isRangeStart acabou de ser setado por selectDate), que
1994
+ // focusBestCalendarTarget() já prioriza. O anúncio de "início selecionado" já
1995
+ // disparou dentro de selectDate() antes deste bloco rodar.
1996
+ this.focusBestCalendarTarget();
1997
+ }
1645
1998
  }
1646
1999
  }
1647
2000
  clearValue(event) {
2001
+ const hadRangeInProgress = this.mode() === 'range' && (this.pendingRangeStart() !== null || this.rangeValue() !== null);
1648
2002
  this.value.set(null);
1649
2003
  this.hours.set(0);
1650
2004
  this.minutes.set(0);
@@ -1655,6 +2009,11 @@ class DatepickerComponent {
1655
2009
  this.setDisplayFor(null);
1656
2010
  this._onChange(null);
1657
2011
  this.clearClick.emit(event);
2012
+ if (hadRangeInProgress) {
2013
+ // Só anuncia quando havia de fato algo a limpar — evita "intervalo limpo" toda vez
2014
+ // que alguém aperta "Limpar" por garantia, sem nada selecionado ainda.
2015
+ void this.liveAnnouncer.announce(this.translateService.instant('platform.angular_components.datepicker_range_cleared'), 'polite');
2016
+ }
1658
2017
  this.closePanel();
1659
2018
  }
1660
2019
  confirm() {
@@ -1815,13 +2174,38 @@ class DatepickerComponent {
1815
2174
  padTime(value) {
1816
2175
  return String(value).padStart(2, '0');
1817
2176
  }
1818
- formatDayAriaLabel(date) {
1819
- return date.toLocaleDateString(this.currentLang(), {
2177
+ /** `day` é opcional e só usado em `mode="range"` — os demais call sites (resumo do valor
2178
+ * segmentado, anúncio de toggle em modo `multiple`) nunca têm um `CalendarDay` à mão e nunca
2179
+ * rodam em `range`, então continuam recebendo exatamente o texto de sempre. */
2180
+ formatDayAriaLabel(date, day) {
2181
+ const base = date.toLocaleDateString(this.currentLang(), {
1820
2182
  weekday: 'long',
1821
2183
  year: 'numeric',
1822
2184
  month: 'long',
1823
2185
  day: 'numeric',
1824
2186
  });
2187
+ if (!day || this.mode() !== 'range')
2188
+ return base;
2189
+ const suffix = this.rangeDayStatusSuffix(day);
2190
+ return suffix ? `${base}, ${suffix}` : base;
2191
+ }
2192
+ /** Sufixo que diz o papel do dia dentro do intervalo selecionado — sem isso, toda célula da
2193
+ * grade soa idêntica pro leitor de tela, e o único jeito de saber onde está o início/fim é
2194
+ * enxergando o destaque visual. */
2195
+ rangeDayStatusSuffix(day) {
2196
+ if (day.isRangeStart && day.isRangeEnd) {
2197
+ return this.translateService.instant('platform.angular_components.datepicker_range_start_end');
2198
+ }
2199
+ if (day.isRangeStart) {
2200
+ return this.translateService.instant('platform.angular_components.datepicker_range_start');
2201
+ }
2202
+ if (day.isRangeEnd) {
2203
+ return this.translateService.instant('platform.angular_components.datepicker_range_end');
2204
+ }
2205
+ if (day.isInRange) {
2206
+ return this.translateService.instant('platform.angular_components.datepicker_range_in_range');
2207
+ }
2208
+ return '';
1825
2209
  }
1826
2210
  /** Formata o valor para exibição no input, aplicando rangeSeparator, dateFormat e multipleSeparator. */
1827
2211
  formatForDisplay(value) {
@@ -1963,7 +2347,7 @@ class DatepickerComponent {
1963
2347
  useExisting: DatepickerComponent,
1964
2348
  multi: true,
1965
2349
  },
1966
- ], viewQueries: [{ propertyName: "popupPanel", first: true, predicate: ["popupPanel"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "increaseHourButton", first: true, predicate: ["increaseHourButton"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "iconButton", first: true, predicate: ["iconButton"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "triggerInput", first: true, predicate: ["triggerInput"], descendants: true, read: ElementRef, isSignal: true }], ngImport: i0, template: "<div\n cdkOverlayOrigin\n #trigger=\"cdkOverlayOrigin\"\n class=\"relative flex w-full items-center\"\n role=\"combobox\"\n aria-haspopup=\"grid\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-controls]=\"popupId()\"\n>\n <input\n #triggerInput\n class=\"h-[35px] w-full rounded-small border border-solid border-grayscale-30 pl-3 text-sm outline-none transition-colors focus:border-primary\"\n [class.pr-10]=\"showIcon() && !showClear()\"\n [class.pr-16]=\"showIcon() && showClear()\"\n [class.pr-6]=\"!showIcon() && showClear()\"\n [class.bg-grayscale-0]=\"!disabled()\"\n [class.text-grayscale-90]=\"!disabled()\"\n [class.border-grayscale-20]=\"disabled()\"\n [class.bg-grayscale-5]=\"disabled()\"\n [class.text-grayscale-30]=\"disabled()\"\n [class.cursor-not-allowed]=\"disabled()\"\n [id]=\"inputId()\"\n [name]=\"name() ?? inputId()\"\n type=\"text\"\n [placeholder]=\"placeholder() ?? (placeholderKey() | translate)\"\n [disabled]=\"disabled()\"\n [readonly]=\"\n readonlyInput() ||\n mode() === 'range' ||\n mode() === 'year' ||\n isMultipleMode() ||\n (isSegmentModeCandidate() && isTouchDevice())\n \"\n [tabIndex]=\"tabindex() ?? null\"\n [autofocus]=\"autofocus()\"\n [(ngModel)]=\"inputDate\"\n (ngModelChange)=\"handleInputChange($event)\"\n (focus)=\"handleInputFocus($event)\"\n (blur)=\"handleInputBlur($event)\"\n (mousedown)=\"handleInputClick($event)\"\n (keydown)=\"handleTriggerKeydown($event)\"\n (input)=\"handleNativeInput($event)\"\n [attr.aria-invalid]=\"ngControl?.control?.invalid || null\"\n />\n\n @if (showClear() && inputDate) {\n <button\n type=\"button\"\n class=\"absolute flex h-[35px] w-6 items-center justify-center text-grayscale-60 transition-colors hover:text-grayscale-90\"\n [class.right-9]=\"showIcon()\"\n [class.right-0]=\"!showIcon()\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_clear' | translate\"\n (click)=\"clearValue($event)\"\n >\n <i\n class=\"fas fa-times text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n\n @if (showIcon()) {\n <button\n #iconButton\n type=\"button\"\n class=\"absolute right-0 flex h-[35px] w-9 items-center justify-center border-l border-solid transition-colors\"\n [class.border-grayscale-20]=\"disabled()\"\n [class.text-grayscale-30]=\"disabled()\"\n [class.cursor-not-allowed]=\"disabled()\"\n [class.border-grayscale-30]=\"!disabled() && !isFocused()\"\n [class.border-primary]=\"isFocused() && !disabled()\"\n [class.text-grayscale-90]=\"!disabled()\"\n [class.hover:bg-grayscale-10]=\"!disabled()\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_open' | translate\"\n (click)=\"toggle()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n >\n <i\n [class]=\"resolvedIcon()\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n</div>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayPositions]=\"positions\"\n (backdropClick)=\"handleBackdropClick($event)\"\n (overlayKeydown)=\"handleOverlayKeydown($event)\"\n (detach)=\"isOpen.set(false)\"\n>\n <div\n #popupPanel\n class=\"z-50 w-72 rounded-medium border border-solid border-grayscale-30 bg-grayscale-0 shadow-md\"\n role=\"dialog\"\n cdkTrapFocus\n [id]=\"popupId()\"\n [attr.aria-label]=\"dialogAriaLabelKey() | translate\"\n >\n @if (showCalendar()) {\n @if (pickerView() === 'calendar') {\n <!-- Cabe\u00E7alho de navega\u00E7\u00E3o mensal -->\n <div class=\"flex items-center justify-between border-b border-solid border-grayscale-30 px-3 py-2\">\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"prevDisabled()\"\n [attr.aria-disabled]=\"prevDisabled() ? 'true' : null\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_prev_month' | translate\"\n (click)=\"navigatePrev()\"\n >\n <i\n class=\"fas fa-chevron-left text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n\n <button\n type=\"button\"\n class=\"flex items-center gap-1 rounded-small px-2 py-1 text-sm font-medium text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_select_month_year' | translate\"\n (click)=\"switchToMonths()\"\n >\n {{ currentMonthKey() | translate }}&nbsp;{{ currentYear() }}\n <i\n class=\"fas fa-chevron-down text-[10px]\"\n aria-hidden=\"true\"\n ></i>\n </button>\n\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"nextDisabled()\"\n [attr.aria-disabled]=\"nextDisabled() ? 'true' : null\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_next_month' | translate\"\n (click)=\"navigateNext()\"\n >\n <i\n class=\"fas fa-chevron-right text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n\n <!-- Cabe\u00E7alhos dos dias da semana -->\n <div\n class=\"grid grid-cols-7 px-3 pt-2\"\n role=\"row\"\n >\n @for (dayKey of orderedWeekDayKeys(); track dayKey) {\n <div\n class=\"flex h-8 items-center justify-center text-xs font-medium text-grayscale-60\"\n role=\"columnheader\"\n [attr.aria-label]=\"dayKey | translate\"\n >\n {{ dayKey | translate }}\n </div>\n }\n </div>\n\n <!-- Grade do calend\u00E1rio -->\n <div\n class=\"grid grid-cols-7 px-3 pb-2\"\n role=\"grid\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_calendar_label'\n | translate: { month: (currentMonthKey() | translate), year: currentYear() }\n \"\n (keydown)=\"handleCalendarGridKeydown($event)\"\n >\n @for (week of calendarWeeks(); track $index) {\n <div\n role=\"row\"\n class=\"contents\"\n >\n @for (day of week; track day.date.toISOString()) {\n <button\n type=\"button\"\n role=\"gridcell\"\n class=\"flex h-8 w-8 items-center justify-center rounded-[50%] text-sm font-normal transition-colors\"\n [class.invisible]=\"!showOtherMonths() && !day.isCurrentMonth\"\n [attr.aria-label]=\"formatDayAriaLabel(day.date)\"\n [attr.aria-selected]=\"day.isSelected || day.isRangeStart || day.isRangeEnd || null\"\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\n [attr.aria-disabled]=\"day.isDisabled ? 'true' : null\"\n [attr.aria-hidden]=\"!showOtherMonths() && !day.isCurrentMonth ? 'true' : null\"\n [attr.data-focus]=\"\n day.isSelected || day.isRangeStart || day.isRangeEnd\n ? 'selected'\n : day.isToday\n ? 'today'\n : null\n \"\n [disabled]=\"day.isDisabled\"\n [ngClass]=\"{\n 'bg-primary font-semibold text-grayscale-0':\n day.isSelected || day.isRangeStart || day.isRangeEnd,\n 'bg-grayscale-10 hover:bg-grayscale-20':\n day.isInRange && !day.isRangeStart && !day.isRangeEnd,\n 'text-grayscale-90 hover:bg-grayscale-10':\n !day.isSelected &&\n !day.isRangeStart &&\n !day.isRangeEnd &&\n !day.isDisabled &&\n day.isCurrentMonth,\n 'text-grayscale-60 hover:bg-grayscale-10':\n !day.isSelected &&\n !day.isRangeStart &&\n !day.isRangeEnd &&\n !day.isDisabled &&\n !day.isCurrentMonth,\n 'ring-2 ring-inset ring-primary':\n day.isToday && !day.isSelected && !day.isRangeStart && !day.isRangeEnd,\n 'cursor-not-allowed text-grayscale-30': day.isDisabled,\n }\"\n (mouseenter)=\"onDayHover(day.date)\"\n (mouseleave)=\"onDayHover(null)\"\n (click)=\"selectDate(day)\"\n >\n {{ day.dayOfMonth }}\n </button>\n }\n </div>\n }\n </div>\n }\n\n @if (pickerView() === 'years') {\n <!-- Cabe\u00E7alho de navega\u00E7\u00E3o por d\u00E9cada -->\n <div class=\"flex items-center justify-between border-b border-solid border-grayscale-30 px-3 py-2\">\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"prevDisabled()\"\n [attr.aria-disabled]=\"prevDisabled() ? 'true' : null\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_prev_decade' | translate\"\n (click)=\"navigatePrev()\"\n >\n <i\n class=\"fas fa-chevron-left text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n\n <span class=\"text-sm font-medium text-grayscale-90\"\n >{{ currentDecadeStart() }} \u2013 {{ currentDecadeStart() + 11 }}</span\n >\n\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"nextDisabled()\"\n [attr.aria-disabled]=\"nextDisabled() ? 'true' : null\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_next_decade' | translate\"\n (click)=\"navigateNext()\"\n >\n <i\n class=\"fas fa-chevron-right text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n\n <!-- Grade de anos -->\n <div\n class=\"grid grid-cols-3 gap-2 px-3 py-3\"\n role=\"grid\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_select_year' | translate\"\n >\n @for (row of yearsGrid(); track $index) {\n @for (year of row; track year) {\n <button\n type=\"button\"\n role=\"gridcell\"\n class=\"flex h-9 items-center justify-center rounded-small text-sm font-normal transition-colors\"\n [attr.aria-selected]=\"isYearSelected(year) || null\"\n [attr.aria-disabled]=\"isYearDisabled(year) ? 'true' : null\"\n [attr.aria-current]=\"isCurrentYear(year) ? 'date' : null\"\n [attr.data-focus]=\"\n isYearSelected(year) ? 'selected' : isCurrentYear(year) ? 'today' : null\n \"\n [disabled]=\"isYearDisabled(year)\"\n [ngClass]=\"{\n 'bg-primary font-semibold text-grayscale-0': isYearSelected(year),\n 'ring-2 ring-inset ring-primary':\n isCurrentYear(year) && !isYearSelected(year) && !isYearDisabled(year),\n 'text-grayscale-90 hover:bg-grayscale-10':\n !isYearSelected(year) && !isYearDisabled(year),\n 'cursor-not-allowed text-grayscale-30': isYearDisabled(year),\n }\"\n (click)=\"selectYear(year)\"\n >\n {{ year }}\n </button>\n }\n }\n </div>\n }\n\n @if (pickerView() === 'months') {\n <!-- Cabe\u00E7alho de navega\u00E7\u00E3o anual -->\n <div class=\"flex items-center justify-between border-b border-solid border-grayscale-30 px-3 py-2\">\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"prevDisabled()\"\n [attr.aria-disabled]=\"prevDisabled() ? 'true' : null\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_prev_year' | translate\"\n (click)=\"navigatePrev()\"\n >\n <i\n class=\"fas fa-chevron-left text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n\n <span class=\"text-sm font-medium text-grayscale-90\">{{ currentYear() }}</span>\n\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"nextDisabled()\"\n [attr.aria-disabled]=\"nextDisabled() ? 'true' : null\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_next_year' | translate\"\n (click)=\"navigateNext()\"\n >\n <i\n class=\"fas fa-chevron-right text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n\n <!-- Grade de meses -->\n <div\n class=\"grid grid-cols-3 gap-2 px-3 py-3\"\n role=\"grid\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_select_month' | translate\"\n >\n @for (row of monthsGrid(); track $index) {\n @for (month of row; track month.index) {\n <button\n type=\"button\"\n role=\"gridcell\"\n class=\"flex h-9 items-center justify-center rounded-small text-sm font-normal transition-colors\"\n [attr.aria-selected]=\"isMonthSelected(month.index) || null\"\n [attr.aria-disabled]=\"isMonthDisabled(month.index) ? 'true' : null\"\n [attr.data-focus]=\"isMonthSelected(month.index) ? 'selected' : null\"\n [disabled]=\"isMonthDisabled(month.index)\"\n [ngClass]=\"{\n 'bg-primary font-semibold text-grayscale-0': isMonthSelected(month.index),\n 'text-grayscale-90 hover:bg-grayscale-10':\n !isMonthSelected(month.index) && !isMonthDisabled(month.index),\n 'cursor-not-allowed text-grayscale-30': isMonthDisabled(month.index),\n }\"\n (click)=\"selectMonth(month.index)\"\n >\n {{ month.key | translate }}\n </button>\n }\n }\n </div>\n\n @if (mode() !== 'month') {\n <div class=\"border-t border-solid border-grayscale-30 px-3 py-2\">\n <button\n type=\"button\"\n class=\"flex items-center gap-2 rounded-small px-2 py-1 text-sm text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n (click)=\"backToCalendar()\"\n >\n <i\n class=\"fas fa-arrow-left\"\n aria-hidden=\"true\"\n ></i>\n {{ 'platform.angular_components.datepicker_back_to_calendar' | translate }}\n </button>\n </div>\n }\n }\n }\n\n <!-- Time picker -->\n @if (showTimePicker()) {\n <div\n class=\"flex items-center justify-center gap-3 px-4 py-3\"\n [class.border-t]=\"showCalendar()\"\n [class.border-solid]=\"showCalendar()\"\n [class.border-grayscale-30]=\"showCalendar()\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_select_time' | translate\"\n >\n <!-- Horas -->\n <div class=\"flex flex-col items-center gap-1\">\n <button\n #increaseHourButton\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_increment_hour' | translate\"\n (click)=\"incrementHours()\"\n >\n <i\n class=\"fas fa-chevron-up text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n <input\n type=\"text\"\n inputmode=\"numeric\"\n [attr.maxlength]=\"timeInputMaxLength\"\n class=\"h-9 w-12 rounded-small border border-solid border-grayscale-30 bg-grayscale-5 text-center text-base font-medium text-grayscale-90 outline-none focus:border-primary focus:outline-1 focus:outline-primary\"\n [value]=\"padTime(displayHours())\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_hour' | translate\"\n aria-live=\"polite\"\n pattern=\"[0-9]+\"\n (keydown)=\"handleHoursKeydown($event)\"\n (change)=\"handleHoursInput($event)\"\n />\n <button\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_decrement_hour' | translate\"\n (click)=\"decrementHours()\"\n >\n <i\n class=\"fas fa-chevron-down text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n\n <span\n class=\"text-xl font-bold text-grayscale-60\"\n aria-hidden=\"true\"\n >:</span\n >\n\n <!-- Minutos -->\n <div class=\"flex flex-col items-center gap-1\">\n <button\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_increment_minute' | translate\"\n (click)=\"incrementMinutes()\"\n >\n <i\n class=\"fas fa-chevron-up text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n <input\n type=\"text\"\n inputmode=\"numeric\"\n [attr.maxlength]=\"timeInputMaxLength\"\n class=\"h-9 w-12 rounded-small border border-solid border-grayscale-30 bg-grayscale-5 text-center text-base font-medium text-grayscale-90 outline-none focus:border-primary focus:outline-1 focus:outline-primary\"\n [value]=\"padTime(minutes())\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_minute' | translate\"\n aria-live=\"polite\"\n pattern=\"[0-9]+\"\n (keydown)=\"handleMinutesKeydown($event)\"\n (change)=\"handleMinutesInput($event)\"\n />\n <button\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_decrement_minute' | translate\"\n (click)=\"decrementMinutes()\"\n >\n <i\n class=\"fas fa-chevron-down text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n\n @if (showSeconds()) {\n <span\n class=\"text-xl font-bold text-grayscale-60\"\n aria-hidden=\"true\"\n >:</span\n >\n\n <!-- Segundos -->\n <div class=\"flex flex-col items-center gap-1\">\n <button\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_increment_second' | translate\"\n (click)=\"incrementSeconds()\"\n >\n <i\n class=\"fas fa-chevron-up text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n <input\n type=\"text\"\n inputmode=\"numeric\"\n [attr.maxlength]=\"timeInputMaxLength\"\n class=\"h-9 w-12 rounded-small border border-solid border-grayscale-30 bg-grayscale-5 text-center text-base font-medium text-grayscale-90 outline-none focus:border-primary focus:outline-1 focus:outline-primary\"\n [value]=\"padTime(seconds())\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_second' | translate\"\n aria-live=\"polite\"\n pattern=\"[0-9]+\"\n (keydown)=\"handleSecondsKeydown($event)\"\n (change)=\"handleSecondsInput($event)\"\n />\n <button\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_decrement_second' | translate\"\n (click)=\"decrementSeconds()\"\n >\n <i\n class=\"fas fa-chevron-down text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n }\n\n @if (is12HourFormat()) {\n <!-- Seletor AM/PM -->\n <button\n type=\"button\"\n class=\"flex h-9 w-12 items-center justify-center rounded-small border border-solid border-grayscale-30 bg-grayscale-5 text-base font-medium text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_toggle_meridiem' | translate\"\n aria-live=\"polite\"\n (click)=\"toggleAmPm()\"\n >\n {{ amPm() }}\n </button>\n }\n </div>\n }\n\n <!-- Rodap\u00E9 de a\u00E7\u00F5es -->\n @if (showButtonBar() || mode() === 'datetime' || mode() === 'time') {\n <div class=\"flex items-center justify-between border-t border-solid border-grayscale-30 px-3 py-2\">\n @if (showButtonBar()) {\n <div>\n @if (mode() === 'date' || mode() === 'datetime' || mode() === 'range') {\n <button\n type=\"button\"\n class=\"rounded-small px-2 py-1 text-sm text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n (click)=\"selectToday()\"\n >\n {{ 'platform.angular_components.datepicker_today' | translate }}\n </button>\n }\n </div>\n\n <div class=\"flex gap-2\">\n <button\n type=\"button\"\n class=\"rounded-small px-2 py-1 text-sm text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n (click)=\"clearValue($event)\"\n >\n {{ 'platform.angular_components.datepicker_clear' | translate }}\n </button>\n\n @if (mode() === 'datetime' || mode() === 'time') {\n <button\n type=\"button\"\n class=\"rounded-small bg-primary px-3 py-1 text-sm font-medium text-grayscale-0 transition-colors hover:opacity-90\"\n (click)=\"confirm()\"\n >\n {{ 'platform.angular_components.datepicker_confirm' | translate }}\n </button>\n }\n </div>\n } @else {\n <div></div>\n <div>\n @if (mode() === 'datetime' || mode() === 'time') {\n <button\n type=\"button\"\n class=\"rounded-small bg-primary px-3 py-1 text-sm font-medium text-grayscale-0 transition-colors hover:opacity-90\"\n (click)=\"confirm()\"\n >\n {{ 'platform.angular_components.datepicker_confirm' | translate }}\n </button>\n }\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n\n", styles: [":host{display:block;position:relative;width:100%}:host.ng-invalid.ng-dirty input{border-color:#c13018}:host.ng-invalid.ng-dirty input:focus{border-color:#c13018;outline-color:#c13018}:host.ng-invalid.ng-dirty button[type=button]{border-color:#c13018}:host.no-icon button[type=button]{display:none}:host.no-icon input{padding-right:.75rem}button[type=button]:focus-visible{outline:2px solid #428bca;outline-offset:1px;border-radius:inherit}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }, { kind: "directive", type: CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }] });
2350
+ ], viewQueries: [{ propertyName: "popupPanel", first: true, predicate: ["popupPanel"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "increaseHourButton", first: true, predicate: ["increaseHourButton"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "iconButton", first: true, predicate: ["iconButton"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "triggerInput", first: true, predicate: ["triggerInput"], descendants: true, read: ElementRef, isSignal: true }], ngImport: i0, template: "<div\n cdkOverlayOrigin\n #trigger=\"cdkOverlayOrigin\"\n class=\"relative flex w-full items-center\"\n role=\"combobox\"\n aria-haspopup=\"grid\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-controls]=\"popupId()\"\n>\n <input\n #triggerInput\n class=\"h-[35px] w-full rounded-small border border-solid border-grayscale-30 pl-3 text-sm outline-none transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-[var(--s-focus-ring-color,#0090ff)]\"\n [class.pr-10]=\"showIcon() && !showClear()\"\n [class.pr-16]=\"showIcon() && showClear()\"\n [class.pr-6]=\"!showIcon() && showClear()\"\n [class.bg-grayscale-0]=\"!disabled()\"\n [class.text-grayscale-90]=\"!disabled()\"\n [class.border-grayscale-20]=\"disabled()\"\n [class.bg-grayscale-5]=\"disabled()\"\n [class.text-grayscale-30]=\"disabled()\"\n [class.cursor-not-allowed]=\"disabled()\"\n [id]=\"inputId()\"\n [name]=\"name() ?? inputId()\"\n type=\"text\"\n [placeholder]=\"placeholder() ?? (placeholderKey() | translate)\"\n [disabled]=\"disabled()\"\n [readonly]=\"\n readonlyInput() ||\n mode() === 'range' ||\n mode() === 'year' ||\n isMultipleMode() ||\n (isSegmentModeCandidate() && isTouchDevice())\n \"\n [tabIndex]=\"tabindex() ?? null\"\n [autofocus]=\"autofocus()\"\n [(ngModel)]=\"inputDate\"\n (ngModelChange)=\"handleInputChange($event)\"\n (focus)=\"handleInputFocus($event)\"\n (blur)=\"handleInputBlur($event)\"\n (mousedown)=\"handleInputClick($event)\"\n (keydown)=\"handleTriggerKeydown($event)\"\n (input)=\"handleNativeInput($event)\"\n [attr.aria-invalid]=\"ngControl?.control?.invalid || null\"\n [attr.aria-describedby]=\"mode() === 'range' ? rangeStatusElementId() : null\"\n [attr.aria-label]=\"dialogAriaLabelKey() | translate: dialogAriaLabelParams()\"\n />\n\n @if (mode() === 'range') {\n <span\n class=\"sr-only\"\n [id]=\"rangeStatusElementId()\"\n >{{ rangePendingStatusText() }}</span\n >\n }\n\n @if (showClear() && inputDate) {\n <button\n type=\"button\"\n class=\"absolute flex h-[35px] w-6 items-center justify-center text-grayscale-60 transition-colors hover:text-grayscale-90\"\n [class.right-9]=\"showIcon()\"\n [class.right-0]=\"!showIcon()\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_clear' | translate\"\n (click)=\"clearValue($event)\"\n >\n <i\n class=\"fas fa-times text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n\n @if (showIcon()) {\n <button\n #iconButton\n type=\"button\"\n class=\"absolute right-0 flex h-[35px] w-9 items-center justify-center border-l border-solid transition-colors\"\n [class.border-grayscale-20]=\"disabled()\"\n [class.text-grayscale-30]=\"disabled()\"\n [class.cursor-not-allowed]=\"disabled()\"\n [class.border-grayscale-30]=\"!disabled() && !isFocused()\"\n [class.border-primary]=\"isFocused() && !disabled()\"\n [class.text-grayscale-90]=\"!disabled()\"\n [class.hover:bg-grayscale-10]=\"!disabled()\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_open' | translate\"\n (click)=\"toggle()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n >\n <i\n [class]=\"resolvedIcon()\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n</div>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayPositions]=\"positions\"\n (backdropClick)=\"handleBackdropClick($event)\"\n (overlayKeydown)=\"handleOverlayKeydown($event)\"\n (detach)=\"isOpen.set(false)\"\n>\n <div\n #popupPanel\n class=\"z-50 w-72 rounded-medium border border-solid border-grayscale-30 bg-grayscale-0 shadow-md\"\n role=\"dialog\"\n cdkTrapFocus\n [id]=\"popupId()\"\n [attr.aria-label]=\"dialogAriaLabelKey() | translate: dialogAriaLabelParams()\"\n >\n @if (showCalendar()) {\n @if (pickerView() === 'calendar') {\n <!-- Cabe\u00E7alho de navega\u00E7\u00E3o mensal -->\n <div class=\"flex items-center justify-between border-b border-solid border-grayscale-30 px-3 py-2\">\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"prevDisabled()\"\n [attr.aria-disabled]=\"prevDisabled() ? 'true' : null\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_prev_month'\n | translate: { month: prevMonthTarget() }\n \"\n (click)=\"navigatePrev()\"\n >\n <i\n class=\"fas fa-chevron-left text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n\n <button\n type=\"button\"\n class=\"flex items-center gap-1 rounded-small px-2 py-1 text-sm font-medium text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_select_month_year' | translate\"\n (click)=\"switchToMonths()\"\n >\n {{ currentMonthKey() | translate }}&nbsp;{{ currentYear() }}\n <i\n class=\"fas fa-chevron-down text-[10px]\"\n aria-hidden=\"true\"\n ></i>\n </button>\n\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"nextDisabled()\"\n [attr.aria-disabled]=\"nextDisabled() ? 'true' : null\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_next_month'\n | translate: { month: nextMonthTarget() }\n \"\n (click)=\"navigateNext()\"\n >\n <i\n class=\"fas fa-chevron-right text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n\n <!-- Cabe\u00E7alhos dos dias da semana -->\n <div\n class=\"grid grid-cols-7 px-3 pt-2\"\n role=\"row\"\n >\n @for (dayKey of orderedWeekDayKeys(); track dayKey) {\n <div\n class=\"flex h-8 items-center justify-center text-xs font-medium text-grayscale-60\"\n role=\"columnheader\"\n [attr.aria-label]=\"dayKey | translate\"\n >\n {{ dayKey | translate }}\n </div>\n }\n </div>\n\n <!-- Grade do calend\u00E1rio -->\n <div\n class=\"grid grid-cols-7 px-3 pb-2\"\n role=\"grid\"\n [attr.aria-label]=\"\n calendarGridAriaLabelKey()\n | translate: { month: (currentMonthKey() | translate), year: currentYear() }\n \"\n [attr.aria-multiselectable]=\"mode() === 'range' ? true : null\"\n (keydown)=\"handleCalendarGridKeydown($event)\"\n >\n @for (week of calendarWeeks(); track $index) {\n <div\n role=\"row\"\n class=\"contents\"\n >\n @for (day of week; track day.date.toISOString()) {\n <button\n type=\"button\"\n role=\"gridcell\"\n class=\"flex h-8 w-8 items-center justify-center rounded-[50%] text-sm font-normal transition-colors\"\n [class.invisible]=\"!showOtherMonths() && !day.isCurrentMonth\"\n [attr.aria-label]=\"formatDayAriaLabel(day.date, day)\"\n [attr.aria-selected]=\"\n day.isSelected || day.isRangeStart || day.isRangeEnd || day.isInRange || null\n \"\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\n [attr.aria-disabled]=\"day.isDisabled ? 'true' : null\"\n [attr.aria-hidden]=\"!showOtherMonths() && !day.isCurrentMonth ? 'true' : null\"\n [attr.data-focus]=\"\n day.isSelected || day.isRangeStart || day.isRangeEnd\n ? 'selected'\n : day.isToday\n ? 'today'\n : null\n \"\n [disabled]=\"day.isDisabled\"\n [ngClass]=\"{\n 'bg-primary font-semibold text-grayscale-0':\n day.isSelected || day.isRangeStart || day.isRangeEnd,\n 'bg-grayscale-10 hover:bg-grayscale-20':\n day.isInRange && !day.isRangeStart && !day.isRangeEnd,\n 'text-grayscale-90 hover:bg-grayscale-10':\n !day.isSelected &&\n !day.isRangeStart &&\n !day.isRangeEnd &&\n !day.isDisabled &&\n day.isCurrentMonth,\n 'text-grayscale-60 hover:bg-grayscale-10':\n !day.isSelected &&\n !day.isRangeStart &&\n !day.isRangeEnd &&\n !day.isDisabled &&\n !day.isCurrentMonth,\n 'ring-2 ring-inset ring-primary':\n day.isToday && !day.isSelected && !day.isRangeStart && !day.isRangeEnd,\n 'cursor-not-allowed text-grayscale-30': day.isDisabled,\n }\"\n (mouseenter)=\"onDayHover(day.date)\"\n (mouseleave)=\"onDayHover(null)\"\n (focus)=\"onDayHover(day.date)\"\n (click)=\"selectDate(day)\"\n >\n {{ day.dayOfMonth }}\n </button>\n }\n </div>\n }\n </div>\n }\n\n @if (pickerView() === 'years') {\n <!-- Cabe\u00E7alho de navega\u00E7\u00E3o por d\u00E9cada -->\n <div\n data-nav-header\n class=\"flex items-center justify-between border-b border-solid border-grayscale-30 px-3 py-2\"\n >\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"prevDisabled()\"\n [attr.aria-disabled]=\"prevDisabled() ? 'true' : null\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_prev_decade' | translate: prevDecadeRange()\n \"\n (click)=\"navigatePrev()\"\n >\n <i\n class=\"fas fa-chevron-left text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n\n <span class=\"text-sm font-medium text-grayscale-90\"\n >{{ currentDecadeStart() }} \u2013 {{ currentDecadeStart() + 11 }}</span\n >\n\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"nextDisabled()\"\n [attr.aria-disabled]=\"nextDisabled() ? 'true' : null\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_next_decade' | translate: nextDecadeRange()\n \"\n (click)=\"navigateNext()\"\n >\n <i\n class=\"fas fa-chevron-right text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n\n <!-- Grade de anos -->\n <div\n class=\"grid grid-cols-3 gap-2 px-3 py-3\"\n role=\"grid\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_select_year' | translate\"\n >\n @for (row of yearsGrid(); track $index) {\n <div\n role=\"row\"\n class=\"contents\"\n >\n @for (year of row; track year) {\n <button\n type=\"button\"\n role=\"gridcell\"\n class=\"flex h-9 items-center justify-center rounded-small text-sm font-normal transition-colors\"\n [attr.aria-selected]=\"isYearSelected(year) || null\"\n [attr.aria-disabled]=\"isYearDisabled(year) ? 'true' : null\"\n [attr.aria-current]=\"isCurrentYear(year) ? 'date' : null\"\n [attr.data-focus]=\"\n isYearSelected(year) ? 'selected' : isCurrentYear(year) ? 'today' : null\n \"\n [disabled]=\"isYearDisabled(year)\"\n [ngClass]=\"{\n 'bg-primary font-semibold text-grayscale-0': isYearSelected(year),\n 'ring-2 ring-inset ring-primary':\n isCurrentYear(year) && !isYearSelected(year) && !isYearDisabled(year),\n 'text-grayscale-90 hover:bg-grayscale-10':\n !isYearSelected(year) && !isYearDisabled(year),\n 'cursor-not-allowed text-grayscale-30': isYearDisabled(year),\n }\"\n (click)=\"selectYear(year)\"\n >\n {{ year }}\n </button>\n }\n </div>\n }\n </div>\n }\n\n @if (pickerView() === 'months') {\n <!-- Cabe\u00E7alho de navega\u00E7\u00E3o anual -->\n <div\n data-nav-header\n class=\"flex items-center justify-between border-b border-solid border-grayscale-30 px-3 py-2\"\n >\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"prevDisabled()\"\n [attr.aria-disabled]=\"prevDisabled() ? 'true' : null\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_prev_year' | translate: { year: prevYearTarget() }\n \"\n (click)=\"navigatePrev()\"\n >\n <i\n class=\"fas fa-chevron-left text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n\n <span class=\"text-sm font-medium text-grayscale-90\">{{ currentYear() }}</span>\n\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"nextDisabled()\"\n [attr.aria-disabled]=\"nextDisabled() ? 'true' : null\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_next_year' | translate: { year: nextYearTarget() }\n \"\n (click)=\"navigateNext()\"\n >\n <i\n class=\"fas fa-chevron-right text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n\n <!-- Grade de meses -->\n <div\n class=\"grid grid-cols-3 gap-2 px-3 py-3\"\n role=\"grid\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_select_month' | translate\"\n >\n @for (row of monthsGrid(); track $index) {\n <div\n role=\"row\"\n class=\"contents\"\n >\n @for (month of row; track month.index) {\n <button\n type=\"button\"\n role=\"gridcell\"\n class=\"flex h-9 items-center justify-center rounded-small text-sm font-normal transition-colors\"\n [attr.aria-selected]=\"isMonthSelected(month.index) || null\"\n [attr.aria-disabled]=\"isMonthDisabled(month.index) ? 'true' : null\"\n [attr.data-focus]=\"isMonthSelected(month.index) ? 'selected' : null\"\n [disabled]=\"isMonthDisabled(month.index)\"\n [ngClass]=\"{\n 'bg-primary font-semibold text-grayscale-0': isMonthSelected(month.index),\n 'text-grayscale-90 hover:bg-grayscale-10':\n !isMonthSelected(month.index) && !isMonthDisabled(month.index),\n 'cursor-not-allowed text-grayscale-30': isMonthDisabled(month.index),\n }\"\n (click)=\"selectMonth(month.index)\"\n >\n {{ month.key | translate }}\n </button>\n }\n </div>\n }\n </div>\n\n @if (mode() !== 'month') {\n <div class=\"border-t border-solid border-grayscale-30 px-3 py-2\">\n <button\n type=\"button\"\n class=\"flex items-center gap-2 rounded-small px-2 py-1 text-sm text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n (click)=\"backToCalendar()\"\n >\n <i\n class=\"fas fa-arrow-left\"\n aria-hidden=\"true\"\n ></i>\n {{ 'platform.angular_components.datepicker_back_to_calendar' | translate }}\n </button>\n </div>\n }\n }\n }\n\n <!-- Time picker -->\n @if (showTimePicker()) {\n <div\n class=\"flex items-center justify-center gap-3 px-4 py-3\"\n [class.border-t]=\"showCalendar()\"\n [class.border-solid]=\"showCalendar()\"\n [class.border-grayscale-30]=\"showCalendar()\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_select_time' | translate\"\n >\n <!-- Horas -->\n <div class=\"flex flex-col items-center gap-1\">\n <button\n #increaseHourButton\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_increment_hour'\n | translate: { time: nextHourTarget() }\n \"\n (click)=\"incrementHours()\"\n >\n <i\n class=\"fas fa-chevron-up text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n <input\n type=\"text\"\n inputmode=\"numeric\"\n [attr.maxlength]=\"timeInputMaxLength\"\n class=\"h-9 w-12 rounded-small border border-solid border-grayscale-30 bg-grayscale-5 text-center text-base font-medium text-grayscale-90 outline-none focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-[var(--s-focus-ring-color,#0090ff)]\"\n [value]=\"padTime(displayHours())\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_hour' | translate\"\n aria-live=\"polite\"\n pattern=\"[0-9]+\"\n (keydown)=\"handleHoursKeydown($event)\"\n (change)=\"handleHoursInput($event)\"\n />\n <button\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_decrement_hour'\n | translate: { time: prevHourTarget() }\n \"\n (click)=\"decrementHours()\"\n >\n <i\n class=\"fas fa-chevron-down text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n\n <span\n class=\"text-xl font-bold text-grayscale-60\"\n aria-hidden=\"true\"\n >:</span\n >\n\n <!-- Minutos -->\n <div class=\"flex flex-col items-center gap-1\">\n <button\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_increment_minute'\n | translate: { time: nextMinuteTarget() }\n \"\n (click)=\"incrementMinutes()\"\n >\n <i\n class=\"fas fa-chevron-up text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n <input\n type=\"text\"\n inputmode=\"numeric\"\n [attr.maxlength]=\"timeInputMaxLength\"\n class=\"h-9 w-12 rounded-small border border-solid border-grayscale-30 bg-grayscale-5 text-center text-base font-medium text-grayscale-90 outline-none focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-[var(--s-focus-ring-color,#0090ff)]\"\n [value]=\"padTime(minutes())\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_minute' | translate\"\n aria-live=\"polite\"\n pattern=\"[0-9]+\"\n (keydown)=\"handleMinutesKeydown($event)\"\n (change)=\"handleMinutesInput($event)\"\n />\n <button\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_decrement_minute'\n | translate: { time: prevMinuteTarget() }\n \"\n (click)=\"decrementMinutes()\"\n >\n <i\n class=\"fas fa-chevron-down text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n\n @if (showSeconds()) {\n <span\n class=\"text-xl font-bold text-grayscale-60\"\n aria-hidden=\"true\"\n >:</span\n >\n\n <!-- Segundos -->\n <div class=\"flex flex-col items-center gap-1\">\n <button\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_increment_second'\n | translate: { time: nextSecondTarget() }\n \"\n (click)=\"incrementSeconds()\"\n >\n <i\n class=\"fas fa-chevron-up text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n <input\n type=\"text\"\n inputmode=\"numeric\"\n [attr.maxlength]=\"timeInputMaxLength\"\n class=\"h-9 w-12 rounded-small border border-solid border-grayscale-30 bg-grayscale-5 text-center text-base font-medium text-grayscale-90 outline-none focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-[var(--s-focus-ring-color,#0090ff)]\"\n [value]=\"padTime(seconds())\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_second' | translate\"\n aria-live=\"polite\"\n pattern=\"[0-9]+\"\n (keydown)=\"handleSecondsKeydown($event)\"\n (change)=\"handleSecondsInput($event)\"\n />\n <button\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_decrement_second'\n | translate: { time: prevSecondTarget() }\n \"\n (click)=\"decrementSeconds()\"\n >\n <i\n class=\"fas fa-chevron-down text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n }\n\n @if (is12HourFormat()) {\n <!-- Seletor AM/PM -->\n <button\n type=\"button\"\n class=\"flex h-9 w-12 items-center justify-center rounded-small border border-solid border-grayscale-30 bg-grayscale-5 text-base font-medium text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_toggle_meridiem'\n | translate: { meridiem: nextMeridiemTarget() }\n \"\n aria-live=\"polite\"\n (click)=\"toggleAmPm()\"\n >\n {{ amPm() }}\n </button>\n }\n </div>\n }\n\n <!-- Rodap\u00E9 de a\u00E7\u00F5es -->\n @if (showButtonBar() || mode() === 'datetime' || mode() === 'time') {\n <div class=\"flex items-center justify-between border-t border-solid border-grayscale-30 px-3 py-2\">\n @if (showButtonBar()) {\n <div>\n @if (mode() === 'date' || mode() === 'datetime' || mode() === 'range') {\n <button\n type=\"button\"\n class=\"rounded-small px-2 py-1 text-sm text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n (click)=\"selectToday()\"\n >\n {{ 'platform.angular_components.datepicker_today' | translate }}\n </button>\n }\n </div>\n\n <div class=\"flex gap-2\">\n <button\n type=\"button\"\n class=\"rounded-small px-2 py-1 text-sm text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n (click)=\"clearValue($event)\"\n >\n {{ 'platform.angular_components.datepicker_clear' | translate }}\n </button>\n\n @if (mode() === 'datetime' || mode() === 'time') {\n <button\n type=\"button\"\n class=\"rounded-small bg-primary px-3 py-1 text-sm font-medium text-grayscale-0 transition-colors hover:opacity-90\"\n (click)=\"confirm()\"\n >\n {{ 'platform.angular_components.datepicker_confirm' | translate }}\n </button>\n }\n </div>\n } @else {\n <div></div>\n <div>\n @if (mode() === 'datetime' || mode() === 'time') {\n <button\n type=\"button\"\n class=\"rounded-small bg-primary px-3 py-1 text-sm font-medium text-grayscale-0 transition-colors hover:opacity-90\"\n (click)=\"confirm()\"\n >\n {{ 'platform.angular_components.datepicker_confirm' | translate }}\n </button>\n }\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n\n", styles: [":host{display:block;position:relative;width:100%}:host.ng-invalid.ng-dirty input{border-color:#c13018}:host.ng-invalid.ng-dirty input:focus{border-color:#c13018;outline-color:#c13018}:host.ng-invalid.ng-dirty button[type=button]{border-color:#c13018}:host.no-icon button[type=button]{display:none}:host.no-icon input{padding-right:.75rem}button[type=button]:focus-visible{outline:2px solid #428bca;outline-offset:1px;border-radius:inherit}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }, { kind: "directive", type: CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }] });
1967
2351
  }
1968
2352
  __decorate([
1969
2353
  numericKeysOnly()
@@ -1997,7 +2381,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
1997
2381
  useExisting: DatepickerComponent,
1998
2382
  multi: true,
1999
2383
  },
2000
- ], template: "<div\n cdkOverlayOrigin\n #trigger=\"cdkOverlayOrigin\"\n class=\"relative flex w-full items-center\"\n role=\"combobox\"\n aria-haspopup=\"grid\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-controls]=\"popupId()\"\n>\n <input\n #triggerInput\n class=\"h-[35px] w-full rounded-small border border-solid border-grayscale-30 pl-3 text-sm outline-none transition-colors focus:border-primary\"\n [class.pr-10]=\"showIcon() && !showClear()\"\n [class.pr-16]=\"showIcon() && showClear()\"\n [class.pr-6]=\"!showIcon() && showClear()\"\n [class.bg-grayscale-0]=\"!disabled()\"\n [class.text-grayscale-90]=\"!disabled()\"\n [class.border-grayscale-20]=\"disabled()\"\n [class.bg-grayscale-5]=\"disabled()\"\n [class.text-grayscale-30]=\"disabled()\"\n [class.cursor-not-allowed]=\"disabled()\"\n [id]=\"inputId()\"\n [name]=\"name() ?? inputId()\"\n type=\"text\"\n [placeholder]=\"placeholder() ?? (placeholderKey() | translate)\"\n [disabled]=\"disabled()\"\n [readonly]=\"\n readonlyInput() ||\n mode() === 'range' ||\n mode() === 'year' ||\n isMultipleMode() ||\n (isSegmentModeCandidate() && isTouchDevice())\n \"\n [tabIndex]=\"tabindex() ?? null\"\n [autofocus]=\"autofocus()\"\n [(ngModel)]=\"inputDate\"\n (ngModelChange)=\"handleInputChange($event)\"\n (focus)=\"handleInputFocus($event)\"\n (blur)=\"handleInputBlur($event)\"\n (mousedown)=\"handleInputClick($event)\"\n (keydown)=\"handleTriggerKeydown($event)\"\n (input)=\"handleNativeInput($event)\"\n [attr.aria-invalid]=\"ngControl?.control?.invalid || null\"\n />\n\n @if (showClear() && inputDate) {\n <button\n type=\"button\"\n class=\"absolute flex h-[35px] w-6 items-center justify-center text-grayscale-60 transition-colors hover:text-grayscale-90\"\n [class.right-9]=\"showIcon()\"\n [class.right-0]=\"!showIcon()\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_clear' | translate\"\n (click)=\"clearValue($event)\"\n >\n <i\n class=\"fas fa-times text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n\n @if (showIcon()) {\n <button\n #iconButton\n type=\"button\"\n class=\"absolute right-0 flex h-[35px] w-9 items-center justify-center border-l border-solid transition-colors\"\n [class.border-grayscale-20]=\"disabled()\"\n [class.text-grayscale-30]=\"disabled()\"\n [class.cursor-not-allowed]=\"disabled()\"\n [class.border-grayscale-30]=\"!disabled() && !isFocused()\"\n [class.border-primary]=\"isFocused() && !disabled()\"\n [class.text-grayscale-90]=\"!disabled()\"\n [class.hover:bg-grayscale-10]=\"!disabled()\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_open' | translate\"\n (click)=\"toggle()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n >\n <i\n [class]=\"resolvedIcon()\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n</div>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayPositions]=\"positions\"\n (backdropClick)=\"handleBackdropClick($event)\"\n (overlayKeydown)=\"handleOverlayKeydown($event)\"\n (detach)=\"isOpen.set(false)\"\n>\n <div\n #popupPanel\n class=\"z-50 w-72 rounded-medium border border-solid border-grayscale-30 bg-grayscale-0 shadow-md\"\n role=\"dialog\"\n cdkTrapFocus\n [id]=\"popupId()\"\n [attr.aria-label]=\"dialogAriaLabelKey() | translate\"\n >\n @if (showCalendar()) {\n @if (pickerView() === 'calendar') {\n <!-- Cabe\u00E7alho de navega\u00E7\u00E3o mensal -->\n <div class=\"flex items-center justify-between border-b border-solid border-grayscale-30 px-3 py-2\">\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"prevDisabled()\"\n [attr.aria-disabled]=\"prevDisabled() ? 'true' : null\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_prev_month' | translate\"\n (click)=\"navigatePrev()\"\n >\n <i\n class=\"fas fa-chevron-left text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n\n <button\n type=\"button\"\n class=\"flex items-center gap-1 rounded-small px-2 py-1 text-sm font-medium text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_select_month_year' | translate\"\n (click)=\"switchToMonths()\"\n >\n {{ currentMonthKey() | translate }}&nbsp;{{ currentYear() }}\n <i\n class=\"fas fa-chevron-down text-[10px]\"\n aria-hidden=\"true\"\n ></i>\n </button>\n\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"nextDisabled()\"\n [attr.aria-disabled]=\"nextDisabled() ? 'true' : null\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_next_month' | translate\"\n (click)=\"navigateNext()\"\n >\n <i\n class=\"fas fa-chevron-right text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n\n <!-- Cabe\u00E7alhos dos dias da semana -->\n <div\n class=\"grid grid-cols-7 px-3 pt-2\"\n role=\"row\"\n >\n @for (dayKey of orderedWeekDayKeys(); track dayKey) {\n <div\n class=\"flex h-8 items-center justify-center text-xs font-medium text-grayscale-60\"\n role=\"columnheader\"\n [attr.aria-label]=\"dayKey | translate\"\n >\n {{ dayKey | translate }}\n </div>\n }\n </div>\n\n <!-- Grade do calend\u00E1rio -->\n <div\n class=\"grid grid-cols-7 px-3 pb-2\"\n role=\"grid\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_calendar_label'\n | translate: { month: (currentMonthKey() | translate), year: currentYear() }\n \"\n (keydown)=\"handleCalendarGridKeydown($event)\"\n >\n @for (week of calendarWeeks(); track $index) {\n <div\n role=\"row\"\n class=\"contents\"\n >\n @for (day of week; track day.date.toISOString()) {\n <button\n type=\"button\"\n role=\"gridcell\"\n class=\"flex h-8 w-8 items-center justify-center rounded-[50%] text-sm font-normal transition-colors\"\n [class.invisible]=\"!showOtherMonths() && !day.isCurrentMonth\"\n [attr.aria-label]=\"formatDayAriaLabel(day.date)\"\n [attr.aria-selected]=\"day.isSelected || day.isRangeStart || day.isRangeEnd || null\"\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\n [attr.aria-disabled]=\"day.isDisabled ? 'true' : null\"\n [attr.aria-hidden]=\"!showOtherMonths() && !day.isCurrentMonth ? 'true' : null\"\n [attr.data-focus]=\"\n day.isSelected || day.isRangeStart || day.isRangeEnd\n ? 'selected'\n : day.isToday\n ? 'today'\n : null\n \"\n [disabled]=\"day.isDisabled\"\n [ngClass]=\"{\n 'bg-primary font-semibold text-grayscale-0':\n day.isSelected || day.isRangeStart || day.isRangeEnd,\n 'bg-grayscale-10 hover:bg-grayscale-20':\n day.isInRange && !day.isRangeStart && !day.isRangeEnd,\n 'text-grayscale-90 hover:bg-grayscale-10':\n !day.isSelected &&\n !day.isRangeStart &&\n !day.isRangeEnd &&\n !day.isDisabled &&\n day.isCurrentMonth,\n 'text-grayscale-60 hover:bg-grayscale-10':\n !day.isSelected &&\n !day.isRangeStart &&\n !day.isRangeEnd &&\n !day.isDisabled &&\n !day.isCurrentMonth,\n 'ring-2 ring-inset ring-primary':\n day.isToday && !day.isSelected && !day.isRangeStart && !day.isRangeEnd,\n 'cursor-not-allowed text-grayscale-30': day.isDisabled,\n }\"\n (mouseenter)=\"onDayHover(day.date)\"\n (mouseleave)=\"onDayHover(null)\"\n (click)=\"selectDate(day)\"\n >\n {{ day.dayOfMonth }}\n </button>\n }\n </div>\n }\n </div>\n }\n\n @if (pickerView() === 'years') {\n <!-- Cabe\u00E7alho de navega\u00E7\u00E3o por d\u00E9cada -->\n <div class=\"flex items-center justify-between border-b border-solid border-grayscale-30 px-3 py-2\">\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"prevDisabled()\"\n [attr.aria-disabled]=\"prevDisabled() ? 'true' : null\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_prev_decade' | translate\"\n (click)=\"navigatePrev()\"\n >\n <i\n class=\"fas fa-chevron-left text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n\n <span class=\"text-sm font-medium text-grayscale-90\"\n >{{ currentDecadeStart() }} \u2013 {{ currentDecadeStart() + 11 }}</span\n >\n\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"nextDisabled()\"\n [attr.aria-disabled]=\"nextDisabled() ? 'true' : null\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_next_decade' | translate\"\n (click)=\"navigateNext()\"\n >\n <i\n class=\"fas fa-chevron-right text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n\n <!-- Grade de anos -->\n <div\n class=\"grid grid-cols-3 gap-2 px-3 py-3\"\n role=\"grid\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_select_year' | translate\"\n >\n @for (row of yearsGrid(); track $index) {\n @for (year of row; track year) {\n <button\n type=\"button\"\n role=\"gridcell\"\n class=\"flex h-9 items-center justify-center rounded-small text-sm font-normal transition-colors\"\n [attr.aria-selected]=\"isYearSelected(year) || null\"\n [attr.aria-disabled]=\"isYearDisabled(year) ? 'true' : null\"\n [attr.aria-current]=\"isCurrentYear(year) ? 'date' : null\"\n [attr.data-focus]=\"\n isYearSelected(year) ? 'selected' : isCurrentYear(year) ? 'today' : null\n \"\n [disabled]=\"isYearDisabled(year)\"\n [ngClass]=\"{\n 'bg-primary font-semibold text-grayscale-0': isYearSelected(year),\n 'ring-2 ring-inset ring-primary':\n isCurrentYear(year) && !isYearSelected(year) && !isYearDisabled(year),\n 'text-grayscale-90 hover:bg-grayscale-10':\n !isYearSelected(year) && !isYearDisabled(year),\n 'cursor-not-allowed text-grayscale-30': isYearDisabled(year),\n }\"\n (click)=\"selectYear(year)\"\n >\n {{ year }}\n </button>\n }\n }\n </div>\n }\n\n @if (pickerView() === 'months') {\n <!-- Cabe\u00E7alho de navega\u00E7\u00E3o anual -->\n <div class=\"flex items-center justify-between border-b border-solid border-grayscale-30 px-3 py-2\">\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"prevDisabled()\"\n [attr.aria-disabled]=\"prevDisabled() ? 'true' : null\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_prev_year' | translate\"\n (click)=\"navigatePrev()\"\n >\n <i\n class=\"fas fa-chevron-left text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n\n <span class=\"text-sm font-medium text-grayscale-90\">{{ currentYear() }}</span>\n\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"nextDisabled()\"\n [attr.aria-disabled]=\"nextDisabled() ? 'true' : null\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_next_year' | translate\"\n (click)=\"navigateNext()\"\n >\n <i\n class=\"fas fa-chevron-right text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n\n <!-- Grade de meses -->\n <div\n class=\"grid grid-cols-3 gap-2 px-3 py-3\"\n role=\"grid\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_select_month' | translate\"\n >\n @for (row of monthsGrid(); track $index) {\n @for (month of row; track month.index) {\n <button\n type=\"button\"\n role=\"gridcell\"\n class=\"flex h-9 items-center justify-center rounded-small text-sm font-normal transition-colors\"\n [attr.aria-selected]=\"isMonthSelected(month.index) || null\"\n [attr.aria-disabled]=\"isMonthDisabled(month.index) ? 'true' : null\"\n [attr.data-focus]=\"isMonthSelected(month.index) ? 'selected' : null\"\n [disabled]=\"isMonthDisabled(month.index)\"\n [ngClass]=\"{\n 'bg-primary font-semibold text-grayscale-0': isMonthSelected(month.index),\n 'text-grayscale-90 hover:bg-grayscale-10':\n !isMonthSelected(month.index) && !isMonthDisabled(month.index),\n 'cursor-not-allowed text-grayscale-30': isMonthDisabled(month.index),\n }\"\n (click)=\"selectMonth(month.index)\"\n >\n {{ month.key | translate }}\n </button>\n }\n }\n </div>\n\n @if (mode() !== 'month') {\n <div class=\"border-t border-solid border-grayscale-30 px-3 py-2\">\n <button\n type=\"button\"\n class=\"flex items-center gap-2 rounded-small px-2 py-1 text-sm text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n (click)=\"backToCalendar()\"\n >\n <i\n class=\"fas fa-arrow-left\"\n aria-hidden=\"true\"\n ></i>\n {{ 'platform.angular_components.datepicker_back_to_calendar' | translate }}\n </button>\n </div>\n }\n }\n }\n\n <!-- Time picker -->\n @if (showTimePicker()) {\n <div\n class=\"flex items-center justify-center gap-3 px-4 py-3\"\n [class.border-t]=\"showCalendar()\"\n [class.border-solid]=\"showCalendar()\"\n [class.border-grayscale-30]=\"showCalendar()\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_select_time' | translate\"\n >\n <!-- Horas -->\n <div class=\"flex flex-col items-center gap-1\">\n <button\n #increaseHourButton\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_increment_hour' | translate\"\n (click)=\"incrementHours()\"\n >\n <i\n class=\"fas fa-chevron-up text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n <input\n type=\"text\"\n inputmode=\"numeric\"\n [attr.maxlength]=\"timeInputMaxLength\"\n class=\"h-9 w-12 rounded-small border border-solid border-grayscale-30 bg-grayscale-5 text-center text-base font-medium text-grayscale-90 outline-none focus:border-primary focus:outline-1 focus:outline-primary\"\n [value]=\"padTime(displayHours())\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_hour' | translate\"\n aria-live=\"polite\"\n pattern=\"[0-9]+\"\n (keydown)=\"handleHoursKeydown($event)\"\n (change)=\"handleHoursInput($event)\"\n />\n <button\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_decrement_hour' | translate\"\n (click)=\"decrementHours()\"\n >\n <i\n class=\"fas fa-chevron-down text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n\n <span\n class=\"text-xl font-bold text-grayscale-60\"\n aria-hidden=\"true\"\n >:</span\n >\n\n <!-- Minutos -->\n <div class=\"flex flex-col items-center gap-1\">\n <button\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_increment_minute' | translate\"\n (click)=\"incrementMinutes()\"\n >\n <i\n class=\"fas fa-chevron-up text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n <input\n type=\"text\"\n inputmode=\"numeric\"\n [attr.maxlength]=\"timeInputMaxLength\"\n class=\"h-9 w-12 rounded-small border border-solid border-grayscale-30 bg-grayscale-5 text-center text-base font-medium text-grayscale-90 outline-none focus:border-primary focus:outline-1 focus:outline-primary\"\n [value]=\"padTime(minutes())\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_minute' | translate\"\n aria-live=\"polite\"\n pattern=\"[0-9]+\"\n (keydown)=\"handleMinutesKeydown($event)\"\n (change)=\"handleMinutesInput($event)\"\n />\n <button\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_decrement_minute' | translate\"\n (click)=\"decrementMinutes()\"\n >\n <i\n class=\"fas fa-chevron-down text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n\n @if (showSeconds()) {\n <span\n class=\"text-xl font-bold text-grayscale-60\"\n aria-hidden=\"true\"\n >:</span\n >\n\n <!-- Segundos -->\n <div class=\"flex flex-col items-center gap-1\">\n <button\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_increment_second' | translate\"\n (click)=\"incrementSeconds()\"\n >\n <i\n class=\"fas fa-chevron-up text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n <input\n type=\"text\"\n inputmode=\"numeric\"\n [attr.maxlength]=\"timeInputMaxLength\"\n class=\"h-9 w-12 rounded-small border border-solid border-grayscale-30 bg-grayscale-5 text-center text-base font-medium text-grayscale-90 outline-none focus:border-primary focus:outline-1 focus:outline-primary\"\n [value]=\"padTime(seconds())\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_second' | translate\"\n aria-live=\"polite\"\n pattern=\"[0-9]+\"\n (keydown)=\"handleSecondsKeydown($event)\"\n (change)=\"handleSecondsInput($event)\"\n />\n <button\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_decrement_second' | translate\"\n (click)=\"decrementSeconds()\"\n >\n <i\n class=\"fas fa-chevron-down text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n }\n\n @if (is12HourFormat()) {\n <!-- Seletor AM/PM -->\n <button\n type=\"button\"\n class=\"flex h-9 w-12 items-center justify-center rounded-small border border-solid border-grayscale-30 bg-grayscale-5 text-base font-medium text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_toggle_meridiem' | translate\"\n aria-live=\"polite\"\n (click)=\"toggleAmPm()\"\n >\n {{ amPm() }}\n </button>\n }\n </div>\n }\n\n <!-- Rodap\u00E9 de a\u00E7\u00F5es -->\n @if (showButtonBar() || mode() === 'datetime' || mode() === 'time') {\n <div class=\"flex items-center justify-between border-t border-solid border-grayscale-30 px-3 py-2\">\n @if (showButtonBar()) {\n <div>\n @if (mode() === 'date' || mode() === 'datetime' || mode() === 'range') {\n <button\n type=\"button\"\n class=\"rounded-small px-2 py-1 text-sm text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n (click)=\"selectToday()\"\n >\n {{ 'platform.angular_components.datepicker_today' | translate }}\n </button>\n }\n </div>\n\n <div class=\"flex gap-2\">\n <button\n type=\"button\"\n class=\"rounded-small px-2 py-1 text-sm text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n (click)=\"clearValue($event)\"\n >\n {{ 'platform.angular_components.datepicker_clear' | translate }}\n </button>\n\n @if (mode() === 'datetime' || mode() === 'time') {\n <button\n type=\"button\"\n class=\"rounded-small bg-primary px-3 py-1 text-sm font-medium text-grayscale-0 transition-colors hover:opacity-90\"\n (click)=\"confirm()\"\n >\n {{ 'platform.angular_components.datepicker_confirm' | translate }}\n </button>\n }\n </div>\n } @else {\n <div></div>\n <div>\n @if (mode() === 'datetime' || mode() === 'time') {\n <button\n type=\"button\"\n class=\"rounded-small bg-primary px-3 py-1 text-sm font-medium text-grayscale-0 transition-colors hover:opacity-90\"\n (click)=\"confirm()\"\n >\n {{ 'platform.angular_components.datepicker_confirm' | translate }}\n </button>\n }\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n\n", styles: [":host{display:block;position:relative;width:100%}:host.ng-invalid.ng-dirty input{border-color:#c13018}:host.ng-invalid.ng-dirty input:focus{border-color:#c13018;outline-color:#c13018}:host.ng-invalid.ng-dirty button[type=button]{border-color:#c13018}:host.no-icon button[type=button]{display:none}:host.no-icon input{padding-right:.75rem}button[type=button]:focus-visible{outline:2px solid #428bca;outline-offset:1px;border-radius:inherit}\n"] }]
2384
+ ], template: "<div\n cdkOverlayOrigin\n #trigger=\"cdkOverlayOrigin\"\n class=\"relative flex w-full items-center\"\n role=\"combobox\"\n aria-haspopup=\"grid\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-controls]=\"popupId()\"\n>\n <input\n #triggerInput\n class=\"h-[35px] w-full rounded-small border border-solid border-grayscale-30 pl-3 text-sm outline-none transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-[var(--s-focus-ring-color,#0090ff)]\"\n [class.pr-10]=\"showIcon() && !showClear()\"\n [class.pr-16]=\"showIcon() && showClear()\"\n [class.pr-6]=\"!showIcon() && showClear()\"\n [class.bg-grayscale-0]=\"!disabled()\"\n [class.text-grayscale-90]=\"!disabled()\"\n [class.border-grayscale-20]=\"disabled()\"\n [class.bg-grayscale-5]=\"disabled()\"\n [class.text-grayscale-30]=\"disabled()\"\n [class.cursor-not-allowed]=\"disabled()\"\n [id]=\"inputId()\"\n [name]=\"name() ?? inputId()\"\n type=\"text\"\n [placeholder]=\"placeholder() ?? (placeholderKey() | translate)\"\n [disabled]=\"disabled()\"\n [readonly]=\"\n readonlyInput() ||\n mode() === 'range' ||\n mode() === 'year' ||\n isMultipleMode() ||\n (isSegmentModeCandidate() && isTouchDevice())\n \"\n [tabIndex]=\"tabindex() ?? null\"\n [autofocus]=\"autofocus()\"\n [(ngModel)]=\"inputDate\"\n (ngModelChange)=\"handleInputChange($event)\"\n (focus)=\"handleInputFocus($event)\"\n (blur)=\"handleInputBlur($event)\"\n (mousedown)=\"handleInputClick($event)\"\n (keydown)=\"handleTriggerKeydown($event)\"\n (input)=\"handleNativeInput($event)\"\n [attr.aria-invalid]=\"ngControl?.control?.invalid || null\"\n [attr.aria-describedby]=\"mode() === 'range' ? rangeStatusElementId() : null\"\n [attr.aria-label]=\"dialogAriaLabelKey() | translate: dialogAriaLabelParams()\"\n />\n\n @if (mode() === 'range') {\n <span\n class=\"sr-only\"\n [id]=\"rangeStatusElementId()\"\n >{{ rangePendingStatusText() }}</span\n >\n }\n\n @if (showClear() && inputDate) {\n <button\n type=\"button\"\n class=\"absolute flex h-[35px] w-6 items-center justify-center text-grayscale-60 transition-colors hover:text-grayscale-90\"\n [class.right-9]=\"showIcon()\"\n [class.right-0]=\"!showIcon()\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_clear' | translate\"\n (click)=\"clearValue($event)\"\n >\n <i\n class=\"fas fa-times text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n\n @if (showIcon()) {\n <button\n #iconButton\n type=\"button\"\n class=\"absolute right-0 flex h-[35px] w-9 items-center justify-center border-l border-solid transition-colors\"\n [class.border-grayscale-20]=\"disabled()\"\n [class.text-grayscale-30]=\"disabled()\"\n [class.cursor-not-allowed]=\"disabled()\"\n [class.border-grayscale-30]=\"!disabled() && !isFocused()\"\n [class.border-primary]=\"isFocused() && !disabled()\"\n [class.text-grayscale-90]=\"!disabled()\"\n [class.hover:bg-grayscale-10]=\"!disabled()\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_open' | translate\"\n (click)=\"toggle()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n >\n <i\n [class]=\"resolvedIcon()\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n</div>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayPositions]=\"positions\"\n (backdropClick)=\"handleBackdropClick($event)\"\n (overlayKeydown)=\"handleOverlayKeydown($event)\"\n (detach)=\"isOpen.set(false)\"\n>\n <div\n #popupPanel\n class=\"z-50 w-72 rounded-medium border border-solid border-grayscale-30 bg-grayscale-0 shadow-md\"\n role=\"dialog\"\n cdkTrapFocus\n [id]=\"popupId()\"\n [attr.aria-label]=\"dialogAriaLabelKey() | translate: dialogAriaLabelParams()\"\n >\n @if (showCalendar()) {\n @if (pickerView() === 'calendar') {\n <!-- Cabe\u00E7alho de navega\u00E7\u00E3o mensal -->\n <div class=\"flex items-center justify-between border-b border-solid border-grayscale-30 px-3 py-2\">\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"prevDisabled()\"\n [attr.aria-disabled]=\"prevDisabled() ? 'true' : null\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_prev_month'\n | translate: { month: prevMonthTarget() }\n \"\n (click)=\"navigatePrev()\"\n >\n <i\n class=\"fas fa-chevron-left text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n\n <button\n type=\"button\"\n class=\"flex items-center gap-1 rounded-small px-2 py-1 text-sm font-medium text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_select_month_year' | translate\"\n (click)=\"switchToMonths()\"\n >\n {{ currentMonthKey() | translate }}&nbsp;{{ currentYear() }}\n <i\n class=\"fas fa-chevron-down text-[10px]\"\n aria-hidden=\"true\"\n ></i>\n </button>\n\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"nextDisabled()\"\n [attr.aria-disabled]=\"nextDisabled() ? 'true' : null\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_next_month'\n | translate: { month: nextMonthTarget() }\n \"\n (click)=\"navigateNext()\"\n >\n <i\n class=\"fas fa-chevron-right text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n\n <!-- Cabe\u00E7alhos dos dias da semana -->\n <div\n class=\"grid grid-cols-7 px-3 pt-2\"\n role=\"row\"\n >\n @for (dayKey of orderedWeekDayKeys(); track dayKey) {\n <div\n class=\"flex h-8 items-center justify-center text-xs font-medium text-grayscale-60\"\n role=\"columnheader\"\n [attr.aria-label]=\"dayKey | translate\"\n >\n {{ dayKey | translate }}\n </div>\n }\n </div>\n\n <!-- Grade do calend\u00E1rio -->\n <div\n class=\"grid grid-cols-7 px-3 pb-2\"\n role=\"grid\"\n [attr.aria-label]=\"\n calendarGridAriaLabelKey()\n | translate: { month: (currentMonthKey() | translate), year: currentYear() }\n \"\n [attr.aria-multiselectable]=\"mode() === 'range' ? true : null\"\n (keydown)=\"handleCalendarGridKeydown($event)\"\n >\n @for (week of calendarWeeks(); track $index) {\n <div\n role=\"row\"\n class=\"contents\"\n >\n @for (day of week; track day.date.toISOString()) {\n <button\n type=\"button\"\n role=\"gridcell\"\n class=\"flex h-8 w-8 items-center justify-center rounded-[50%] text-sm font-normal transition-colors\"\n [class.invisible]=\"!showOtherMonths() && !day.isCurrentMonth\"\n [attr.aria-label]=\"formatDayAriaLabel(day.date, day)\"\n [attr.aria-selected]=\"\n day.isSelected || day.isRangeStart || day.isRangeEnd || day.isInRange || null\n \"\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\n [attr.aria-disabled]=\"day.isDisabled ? 'true' : null\"\n [attr.aria-hidden]=\"!showOtherMonths() && !day.isCurrentMonth ? 'true' : null\"\n [attr.data-focus]=\"\n day.isSelected || day.isRangeStart || day.isRangeEnd\n ? 'selected'\n : day.isToday\n ? 'today'\n : null\n \"\n [disabled]=\"day.isDisabled\"\n [ngClass]=\"{\n 'bg-primary font-semibold text-grayscale-0':\n day.isSelected || day.isRangeStart || day.isRangeEnd,\n 'bg-grayscale-10 hover:bg-grayscale-20':\n day.isInRange && !day.isRangeStart && !day.isRangeEnd,\n 'text-grayscale-90 hover:bg-grayscale-10':\n !day.isSelected &&\n !day.isRangeStart &&\n !day.isRangeEnd &&\n !day.isDisabled &&\n day.isCurrentMonth,\n 'text-grayscale-60 hover:bg-grayscale-10':\n !day.isSelected &&\n !day.isRangeStart &&\n !day.isRangeEnd &&\n !day.isDisabled &&\n !day.isCurrentMonth,\n 'ring-2 ring-inset ring-primary':\n day.isToday && !day.isSelected && !day.isRangeStart && !day.isRangeEnd,\n 'cursor-not-allowed text-grayscale-30': day.isDisabled,\n }\"\n (mouseenter)=\"onDayHover(day.date)\"\n (mouseleave)=\"onDayHover(null)\"\n (focus)=\"onDayHover(day.date)\"\n (click)=\"selectDate(day)\"\n >\n {{ day.dayOfMonth }}\n </button>\n }\n </div>\n }\n </div>\n }\n\n @if (pickerView() === 'years') {\n <!-- Cabe\u00E7alho de navega\u00E7\u00E3o por d\u00E9cada -->\n <div\n data-nav-header\n class=\"flex items-center justify-between border-b border-solid border-grayscale-30 px-3 py-2\"\n >\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"prevDisabled()\"\n [attr.aria-disabled]=\"prevDisabled() ? 'true' : null\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_prev_decade' | translate: prevDecadeRange()\n \"\n (click)=\"navigatePrev()\"\n >\n <i\n class=\"fas fa-chevron-left text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n\n <span class=\"text-sm font-medium text-grayscale-90\"\n >{{ currentDecadeStart() }} \u2013 {{ currentDecadeStart() + 11 }}</span\n >\n\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"nextDisabled()\"\n [attr.aria-disabled]=\"nextDisabled() ? 'true' : null\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_next_decade' | translate: nextDecadeRange()\n \"\n (click)=\"navigateNext()\"\n >\n <i\n class=\"fas fa-chevron-right text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n\n <!-- Grade de anos -->\n <div\n class=\"grid grid-cols-3 gap-2 px-3 py-3\"\n role=\"grid\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_select_year' | translate\"\n >\n @for (row of yearsGrid(); track $index) {\n <div\n role=\"row\"\n class=\"contents\"\n >\n @for (year of row; track year) {\n <button\n type=\"button\"\n role=\"gridcell\"\n class=\"flex h-9 items-center justify-center rounded-small text-sm font-normal transition-colors\"\n [attr.aria-selected]=\"isYearSelected(year) || null\"\n [attr.aria-disabled]=\"isYearDisabled(year) ? 'true' : null\"\n [attr.aria-current]=\"isCurrentYear(year) ? 'date' : null\"\n [attr.data-focus]=\"\n isYearSelected(year) ? 'selected' : isCurrentYear(year) ? 'today' : null\n \"\n [disabled]=\"isYearDisabled(year)\"\n [ngClass]=\"{\n 'bg-primary font-semibold text-grayscale-0': isYearSelected(year),\n 'ring-2 ring-inset ring-primary':\n isCurrentYear(year) && !isYearSelected(year) && !isYearDisabled(year),\n 'text-grayscale-90 hover:bg-grayscale-10':\n !isYearSelected(year) && !isYearDisabled(year),\n 'cursor-not-allowed text-grayscale-30': isYearDisabled(year),\n }\"\n (click)=\"selectYear(year)\"\n >\n {{ year }}\n </button>\n }\n </div>\n }\n </div>\n }\n\n @if (pickerView() === 'months') {\n <!-- Cabe\u00E7alho de navega\u00E7\u00E3o anual -->\n <div\n data-nav-header\n class=\"flex items-center justify-between border-b border-solid border-grayscale-30 px-3 py-2\"\n >\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"prevDisabled()\"\n [attr.aria-disabled]=\"prevDisabled() ? 'true' : null\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_prev_year' | translate: { year: prevYearTarget() }\n \"\n (click)=\"navigatePrev()\"\n >\n <i\n class=\"fas fa-chevron-left text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n\n <span class=\"text-sm font-medium text-grayscale-90\">{{ currentYear() }}</span>\n\n <button\n type=\"button\"\n class=\"flex h-7 w-7 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10 disabled:cursor-not-allowed disabled:text-grayscale-30\"\n [disabled]=\"nextDisabled()\"\n [attr.aria-disabled]=\"nextDisabled() ? 'true' : null\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_next_year' | translate: { year: nextYearTarget() }\n \"\n (click)=\"navigateNext()\"\n >\n <i\n class=\"fas fa-chevron-right text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n\n <!-- Grade de meses -->\n <div\n class=\"grid grid-cols-3 gap-2 px-3 py-3\"\n role=\"grid\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_select_month' | translate\"\n >\n @for (row of monthsGrid(); track $index) {\n <div\n role=\"row\"\n class=\"contents\"\n >\n @for (month of row; track month.index) {\n <button\n type=\"button\"\n role=\"gridcell\"\n class=\"flex h-9 items-center justify-center rounded-small text-sm font-normal transition-colors\"\n [attr.aria-selected]=\"isMonthSelected(month.index) || null\"\n [attr.aria-disabled]=\"isMonthDisabled(month.index) ? 'true' : null\"\n [attr.data-focus]=\"isMonthSelected(month.index) ? 'selected' : null\"\n [disabled]=\"isMonthDisabled(month.index)\"\n [ngClass]=\"{\n 'bg-primary font-semibold text-grayscale-0': isMonthSelected(month.index),\n 'text-grayscale-90 hover:bg-grayscale-10':\n !isMonthSelected(month.index) && !isMonthDisabled(month.index),\n 'cursor-not-allowed text-grayscale-30': isMonthDisabled(month.index),\n }\"\n (click)=\"selectMonth(month.index)\"\n >\n {{ month.key | translate }}\n </button>\n }\n </div>\n }\n </div>\n\n @if (mode() !== 'month') {\n <div class=\"border-t border-solid border-grayscale-30 px-3 py-2\">\n <button\n type=\"button\"\n class=\"flex items-center gap-2 rounded-small px-2 py-1 text-sm text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n (click)=\"backToCalendar()\"\n >\n <i\n class=\"fas fa-arrow-left\"\n aria-hidden=\"true\"\n ></i>\n {{ 'platform.angular_components.datepicker_back_to_calendar' | translate }}\n </button>\n </div>\n }\n }\n }\n\n <!-- Time picker -->\n @if (showTimePicker()) {\n <div\n class=\"flex items-center justify-center gap-3 px-4 py-3\"\n [class.border-t]=\"showCalendar()\"\n [class.border-solid]=\"showCalendar()\"\n [class.border-grayscale-30]=\"showCalendar()\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_select_time' | translate\"\n >\n <!-- Horas -->\n <div class=\"flex flex-col items-center gap-1\">\n <button\n #increaseHourButton\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_increment_hour'\n | translate: { time: nextHourTarget() }\n \"\n (click)=\"incrementHours()\"\n >\n <i\n class=\"fas fa-chevron-up text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n <input\n type=\"text\"\n inputmode=\"numeric\"\n [attr.maxlength]=\"timeInputMaxLength\"\n class=\"h-9 w-12 rounded-small border border-solid border-grayscale-30 bg-grayscale-5 text-center text-base font-medium text-grayscale-90 outline-none focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-[var(--s-focus-ring-color,#0090ff)]\"\n [value]=\"padTime(displayHours())\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_hour' | translate\"\n aria-live=\"polite\"\n pattern=\"[0-9]+\"\n (keydown)=\"handleHoursKeydown($event)\"\n (change)=\"handleHoursInput($event)\"\n />\n <button\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_decrement_hour'\n | translate: { time: prevHourTarget() }\n \"\n (click)=\"decrementHours()\"\n >\n <i\n class=\"fas fa-chevron-down text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n\n <span\n class=\"text-xl font-bold text-grayscale-60\"\n aria-hidden=\"true\"\n >:</span\n >\n\n <!-- Minutos -->\n <div class=\"flex flex-col items-center gap-1\">\n <button\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_increment_minute'\n | translate: { time: nextMinuteTarget() }\n \"\n (click)=\"incrementMinutes()\"\n >\n <i\n class=\"fas fa-chevron-up text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n <input\n type=\"text\"\n inputmode=\"numeric\"\n [attr.maxlength]=\"timeInputMaxLength\"\n class=\"h-9 w-12 rounded-small border border-solid border-grayscale-30 bg-grayscale-5 text-center text-base font-medium text-grayscale-90 outline-none focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-[var(--s-focus-ring-color,#0090ff)]\"\n [value]=\"padTime(minutes())\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_minute' | translate\"\n aria-live=\"polite\"\n pattern=\"[0-9]+\"\n (keydown)=\"handleMinutesKeydown($event)\"\n (change)=\"handleMinutesInput($event)\"\n />\n <button\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_decrement_minute'\n | translate: { time: prevMinuteTarget() }\n \"\n (click)=\"decrementMinutes()\"\n >\n <i\n class=\"fas fa-chevron-down text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n\n @if (showSeconds()) {\n <span\n class=\"text-xl font-bold text-grayscale-60\"\n aria-hidden=\"true\"\n >:</span\n >\n\n <!-- Segundos -->\n <div class=\"flex flex-col items-center gap-1\">\n <button\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_increment_second'\n | translate: { time: nextSecondTarget() }\n \"\n (click)=\"incrementSeconds()\"\n >\n <i\n class=\"fas fa-chevron-up text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n <input\n type=\"text\"\n inputmode=\"numeric\"\n [attr.maxlength]=\"timeInputMaxLength\"\n class=\"h-9 w-12 rounded-small border border-solid border-grayscale-30 bg-grayscale-5 text-center text-base font-medium text-grayscale-90 outline-none focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-[var(--s-focus-ring-color,#0090ff)]\"\n [value]=\"padTime(seconds())\"\n [attr.aria-label]=\"'platform.angular_components.datepicker_second' | translate\"\n aria-live=\"polite\"\n pattern=\"[0-9]+\"\n (keydown)=\"handleSecondsKeydown($event)\"\n (change)=\"handleSecondsInput($event)\"\n />\n <button\n type=\"button\"\n class=\"flex h-6 w-6 items-center justify-center rounded-small text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_decrement_second'\n | translate: { time: prevSecondTarget() }\n \"\n (click)=\"decrementSeconds()\"\n >\n <i\n class=\"fas fa-chevron-down text-xs\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n }\n\n @if (is12HourFormat()) {\n <!-- Seletor AM/PM -->\n <button\n type=\"button\"\n class=\"flex h-9 w-12 items-center justify-center rounded-small border border-solid border-grayscale-30 bg-grayscale-5 text-base font-medium text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n [attr.aria-label]=\"\n 'platform.angular_components.datepicker_toggle_meridiem'\n | translate: { meridiem: nextMeridiemTarget() }\n \"\n aria-live=\"polite\"\n (click)=\"toggleAmPm()\"\n >\n {{ amPm() }}\n </button>\n }\n </div>\n }\n\n <!-- Rodap\u00E9 de a\u00E7\u00F5es -->\n @if (showButtonBar() || mode() === 'datetime' || mode() === 'time') {\n <div class=\"flex items-center justify-between border-t border-solid border-grayscale-30 px-3 py-2\">\n @if (showButtonBar()) {\n <div>\n @if (mode() === 'date' || mode() === 'datetime' || mode() === 'range') {\n <button\n type=\"button\"\n class=\"rounded-small px-2 py-1 text-sm text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n (click)=\"selectToday()\"\n >\n {{ 'platform.angular_components.datepicker_today' | translate }}\n </button>\n }\n </div>\n\n <div class=\"flex gap-2\">\n <button\n type=\"button\"\n class=\"rounded-small px-2 py-1 text-sm text-grayscale-90 transition-colors hover:bg-grayscale-10\"\n (click)=\"clearValue($event)\"\n >\n {{ 'platform.angular_components.datepicker_clear' | translate }}\n </button>\n\n @if (mode() === 'datetime' || mode() === 'time') {\n <button\n type=\"button\"\n class=\"rounded-small bg-primary px-3 py-1 text-sm font-medium text-grayscale-0 transition-colors hover:opacity-90\"\n (click)=\"confirm()\"\n >\n {{ 'platform.angular_components.datepicker_confirm' | translate }}\n </button>\n }\n </div>\n } @else {\n <div></div>\n <div>\n @if (mode() === 'datetime' || mode() === 'time') {\n <button\n type=\"button\"\n class=\"rounded-small bg-primary px-3 py-1 text-sm font-medium text-grayscale-0 transition-colors hover:opacity-90\"\n (click)=\"confirm()\"\n >\n {{ 'platform.angular_components.datepicker_confirm' | translate }}\n </button>\n }\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n\n", styles: [":host{display:block;position:relative;width:100%}:host.ng-invalid.ng-dirty input{border-color:#c13018}:host.ng-invalid.ng-dirty input:focus{border-color:#c13018;outline-color:#c13018}:host.ng-invalid.ng-dirty button[type=button]{border-color:#c13018}:host.no-icon button[type=button]{display:none}:host.no-icon input{padding-right:.75rem}button[type=button]:focus-visible{outline:2px solid #428bca;outline-offset:1px;border-radius:inherit}\n"] }]
2001
2385
  }], ctorParameters: () => [], propDecorators: { handleHoursKeydown: [], handleMinutesKeydown: [], handleSecondsKeydown: [] } });
2002
2386
 
2003
2387
  /**