@seniorsistemas/angular-components 19.9.8 → 19.9.9
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.
- package/card/lib/card/card.component.d.ts +6 -2
- package/country-phone-picker/lib/country-phone-picker/country-phone-picker.component.d.ts +0 -1
- package/datepicker/README.md +6 -2
- package/datepicker/lib/datepicker/date-segment-input.d.ts +7 -1
- package/datepicker/lib/datepicker/datepicker.component.d.ts +137 -3
- package/dialog/lib/src/dialog/services/dialog.service.d.ts +2 -0
- package/esm2022/accordion/lib/accordion/components/accordion-panel/accordion-panel.component.mjs +3 -3
- package/esm2022/autocomplete/lib/autocomplete/autocomplete.component.mjs +8 -3
- package/esm2022/autocomplete/lib/autocomplete/components/autocomplete-chip/autocomplete-chip.component.mjs +4 -3
- package/esm2022/breadcrumb/lib/breadcrumb/breadcrumb.component.mjs +3 -3
- package/esm2022/breadcrumb/lib/dynamic-breadcrumb/dynamic-breadcrumb.component.mjs +4 -2
- package/esm2022/button/lib/button/button.component.mjs +3 -3
- package/esm2022/card/lib/card/card.component.mjs +13 -5
- package/esm2022/checkbox/lib/checkbox/checkbox.component.mjs +3 -3
- package/esm2022/checkbox-list/lib/checkbox-list/checkbox-list.component.mjs +3 -3
- package/esm2022/chips/lib/chips/chip-item/chip-item.component.mjs +3 -3
- package/esm2022/chips/lib/chips/chips/chips.component.mjs +3 -3
- package/esm2022/code-editor/lib/code-editor/infra/cores/codemirror-6/themes/sds-light/sds-light-style.mjs +3 -2
- package/esm2022/collapse-link/lib/collapse-link/collapse-link.component.mjs +3 -3
- package/esm2022/country-phone-picker/lib/country-phone-picker/country-phone-picker.component.mjs +14 -9
- package/esm2022/datepicker/lib/datepicker/date-segment-input.mjs +19 -2
- package/esm2022/datepicker/lib/datepicker/datepicker.component.mjs +405 -38
- package/esm2022/dialog/lib/src/dialog/dialog.component.mjs +3 -3
- package/esm2022/dialog/lib/src/dialog/services/dialog.service.mjs +13 -1
- package/esm2022/drawer/lib/drawer/drawer.component.mjs +3 -3
- package/esm2022/dynamic-form/dynamic-form/components/lookup/lookup.component.mjs +3 -3
- package/esm2022/dynamic-form/dynamic-form/form-field/fields/bignumber/bignumber-field.component.mjs +3 -3
- package/esm2022/dynamic-form/dynamic-form/form-field/fields/currency/currency-field.component.mjs +3 -3
- package/esm2022/dynamic-form/dynamic-form/form-field/fields/number/number-field.component.mjs +3 -3
- package/esm2022/dynamic-form/dynamic-form/form-field/fields/password/password-field.component.mjs +3 -3
- package/esm2022/dynamic-form/dynamic-form/form-field/fields/text/text-field.component.mjs +3 -3
- package/esm2022/editor/lib/editor/editor.component.mjs +3 -3
- package/esm2022/editor/lib/editor/toolbar-button/editor-toolbar-button.component.mjs +3 -3
- package/esm2022/fieldset/lib/fieldset/fieldset.component.mjs +3 -3
- package/esm2022/file-picker/lib/file-picker/file-picker.component.mjs +3 -3
- package/esm2022/gantt/lib/gantt/components/gantt/bar.mjs +2 -1
- package/esm2022/gantt/lib/gantt/gantt.component.mjs +3 -3
- package/esm2022/global-search/lib/global-search/global-search.component.mjs +16 -25
- package/esm2022/grid-menu/lib/grid-menu/components/grid-menu-item/grid-menu-item.component.mjs +3 -3
- package/esm2022/input-text/lib/input-text/input-text.directive.mjs +3 -3
- package/esm2022/lib/locale/fallback.mjs +40 -13
- package/esm2022/navigation-button/lib/navigation-button/navigation-button.component.mjs +3 -3
- package/esm2022/object-card/lib/object-card/object-card.component.mjs +3 -3
- package/esm2022/paginator/lib/paginator/paginator.component.mjs +3 -3
- package/esm2022/pin-code-field/lib/pin-code-field/pin-code-field.component.mjs +3 -3
- package/esm2022/radio-button/lib/radio-button/radio-button.component.mjs +4 -10
- package/esm2022/rating-scale/lib/rating-scale/rating-scale.component.mjs +3 -3
- package/esm2022/select/lib/select/select.component.mjs +3 -3
- package/esm2022/select-button/lib/select-button/components/select-button-item/select-button-item.component.mjs +3 -3
- package/esm2022/shared/lib/accessibility/datepicker-no-period-tab.directive.mjs +6 -6
- package/esm2022/side-sheet/lib/side-sheet/side-sheet.component.mjs +3 -3
- package/esm2022/slider/lib/slider/slider.component.mjs +67 -65
- package/esm2022/slider/lib/slider/slider.module.mjs +2 -2
- package/esm2022/split-button/lib/split-button/split-button.component.mjs +3 -3
- package/esm2022/star-rating/star-rating/star-rating.component.mjs +3 -3
- package/esm2022/stepper/lib/stepper/stepper.component.mjs +3 -3
- package/esm2022/switch/lib/switch/switch.component.mjs +5 -19
- package/esm2022/tabs/lib/tabs/tabs.component.mjs +3 -3
- package/esm2022/text-area/lib/text-area/text-area.component.mjs +3 -3
- package/esm2022/thumbnail/lib/thumbnail/thumbnail.component.mjs +10 -3
- package/esm2022/thumbnails/lib/thumbnails/components/thumbnail-item/thumbnail-item.component.mjs +3 -3
- package/esm2022/tiered-menu/lib/tiered-menu/components/tiered-menu-item/tiered-menu-item.component.mjs +3 -3
- package/esm2022/tiered-menu/lib/tiered-menu/services/tiered-menu.global.service.mjs +4 -3
- package/esm2022/tile/lib/tile/tile.component.mjs +3 -3
- package/esm2022/tree/lib/tree/components/tree-node-item/tree-node-item.component.mjs +20 -3
- package/esm2022/workspace-switch/lib/workspace-switch/workspace-switch.component.mjs +3 -3
- package/fesm2022/seniorsistemas-angular-components-accordion.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-accordion.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-autocomplete.mjs +10 -5
- package/fesm2022/seniorsistemas-angular-components-autocomplete.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-breadcrumb.mjs +5 -3
- package/fesm2022/seniorsistemas-angular-components-breadcrumb.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-button.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-button.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-card.mjs +12 -4
- package/fesm2022/seniorsistemas-angular-components-card.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-checkbox-list.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-checkbox-list.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-checkbox.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-checkbox.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-chips.mjs +4 -4
- package/fesm2022/seniorsistemas-angular-components-chips.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-code-editor.mjs +2 -1
- package/fesm2022/seniorsistemas-angular-components-code-editor.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-collapse-link.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-collapse-link.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-country-phone-picker.mjs +13 -8
- package/fesm2022/seniorsistemas-angular-components-country-phone-picker.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-datepicker.mjs +422 -38
- package/fesm2022/seniorsistemas-angular-components-datepicker.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-dialog.mjs +14 -2
- package/fesm2022/seniorsistemas-angular-components-dialog.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-drawer.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-drawer.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-dynamic-form.mjs +12 -12
- package/fesm2022/seniorsistemas-angular-components-dynamic-form.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-editor.mjs +4 -4
- package/fesm2022/seniorsistemas-angular-components-editor.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-fieldset.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-fieldset.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-file-picker.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-file-picker.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-gantt.mjs +3 -2
- package/fesm2022/seniorsistemas-angular-components-gantt.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-global-search.mjs +14 -23
- package/fesm2022/seniorsistemas-angular-components-global-search.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-grid-menu.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-grid-menu.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-input-text.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-input-text.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-navigation-button.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-navigation-button.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-object-card.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-object-card.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-paginator.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-paginator.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-pin-code-field.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-pin-code-field.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-radio-button.mjs +3 -9
- package/fesm2022/seniorsistemas-angular-components-radio-button.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-rating-scale.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-rating-scale.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-select-button.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-select-button.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-select.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-select.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-shared.mjs +5 -5
- package/fesm2022/seniorsistemas-angular-components-shared.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-side-sheet.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-side-sheet.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-slider.mjs +67 -65
- package/fesm2022/seniorsistemas-angular-components-slider.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-split-button.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-split-button.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-star-rating.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-star-rating.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-stepper.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-stepper.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-switch.mjs +4 -18
- package/fesm2022/seniorsistemas-angular-components-switch.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-tabs.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-tabs.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-text-area.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-text-area.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-thumbnail.mjs +9 -2
- package/fesm2022/seniorsistemas-angular-components-thumbnail.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-thumbnails.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-thumbnails.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-tiered-menu.mjs +5 -4
- package/fesm2022/seniorsistemas-angular-components-tiered-menu.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-tile.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-tile.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-tree.mjs +20 -3
- package/fesm2022/seniorsistemas-angular-components-tree.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-workspace-switch.mjs +2 -2
- package/fesm2022/seniorsistemas-angular-components-workspace-switch.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components.mjs +39 -12
- package/fesm2022/seniorsistemas-angular-components.mjs.map +1 -1
- package/global-search/lib/global-search/global-search.component.d.ts +7 -3
- package/package.json +1 -1
- package/radio-button/lib/radio-button/radio-button.component.d.ts +0 -1
- package/slider/lib/slider/slider.component.d.ts +25 -7
- package/styles.css +5 -0
- package/switch/lib/switch/switch.component.d.ts +0 -2
- package/thumbnail/lib/thumbnail/thumbnail.component.d.ts +1 -0
- 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
|
-
/**
|
|
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
|
|
762
|
-
const h12 =
|
|
798
|
+
return hours24;
|
|
799
|
+
const h12 = hours24 % DatepickerComponent.HOURS_PER_MERIDIEM;
|
|
763
800
|
return h12 === 0 ? DatepickerComponent.HOURS_PER_MERIDIEM : h12;
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
|
|
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
|
-
|
|
784
|
-
|
|
785
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
1010
|
-
if (
|
|
1011
|
-
|
|
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
|
|
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
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
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(
|
|
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.
|
|
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
|
-
|
|
1454
|
-
this.
|
|
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
|
-
|
|
1470
|
-
this.
|
|
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
|
-
|
|
1819
|
-
|
|
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 }} {{ 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 }} {{ 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 }} {{ 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 }} {{ 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
|
/**
|