@shival99/z-ui 1.9.25 → 1.9.26

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.
@@ -2,11 +2,13 @@ import { DecimalPipe } from '@angular/common';
2
2
  import * as i0 from '@angular/core';
3
3
  import { Pipe, input, output, viewChild, computed, signal, inject, Injector, DestroyRef, effect, forwardRef, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
4
4
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
5
- import { NgControl, NgModel, NG_VALUE_ACCESSOR } from '@angular/forms';
5
+ import * as i1 from '@angular/forms';
6
+ import { NgControl, NgModel, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
6
7
  import { TranslatePipe } from '@ngx-translate/core';
7
8
  import { ZButtonComponent } from '@shival99/z-ui/components/z-button';
8
9
  import { ZIconComponent } from '@shival99/z-ui/components/z-icon';
9
10
  import { ZPopoverDirective } from '@shival99/z-ui/components/z-popover';
11
+ import { ZSelectComponent } from '@shival99/z-ui/components/z-select';
10
12
  import { ZTranslateService } from '@shival99/z-ui/services';
11
13
  import { zTransform, zUuid, zMergeClasses, zCreateEvent } from '@shival99/z-ui/utils';
12
14
  import { NgScrollbar } from 'ngx-scrollbar';
@@ -1015,6 +1017,11 @@ class ZCalendarComponent {
1015
1017
  period = signal('AM', ...(ngDevMode ? [{ debugName: "period" }] : []));
1016
1018
  inputDisplayValue = signal('', ...(ngDevMode ? [{ debugName: "inputDisplayValue" }] : []));
1017
1019
  activePresetKey = signal(null, ...(ngDevMode ? [{ debugName: "activePresetKey" }] : []));
1020
+ quickSelectOptions = computed(() => this.quickSelectPresets.map(preset => ({
1021
+ label: preset.label,
1022
+ value: preset.key,
1023
+ disabled: this._isQuickSelectPresetDisabled(preset),
1024
+ })), ...(ngDevMode ? [{ debugName: "quickSelectOptions" }] : []));
1018
1025
  uiState = signal({
1019
1026
  hasViewChanged: false,
1020
1027
  hasEndViewChanged: false,
@@ -2109,6 +2116,16 @@ class ZCalendarComponent {
2109
2116
  this.close();
2110
2117
  }
2111
2118
  }
2119
+ onQuickSelectKeyChange(key) {
2120
+ if (!key) {
2121
+ return;
2122
+ }
2123
+ const preset = this.quickSelectPresets.find(item => item.key === key);
2124
+ if (!preset || this._isQuickSelectPresetDisabled(preset)) {
2125
+ return;
2126
+ }
2127
+ this.onQuickSelect(preset);
2128
+ }
2112
2129
  onTodayClick() {
2113
2130
  const now = new Date();
2114
2131
  const today = getToday();
@@ -2619,6 +2636,26 @@ class ZCalendarComponent {
2619
2636
  }
2620
2637
  return 'custom';
2621
2638
  }
2639
+ _isQuickSelectPresetDisabled(preset) {
2640
+ const disabledDateFn = this.zDisabledDate();
2641
+ if (preset.key === 'custom' || !disabledDateFn) {
2642
+ return false;
2643
+ }
2644
+ const value = preset.getValue();
2645
+ if (!value) {
2646
+ return false;
2647
+ }
2648
+ if (value instanceof Date) {
2649
+ return disabledDateFn(value);
2650
+ }
2651
+ if (value.start && disabledDateFn(value.start)) {
2652
+ return true;
2653
+ }
2654
+ if (value.end && disabledDateFn(value.end)) {
2655
+ return true;
2656
+ }
2657
+ return false;
2658
+ }
2622
2659
  _applyValue() {
2623
2660
  const emitValue = this._getEmitValue();
2624
2661
  this._onChange(emitValue);
@@ -2991,14 +3028,16 @@ class ZCalendarComponent {
2991
3028
  multi: true,
2992
3029
  },
2993
3030
  TranslatePipe,
2994
- ], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["triggerEl"], descendants: true, isSignal: true }, { propertyName: "inputRef", first: true, predicate: ["inputEl"], descendants: true, isSignal: true }], exportAs: ["zCalendar"], ngImport: i0, template: "<div class=\"z-calendar-wrapper flex w-full flex-col gap-2\">\n @if (zLabel()) {\n <label [for]=\"pickerId\" class=\"text-xs leading-none font-medium\" [class]=\"zLabelClass()\">\n {{ zLabel() }}\n @if (zRequired()) {\n <span class=\"text-destructive! ml-0.5\">*</span>\n }\n </label>\n }\n\n <div class=\"relative\">\n <div\n #triggerEl\n z-popover\n [zPopoverContent]=\"calendarTpl\"\n zPosition=\"bottom-left\"\n zPopoverWidth=\"auto\"\n [zOffset]=\"6\"\n [zDisabled]=\"isDisabled() || zReadonly()\"\n [zManualClose]=\"showCancelButton()\"\n [zScrollClose]=\"zScrollClose()\"\n zTrigger=\"click\"\n zClass=\"border-0 shadow-none p-0\"\n (zHideStart)=\"onPopoverHide()\"\n (zShow)=\"onPopoverShow()\"\n (zControl)=\"onPopoverControl($event)\"\n [id]=\"pickerId\"\n [class]=\"triggerClasses()\"\n (keydown)=\"onTriggerKeydown($event)\">\n <z-icon\n [zType]=\"isRangeMode() ? 'lucideCalendarRange' : 'lucideCalendar'\"\n zSize=\"16\"\n class=\"text-muted-foreground shrink-0 cursor-pointer\"\n (click)=\"$event.stopPropagation(); toggle()\" />\n\n @if (isRangeMode()) {\n <input\n type=\"text\"\n data-range-type=\"start\"\n class=\"placeholder:text-muted-foreground w-0 min-w-0 flex-1 truncate bg-transparent text-center text-sm outline-none\"\n [placeholder]=\"'i18n_z_ui_calendar_start_date' | translate\"\n [value]=\"inputDisplayStart()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"zReadonly()\"\n (click)=\"isOpen() && $event.stopPropagation()\"\n (focus)=\"onInputFocus($event)\"\n (input)=\"onStartInputChange($event)\"\n (blur)=\"onInputBlur($event)\"\n (keydown.enter)=\"onStartInputEnter($event)\"\n (keydown.escape)=\"onStartInputEscape()\" />\n <span class=\"text-muted-foreground text-sm\">-</span>\n <input\n type=\"text\"\n data-range-type=\"end\"\n class=\"placeholder:text-muted-foreground w-0 min-w-0 flex-1 truncate bg-transparent text-center text-sm outline-none\"\n [placeholder]=\"'i18n_z_ui_calendar_end_date' | translate\"\n [value]=\"inputDisplayEnd()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"zReadonly()\"\n (click)=\"isOpen() && $event.stopPropagation()\"\n (focus)=\"onInputFocus($event)\"\n (input)=\"onEndInputChange($event)\"\n (blur)=\"onInputBlur($event)\"\n (keydown.enter)=\"onEndInputEnter($event)\"\n (keydown.escape)=\"onEndInputEscape()\" />\n } @else {\n <input\n #inputEl\n type=\"text\"\n class=\"placeholder:text-muted-foreground w-0 min-w-0 flex-1 truncate bg-transparent text-sm outline-none\"\n [placeholder]=\"effectivePlaceholder()\"\n [value]=\"inputDisplayValue()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"zReadonly()\"\n (click)=\"isOpen() && $event.stopPropagation()\"\n (focus)=\"onInputFocus($event)\"\n (input)=\"onInputChange($event)\"\n (blur)=\"onInputBlur($event)\"\n (keydown.enter)=\"onInputEnter($event)\"\n (keydown.escape)=\"onInputEscape()\" />\n }\n\n @if (zAllowClear() && !isDisabled() && !zReadonly()) {\n <button\n type=\"button\"\n tabindex=\"-1\"\n class=\"text-muted-foreground hover:text-foreground flex size-5 shrink-0 cursor-pointer items-center justify-center rounded-sm transition-all\"\n [class.opacity-0]=\"!hasValue()\"\n [class.pointer-events-none]=\"!hasValue()\"\n (click)=\"onClear($event)\">\n <z-icon zType=\"lucideX\" zSize=\"18\" />\n </button>\n }\n </div>\n </div>\n\n @if (hasError()) {\n <p class=\"text-destructive animate-in fade-in slide-in-from-top-1 m-0 text-xs duration-200\">\n {{ errorMessage() }}\n </p>\n }\n</div>\n\n<ng-template #calendarTpl>\n <div\n class=\"z-calendar-calendar bg-popover border-border flex max-h-[50dvh] max-w-[95vw] overflow-auto rounded-sm border shadow-lg min-[480px]:max-h-[55dvh] sm:max-h-none sm:max-w-none sm:flex-row sm:overflow-visible\"\n [class.flex-col]=\"!(zQuickSelect() && zMode() === 'range')\"\n [class.flex-row]=\"zQuickSelect() && zMode() === 'range'\"\n (keydown)=\"onCalendarKeydown($event)\">\n @if (zQuickSelect() && zMode() === 'range') {\n <div class=\"border-border flex shrink-0 flex-col gap-0 space-y-1 overflow-y-auto border-r p-2\">\n @for (preset of quickSelectPresets; track preset.key) {\n @let presetDisabled = preset | zIsPresetDisabled: zDisabledDate();\n <button\n type=\"button\"\n class=\"cursor-pointer rounded-sm px-3 py-1.5 text-left text-sm whitespace-nowrap transition-colors\"\n [class.hover:bg-muted]=\"activePresetKey() !== preset.key && !presetDisabled\"\n [class.bg-primary]=\"activePresetKey() === preset.key\"\n [class.text-primary-foreground]=\"activePresetKey() === preset.key\"\n [class.font-medium]=\"activePresetKey() === preset.key\"\n [class.opacity-40]=\"presetDisabled\"\n [class.cursor-not-allowed]=\"presetDisabled\"\n [disabled]=\"presetDisabled\"\n (click)=\"onQuickSelect(preset)\">\n {{ preset.label | translate }}\n </button>\n }\n </div>\n }\n <div\n class=\"flex flex-1 flex-col items-center overflow-auto py-2 sm:overflow-visible\"\n [class]=\"!isRangeMode() ? 'w-[17.5rem]' : ''\">\n @if (!isTimeMode()) {\n <div\n class=\"z-calendars-wrapper flex w-full flex-col items-center gap-3 sm:flex-row sm:items-stretch sm:justify-center sm:gap-0\">\n <!-- First Calendar -->\n <div class=\"z-calendar-section flex w-[17.5rem] shrink-0 flex-col\">\n @if (!isTimeMode()) {\n <!-- Header -->\n <div class=\"border-border flex w-full items-center justify-between gap-0.5 px-2\">\n <!-- Double left arrow (always visible) -->\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zWave]=\"false\"\n (click)=\"navigatePreviousFast()\">\n <z-icon zType=\"lucideChevronsLeft\" zSize=\"18\" />\n </button>\n\n <!-- Single left arrow (hidden in month/year view) -->\n @if (currentView() === 'day') {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zWave]=\"false\"\n (click)=\"navigatePrevious()\">\n <z-icon zType=\"lucideChevronLeft\" zSize=\"18\" />\n </button>\n }\n\n <!-- Header content -->\n <div class=\"flex flex-1 shrink-0 items-center justify-center gap-0\">\n @if (currentView() === 'day') {\n <!-- Day view: Month + Year -->\n @if (!isYearMode() && !isQuarterMode()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n (click)=\"setView('month')\">\n {{ currentMonthName() }}\n </button>\n }\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n [zDisabled]=\"isYearMode()\"\n (click)=\"setView('year')\">\n {{ currentYear() }}\n </button>\n } @else if (currentView() === 'month') {\n <!-- Month view: Only Year -->\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n (click)=\"setView('year')\">\n {{ currentYear() }}\n </button>\n } @else if (currentView() === 'year') {\n <!-- Year view: Year Range -->\n <span class=\"text-sm font-medium\">\n {{ yearRange()[0] }} - {{ yearRange()[yearRange().length - 1] }}\n </span>\n } @else if (currentView() === 'quarter') {\n <!-- Quarter view: Only Year -->\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n (click)=\"setView('year')\">\n {{ currentYear() }}\n </button>\n }\n </div>\n\n <!-- Single right arrow (hidden in month/year view) -->\n @if (currentView() === 'day') {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zDisabled]=\"!canNavigateStartNext()\"\n [zWave]=\"false\"\n (click)=\"navigateNext()\">\n <z-icon zType=\"lucideChevronRight\" zSize=\"18\" />\n </button>\n }\n\n <!-- Double right arrow (always visible) -->\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zDisabled]=\"!canNavigateStartNext()\"\n [zWave]=\"false\"\n (click)=\"navigateNextFast()\">\n <z-icon zType=\"lucideChevronsRight\" zSize=\"18\" />\n </button>\n </div>\n\n <!-- Body -->\n <div\n class=\"flex h-full w-full flex-col items-center justify-center p-2\"\n [class.min-h-[14rem]]=\"!isQuarterMode()\"\n [class.h-[14rem]]=\"\n !isYearMode() &&\n !isMonthMode() &&\n !isQuarterMode() &&\n (currentView() === 'month' || currentView() === 'year')\n \"\n [class.min-h-[6.25rem]]=\"isQuarterMode()\"\n [class.!min-h-auto]=\"isYearMode() || isMonthMode() || isQuarterMode()\"\n [class.!h-auto]=\"isYearMode() || isMonthMode() || isQuarterMode()\">\n @if (currentView() === 'day') {\n <div\n class=\"flex h-full w-full flex-1 flex-col gap-1\"\n [class.animate-calendar-enter]=\"uiState().hasViewChanged\">\n <!-- Weekday headers -->\n <div class=\"flex w-full flex-1 justify-center gap-1\">\n @for (weekday of weekdayNames(); track weekday) {\n <div\n class=\"text-muted-foreground flex h-[1.875rem] w-[2.0313rem] items-center justify-center text-xs font-medium\">\n {{ weekday }}\n </div>\n }\n </div>\n\n <!-- Date rows -->\n @for (week of calendarDays(); track $index) {\n <div class=\"flex w-full flex-1 justify-center gap-1\">\n @for (day of week; track day.date.getTime()) {\n <button\n type=\"button\"\n [class]=\"day | zDayClasses\"\n class=\"h-[1.875rem] !w-[2.0313rem] !text-sm\"\n [disabled]=\"day.isDisabled\"\n (click)=\"onDayClick(day)\"\n (mouseenter)=\"onDayHover(day)\"\n (mouseleave)=\"onDayLeave()\">\n {{ day.day }}\n </button>\n }\n </div>\n }\n </div>\n }\n @if (currentView() === 'month') {\n <div\n class=\"grid h-full w-full grid-cols-3 grid-rows-4 gap-2.5 gap-y-5!\"\n [class.animate-calendar-enter]=\"uiState().hasViewChanged\">\n @for (month of monthNames(); track month; let i = $index) {\n @let monthDisabled = i | zIsStartMonthDisabled: startMonthDisabledContext();\n <div class=\"flex flex-1 items-center justify-center\">\n <button\n type=\"button\"\n [class]=\"i | zMonthClasses: selectedMonthIndex() : todayMonthIndex()\"\n class=\"!h-7 !w-full !text-sm\"\n [disabled]=\"monthDisabled\"\n [class.opacity-30]=\"monthDisabled\"\n [class.cursor-not-allowed]=\"monthDisabled\"\n (click)=\"onMonthSelect(i)\">\n {{ month }}\n </button>\n </div>\n }\n </div>\n }\n\n @if (currentView() === 'year') {\n <div\n class=\"grid h-full w-full grid-cols-3 grid-rows-4 gap-2.5 gap-y-5!\"\n [class.animate-calendar-enter]=\"uiState().hasViewChanged\">\n @for (year of yearRange(); track year) {\n @let yearDisabled = year | zIsStartYearDisabled: startYearDisabledContext();\n <div class=\"flex flex-1 items-center justify-center\">\n <button\n type=\"button\"\n [class]=\"year | zYearClasses: selectedYear() : todayYear()\"\n class=\"!h-7 !w-full !text-sm\"\n [disabled]=\"yearDisabled\"\n [class.opacity-30]=\"yearDisabled\"\n [class.cursor-not-allowed]=\"yearDisabled\"\n (click)=\"onYearClick(year)\">\n {{ year }}\n </button>\n </div>\n }\n </div>\n }\n\n @if (currentView() === 'quarter') {\n <div\n class=\"grid h-full w-full grid-cols-2 grid-rows-2 gap-2 p-1\"\n [class.animate-calendar-enter]=\"uiState().hasViewChanged\">\n @for (quarter of quarterNames; track quarter; let i = $index) {\n <div class=\"flex flex-1 items-center justify-center\">\n <button\n type=\"button\"\n [class]=\"i | zQuarterClasses: selectedQuarterIndex() : todayQuarterIndex()\"\n class=\"!h-8 !w-full !text-sm\"\n (click)=\"onQuarterClick(i)\">\n {{ quarter }}\n </button>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Second Calendar (Range Mode Only) -->\n @if (isRangeMode()) {\n <!-- Divider -->\n <div class=\"border-border bg-border hidden self-stretch sm:block sm:w-px\"></div>\n <div class=\"border-border bg-border block h-px w-full sm:hidden\"></div>\n\n <div class=\"z-calendar-section flex w-[17.5rem] shrink-0 flex-col\">\n <!-- Header -->\n <div class=\"border-border flex w-full items-center justify-between gap-0.5 px-2\">\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zDisabled]=\"!canNavigateEndPrev()\"\n [zWave]=\"false\"\n (click)=\"navigateEndPreviousFast()\">\n <z-icon zType=\"lucideChevronsLeft\" zSize=\"18\" />\n </button>\n\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zDisabled]=\"!canNavigateEndPrev()\"\n [zWave]=\"false\"\n (click)=\"navigateEndPrevious()\">\n <z-icon zType=\"lucideChevronLeft\" zSize=\"18\" />\n </button>\n\n <div class=\"flex w-[7.5rem] shrink-0 items-center justify-center gap-0\">\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n (click)=\"setEndView('month')\">\n {{ endMonthName() }}\n </button>\n\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n (click)=\"setEndView('year')\">\n {{ endMonthYear() }}\n </button>\n </div>\n\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zWave]=\"false\"\n [zWave]=\"false\"\n (click)=\"navigateEndNext()\">\n <z-icon zType=\"lucideChevronRight\" zSize=\"18\" />\n </button>\n\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zWave]=\"false\"\n [zWave]=\"false\"\n (click)=\"navigateEndNextFast()\">\n <z-icon zType=\"lucideChevronsRight\" zSize=\"18\" />\n </button>\n </div>\n\n <!-- Body -->\n <div\n class=\"flex h-full min-h-[14rem] w-full flex-col items-center justify-center p-2\"\n [class.h-[14rem]]=\"endView() === 'month' || endView() === 'year'\">\n @if (endView() === 'day') {\n <div\n class=\"flex h-full w-full flex-1 flex-col gap-1\"\n [class.animate-calendar-enter]=\"uiState().hasEndViewChanged\">\n <!-- Weekday headers -->\n <div class=\"flex w-full flex-1 justify-center gap-1\">\n @for (weekday of weekdayNames(); track weekday) {\n <div\n class=\"text-muted-foreground flex h-[1.875rem] w-[2.0313rem] items-center justify-center text-xs font-medium\">\n {{ weekday }}\n </div>\n }\n </div>\n\n <!-- Date rows -->\n @for (week of calendarDaysEnd(); track $index) {\n <div class=\"flex w-full flex-1 justify-center gap-1\">\n @for (day of week; track day.date.getTime()) {\n <button\n type=\"button\"\n [class]=\"day | zDayClasses\"\n class=\"h-[1.875rem] !w-[2.0313rem] !text-sm\"\n [disabled]=\"day.isDisabled\"\n (click)=\"onDayClick(day)\"\n (mouseenter)=\"onDayHover(day)\"\n (mouseleave)=\"onDayLeave()\">\n {{ day.day }}\n </button>\n }\n </div>\n }\n </div>\n }\n @if (endView() === 'month') {\n <div\n class=\"grid h-full w-full grid-cols-3 grid-rows-4 gap-2.5 gap-y-5!\"\n [class.animate-calendar-enter]=\"uiState().hasEndViewChanged\">\n @for (month of monthNames(); track month; let i = $index) {\n @let endMonthDisabled = i | zIsEndMonthDisabled: endMonthDisabledContext();\n <div class=\"flex flex-1 items-center justify-center\">\n <button\n type=\"button\"\n [class]=\"i | zMonthClasses: endMonth().getMonth() : -1\"\n class=\"!h-7 !w-full !text-sm\"\n [disabled]=\"endMonthDisabled\"\n [class.opacity-30]=\"endMonthDisabled\"\n [class.cursor-not-allowed]=\"endMonthDisabled\"\n (click)=\"onEndMonthClick(i)\">\n {{ month }}\n </button>\n </div>\n }\n </div>\n }\n\n @if (endView() === 'year') {\n <div\n class=\"grid h-full w-full grid-cols-3 grid-rows-4 gap-2.5 gap-y-5!\"\n [class.animate-calendar-enter]=\"uiState().hasEndViewChanged\">\n @for (year of endYearRange(); track year) {\n @let endYearDisabled = year | zIsEndYearDisabled: endYearDisabledContext();\n <div class=\"flex flex-1 items-center justify-center\">\n <button\n type=\"button\"\n [class]=\"year | zYearClasses: endMonth().getFullYear() : -1\"\n class=\"!h-7 !w-full !text-sm\"\n [disabled]=\"endYearDisabled\"\n [class.opacity-30]=\"endYearDisabled\"\n [class.cursor-not-allowed]=\"endYearDisabled\"\n (click)=\"onEndYearClick(year)\">\n {{ year }}\n </button>\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n\n <!-- Compact Time Picker Below Calendar (Single Date) -->\n @if (!isRangeMode() && zShowTime()) {\n <div class=\"border-border w-full border-t text-center\">\n <div\n class=\"hover:bg-muted my-1 inline-flex cursor-pointer items-center rounded-sm px-2 py-1 transition-colors\"\n z-popover\n [zPopoverContent]=\"timeDropdownTpl\"\n zPosition=\"bottom\"\n zPopoverWidth=\"auto\"\n [zOffset]=\"4\"\n zTrigger=\"click\"\n zClass=\"border-border shadow-md\"\n (zShow)=\"onTimeDropdownShow()\">\n <div class=\"flex items-center justify-center gap-1\">\n <!-- Hour -->\n @if (zShowHour()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedHour() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowHour() && zShowMinute()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Minute -->\n @if (zShowMinute()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedMinute() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowMinute() && zShowSecond()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Second -->\n @if (zShowSecond()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedSecond() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n <!-- AM/PM Toggle -->\n @if (zTimeFormat() === '12h') {\n <button\n type=\"button\"\n class=\"bg-primary/10 text-primary hover:bg-primary/20 active:bg-primary/30 ml-1 flex w-8 cursor-pointer items-center justify-center rounded-sm border-none px-2 py-1 text-xs font-semibold transition-colors\"\n (click)=\"togglePeriod(); $event.stopPropagation()\">\n {{ period() }}\n </button>\n }\n </div>\n </div>\n </div>\n }\n\n <!-- Compact Time Pickers Below Calendars (Range Mode) -->\n @if (isRangeMode() && zShowTime()) {\n <div class=\"border-border flex w-full flex-col border-t sm:flex-row\">\n <!-- Start Time -->\n <div class=\"flex w-full flex-col items-center justify-center gap-1\">\n <div\n class=\"hover:bg-muted my-1 inline-flex cursor-pointer items-center rounded-sm px-2 py-1 transition-colors\"\n z-popover\n [zPopoverContent]=\"timeDropdownTpl\"\n zPosition=\"bottom\"\n zPopoverWidth=\"auto\"\n [zOffset]=\"4\"\n zTrigger=\"click\"\n zClass=\"border-border shadow-md\"\n (zShow)=\"onTimeDropdownShow()\">\n <div class=\"flex items-center justify-center gap-1\">\n <!-- Hour -->\n @if (zShowHour()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedHour() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowHour() && zShowMinute()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Minute -->\n @if (zShowMinute()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedMinute() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowMinute() && zShowSecond()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Second -->\n @if (zShowSecond()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedSecond() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n <!-- AM/PM Toggle -->\n @if (zTimeFormat() === '12h') {\n <button\n type=\"button\"\n class=\"bg-primary/10 text-primary hover:bg-primary/20 active:bg-primary/30 ml-1 flex w-8 cursor-pointer items-center justify-center rounded-sm border-none px-2 py-1 text-xs font-semibold transition-colors\"\n (click)=\"togglePeriod(); $event.stopPropagation()\">\n {{ period() }}\n </button>\n }\n </div>\n </div>\n </div>\n\n <!-- Divider space -->\n <div class=\"border-border bg-border h-px self-stretch sm:block sm:h-full sm:w-px\"></div>\n\n <!-- End Time -->\n <div class=\"flex w-full flex-col items-center justify-center gap-1\">\n <div\n class=\"hover:bg-muted my-1 inline-flex cursor-pointer items-center rounded-sm px-2 py-1 transition-colors\"\n z-popover\n [zPopoverContent]=\"timeDropdownEndTpl\"\n zPosition=\"bottom\"\n zPopoverWidth=\"auto\"\n [zOffset]=\"4\"\n zTrigger=\"click\"\n zClass=\"border-border shadow-md\"\n (zShow)=\"onTimeDropdownEndShow()\">\n <div class=\"flex items-center justify-center gap-1\">\n <!-- Hour -->\n @if (zShowHour()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementHourEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedHourEnd() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementHourEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowHour() && zShowMinute()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Minute -->\n @if (zShowMinute()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementMinuteEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedMinuteEnd() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementMinuteEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowMinute() && zShowSecond()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Second -->\n @if (zShowSecond()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementSecondEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedSecondEnd() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementSecondEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n <!-- AM/PM Toggle -->\n @if (zTimeFormat() === '12h') {\n <button\n type=\"button\"\n class=\"bg-primary/10 text-primary hover:bg-primary/20 active:bg-primary/30 ml-1 flex w-8 cursor-pointer items-center justify-center rounded-sm border-none px-2 py-1 text-xs font-semibold transition-colors\"\n (click)=\"togglePeriodEnd(); $event.stopPropagation()\">\n {{ periodEnd() }}\n </button>\n }\n </div>\n </div>\n </div>\n </div>\n }\n } @else {\n <!-- Time Only Mode - Compact Display -->\n <div class=\"flex flex-col items-center gap-3 pb-2\">\n <div\n class=\"hover:bg-muted inline-flex cursor-pointer items-center rounded-sm px-3 py-2 transition-colors\"\n z-popover\n [zPopoverContent]=\"timeDropdownTpl\"\n zPosition=\"bottom\"\n zPopoverWidth=\"auto\"\n [zOffset]=\"4\"\n zTrigger=\"click\"\n zClass=\"border-border shadow-md\"\n (zShow)=\"onTimeDropdownShow()\">\n <div class=\"flex items-center justify-center gap-1.5\">\n <!-- Hour -->\n @if (zShowHour()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-9 cursor-pointer flex-col items-center gap-0 rounded-sm px-1.5 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"16\" />\n </button>\n <span class=\"text-foreground min-w-6 text-center text-base leading-tight font-medium select-none\">\n {{ formattedHour() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"16\" />\n </button>\n </div>\n }\n @if (zShowHour() && zShowMinute()) {\n <span class=\"text-muted-foreground text-base font-medium\">:</span>\n }\n <!-- Minute -->\n @if (zShowMinute()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-9 cursor-pointer flex-col items-center gap-0 rounded-sm px-1.5 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"16\" />\n </button>\n <span class=\"text-foreground min-w-6 text-center text-base leading-tight font-medium select-none\">\n {{ formattedMinute() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"16\" />\n </button>\n </div>\n }\n @if (zShowMinute() && zShowSecond()) {\n <span class=\"text-muted-foreground text-base font-medium\">:</span>\n }\n <!-- Second -->\n @if (zShowSecond()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-9 cursor-pointer flex-col items-center gap-0 rounded-sm px-1.5 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"16\" />\n </button>\n <span class=\"text-foreground min-w-6 text-center text-base leading-tight font-medium select-none\">\n {{ formattedSecond() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"16\" />\n </button>\n </div>\n }\n <!-- AM/PM Toggle -->\n @if (zTimeFormat() === '12h') {\n <button\n type=\"button\"\n class=\"bg-primary/10 text-primary hover:bg-primary/20 active:bg-primary/30 ml-1 flex w-10 cursor-pointer items-center justify-center rounded-sm border-none px-2.5 py-1.5 text-sm font-semibold transition-colors\"\n (click)=\"togglePeriod(); $event.stopPropagation()\">\n {{ period() }}\n </button>\n }\n </div>\n </div>\n </div>\n }\n\n @if (!(zQuickSelect() && zMode() === 'range' && !showOkButton() && !showCancelButton())) {\n <div class=\"border-border flex w-full items-center justify-between gap-2 border-t px-2 pt-2\">\n @if (!zQuickSelect() || zMode() !== 'range') {\n <button type=\"button\" z-button zType=\"secondary\" zSize=\"sm\" [zWave]=\"false\" (click)=\"onTodayClick()\">\n {{ todayButtonText() }}\n </button>\n } @else {\n <div></div>\n }\n\n @if (showOkButton() || showCancelButton()) {\n <div class=\"flex items-center gap-2\">\n @if (showCancelButton()) {\n <button type=\"button\" z-button zType=\"outline\" zSize=\"sm\" (click)=\"onCancelClick()\">\n {{ zCancelText() ?? ('i18n_z_ui_calendar_cancel' | translate) }}\n </button>\n }\n @if (showOkButton()) {\n <button type=\"button\" z-button zSize=\"sm\" [zDisabled]=\"!canApply()\" (click)=\"onOkClick()\">\n {{ zOkText() ?? ('i18n_z_ui_calendar_ok' | translate) }}\n </button>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n</ng-template>\n\n<ng-template #timeDropdownTpl>\n <div class=\"bg-popover flex overflow-hidden rounded-sm\">\n @if (zShowHour()) {\n <div\n class=\"flex flex-col\"\n [class.border-r]=\"zShowMinute() || zShowSecond()\"\n [class.border-border]=\"zShowMinute() || zShowSecond()\">\n <ng-scrollbar\n class=\"z-time-scroll-hour h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowMinute() && !zShowSecond()\"\n [class.rounded-l-sm]=\"zShowMinute() || zShowSecond()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (hr of hourOptions(); track hr) {\n @let hrSelected = hr === displayHour();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 cursor-pointer items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!hrSelected\"\n [class.bg-primary]=\"hrSelected\"\n [class.text-primary-foreground]=\"hrSelected\"\n [class.font-medium]=\"hrSelected\"\n (click)=\"selectHour(hr)\">\n {{ hr | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n @if (zShowMinute()) {\n <div class=\"flex flex-col\" [class.border-r]=\"zShowSecond()\" [class.border-border]=\"zShowSecond()\">\n <ng-scrollbar\n class=\"z-time-scroll-minute h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowHour() && !zShowSecond()\"\n [class.rounded-l-sm]=\"!zShowHour() && zShowSecond()\"\n [class.rounded-r-sm]=\"zShowHour() && !zShowSecond()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (min of minuteOptions; track min) {\n @let minSelected = min === minute();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 cursor-pointer items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!minSelected\"\n [class.bg-primary]=\"minSelected\"\n [class.text-primary-foreground]=\"minSelected\"\n [class.font-medium]=\"minSelected\"\n (click)=\"selectMinute(min)\">\n {{ min | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n @if (zShowSecond()) {\n <div class=\"flex flex-col\">\n <ng-scrollbar\n class=\"z-time-scroll-second h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowHour() && !zShowMinute()\"\n [class.rounded-r-sm]=\"zShowHour() || zShowMinute()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (sec of secondOptions; track sec) {\n @let secSelected = sec === second();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 cursor-pointer items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!secSelected\"\n [class.bg-primary]=\"secSelected\"\n [class.text-primary-foreground]=\"secSelected\"\n [class.font-medium]=\"secSelected\"\n (click)=\"selectSecond(sec)\">\n {{ sec | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n </div>\n</ng-template>\n\n<ng-template #timeDropdownEndTpl>\n <div class=\"bg-popover flex overflow-hidden rounded-sm\">\n @if (zShowHour()) {\n <div\n class=\"flex flex-col\"\n [class.border-r]=\"zShowMinute() || zShowSecond()\"\n [class.border-border]=\"zShowMinute() || zShowSecond()\">\n <ng-scrollbar\n class=\"z-time-scroll-hour-end h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowMinute() && !zShowSecond()\"\n [class.rounded-l-sm]=\"zShowMinute() || zShowSecond()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (hr of hourOptions(); track hr) {\n @let hrDisabled = hr | zIsEndHourDisabled: endTimeContext();\n @let hrEndSelected = hr === displayHourEnd();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!hrDisabled && !hrEndSelected\"\n [class.cursor-pointer]=\"!hrDisabled\"\n [class.bg-primary]=\"hrEndSelected\"\n [class.text-primary-foreground]=\"hrEndSelected\"\n [class.font-medium]=\"hrEndSelected\"\n [class.opacity-30]=\"hrDisabled\"\n [class.cursor-not-allowed]=\"hrDisabled\"\n [disabled]=\"hrDisabled\"\n (click)=\"selectHourEnd(hr)\">\n {{ hr | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n @if (zShowMinute()) {\n <div class=\"flex flex-col\" [class.border-r]=\"zShowSecond()\" [class.border-border]=\"zShowSecond()\">\n <ng-scrollbar\n class=\"z-time-scroll-minute-end h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowHour() && !zShowSecond()\"\n [class.rounded-l-sm]=\"!zShowHour() && zShowSecond()\"\n [class.rounded-r-sm]=\"zShowHour() && !zShowSecond()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (min of minuteOptions; track min) {\n @let minDisabled = min | zIsEndMinuteDisabled: endTimeContext();\n @let minEndSelected = min === minuteEnd();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!minDisabled && !minEndSelected\"\n [class.cursor-pointer]=\"!minDisabled\"\n [class.bg-primary]=\"minEndSelected\"\n [class.text-primary-foreground]=\"minEndSelected\"\n [class.font-medium]=\"minEndSelected\"\n [class.opacity-30]=\"minDisabled\"\n [class.cursor-not-allowed]=\"minDisabled\"\n [disabled]=\"minDisabled\"\n (click)=\"selectMinuteEnd(min)\">\n {{ min | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n @if (zShowSecond()) {\n <div class=\"flex flex-col\">\n <ng-scrollbar\n class=\"z-time-scroll-second-end h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowHour() && !zShowMinute()\"\n [class.rounded-r-sm]=\"zShowHour() || zShowMinute()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (sec of secondOptions; track sec) {\n @let secDisabled = sec | zIsEndSecondDisabled: endTimeContext();\n @let secEndSelected = sec === secondEnd();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!secDisabled && !secEndSelected\"\n [class.cursor-pointer]=\"!secDisabled\"\n [class.bg-primary]=\"secEndSelected\"\n [class.text-primary-foreground]=\"secEndSelected\"\n [class.font-medium]=\"secEndSelected\"\n [class.opacity-30]=\"secDisabled\"\n [class.cursor-not-allowed]=\"secDisabled\"\n [disabled]=\"secDisabled\"\n (click)=\"selectSecondEnd(sec)\">\n {{ sec | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n </div>\n</ng-template>\n", styles: [".animate-calendar-enter{animation:z-calendar-view-enter .2s ease-out}@keyframes z-calendar-view-enter{0%{opacity:0;transform:scale(.95) translateY(.25rem)}to{opacity:1;transform:scale(1) translateY(0)}}.z-calendar input{text-overflow:ellipsis;overflow:hidden}\n"], dependencies: [{ kind: "component", type: NgScrollbar, selector: "ng-scrollbar:not([externalViewport]), [ngScrollbar]", exportAs: ["ngScrollbar"] }, { kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zSize", "zStrokeWidth", "zSvg"] }, { kind: "directive", type: ZPopoverDirective, selector: "[z-popover]", inputs: ["zPopoverContent", "zPosition", "zTrigger", "zClass", "zShowDelay", "zHideDelay", "zDisabled", "zOffset", "zPopoverWidth", "zManualClose", "zScrollClose", "zShowArrow"], outputs: ["zShow", "zHide", "zHideStart", "zControl", "zPositionChange"], exportAs: ["zPopover"] }, { kind: "component", type: ZButtonComponent, selector: "z-button, button[z-button], a[z-button]", inputs: ["class", "zType", "zSize", "zShape", "zLabel", "zLoading", "zDisabled", "zTypeIcon", "zSizeIcon", "zStrokeWidthIcon", "zWave"], exportAs: ["zButton"] }, { kind: "pipe", type: DecimalPipe, name: "number" }, { kind: "pipe", type: ZDayClassesPipe, name: "zDayClasses" }, { kind: "pipe", type: ZMonthClassesPipe, name: "zMonthClasses" }, { kind: "pipe", type: ZQuarterClassesPipe, name: "zQuarterClasses" }, { kind: "pipe", type: ZYearClassesPipe, name: "zYearClasses" }, { kind: "pipe", type: ZIsPresetDisabledPipe, name: "zIsPresetDisabled" }, { kind: "pipe", type: ZIsEndHourDisabledPipe, name: "zIsEndHourDisabled" }, { kind: "pipe", type: ZIsEndMinuteDisabledPipe, name: "zIsEndMinuteDisabled" }, { kind: "pipe", type: ZIsEndSecondDisabledPipe, name: "zIsEndSecondDisabled" }, { kind: "pipe", type: ZIsStartMonthDisabledPipe, name: "zIsStartMonthDisabled" }, { kind: "pipe", type: ZIsEndMonthDisabledPipe, name: "zIsEndMonthDisabled" }, { kind: "pipe", type: ZIsStartYearDisabledPipe, name: "zIsStartYearDisabled" }, { kind: "pipe", type: ZIsEndYearDisabledPipe, name: "zIsEndYearDisabled" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
3031
+ ], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["triggerEl"], descendants: true, isSignal: true }, { propertyName: "inputRef", first: true, predicate: ["inputEl"], descendants: true, isSignal: true }], exportAs: ["zCalendar"], ngImport: i0, template: "<div class=\"z-calendar-wrapper flex w-full flex-col gap-2\">\n @if (zLabel()) {\n <label [for]=\"pickerId\" class=\"text-xs leading-none font-medium\" [class]=\"zLabelClass()\">\n {{ zLabel() }}\n @if (zRequired()) {\n <span class=\"text-destructive! ml-0.5\">*</span>\n }\n </label>\n }\n\n <div class=\"relative\">\n <div\n #triggerEl\n z-popover\n [zPopoverContent]=\"calendarTpl\"\n zPosition=\"bottom-left\"\n zPopoverWidth=\"auto\"\n [zOffset]=\"6\"\n [zDisabled]=\"isDisabled() || zReadonly()\"\n [zManualClose]=\"showCancelButton()\"\n [zScrollClose]=\"zScrollClose()\"\n zTrigger=\"click\"\n zClass=\"border-0 shadow-none p-0\"\n (zHideStart)=\"onPopoverHide()\"\n (zShow)=\"onPopoverShow()\"\n (zControl)=\"onPopoverControl($event)\"\n [id]=\"pickerId\"\n [class]=\"triggerClasses()\"\n (keydown)=\"onTriggerKeydown($event)\">\n <z-icon\n [zType]=\"isRangeMode() ? 'lucideCalendarRange' : 'lucideCalendar'\"\n zSize=\"16\"\n class=\"text-muted-foreground shrink-0 cursor-pointer\"\n (click)=\"$event.stopPropagation(); toggle()\" />\n\n @if (isRangeMode()) {\n <input\n type=\"text\"\n data-range-type=\"start\"\n class=\"placeholder:text-muted-foreground w-0 min-w-0 flex-1 truncate bg-transparent text-center text-sm outline-none\"\n [placeholder]=\"'i18n_z_ui_calendar_start_date' | translate\"\n [value]=\"inputDisplayStart()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"zReadonly()\"\n (click)=\"isOpen() && $event.stopPropagation()\"\n (focus)=\"onInputFocus($event)\"\n (input)=\"onStartInputChange($event)\"\n (blur)=\"onInputBlur($event)\"\n (keydown.enter)=\"onStartInputEnter($event)\"\n (keydown.escape)=\"onStartInputEscape()\" />\n <span class=\"text-muted-foreground text-sm\">-</span>\n <input\n type=\"text\"\n data-range-type=\"end\"\n class=\"placeholder:text-muted-foreground w-0 min-w-0 flex-1 truncate bg-transparent text-center text-sm outline-none\"\n [placeholder]=\"'i18n_z_ui_calendar_end_date' | translate\"\n [value]=\"inputDisplayEnd()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"zReadonly()\"\n (click)=\"isOpen() && $event.stopPropagation()\"\n (focus)=\"onInputFocus($event)\"\n (input)=\"onEndInputChange($event)\"\n (blur)=\"onInputBlur($event)\"\n (keydown.enter)=\"onEndInputEnter($event)\"\n (keydown.escape)=\"onEndInputEscape()\" />\n } @else {\n <input\n #inputEl\n type=\"text\"\n class=\"placeholder:text-muted-foreground w-0 min-w-0 flex-1 truncate bg-transparent text-sm outline-none\"\n [placeholder]=\"effectivePlaceholder()\"\n [value]=\"inputDisplayValue()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"zReadonly()\"\n (click)=\"isOpen() && $event.stopPropagation()\"\n (focus)=\"onInputFocus($event)\"\n (input)=\"onInputChange($event)\"\n (blur)=\"onInputBlur($event)\"\n (keydown.enter)=\"onInputEnter($event)\"\n (keydown.escape)=\"onInputEscape()\" />\n }\n\n @if (zAllowClear() && !isDisabled() && !zReadonly()) {\n <button\n type=\"button\"\n tabindex=\"-1\"\n class=\"text-muted-foreground hover:text-foreground flex size-5 shrink-0 cursor-pointer items-center justify-center rounded-sm transition-all\"\n [class.opacity-0]=\"!hasValue()\"\n [class.pointer-events-none]=\"!hasValue()\"\n (click)=\"onClear($event)\">\n <z-icon zType=\"lucideX\" zSize=\"18\" />\n </button>\n }\n </div>\n </div>\n\n @if (hasError()) {\n <p class=\"text-destructive animate-in fade-in slide-in-from-top-1 m-0 text-xs duration-200\">\n {{ errorMessage() }}\n </p>\n }\n</div>\n\n<ng-template #calendarTpl>\n <div\n class=\"z-calendar-calendar bg-popover border-border flex max-h-[50dvh] max-w-[calc(100vw-1.5rem)] flex-col overflow-hidden rounded-sm border shadow-lg min-[480px]:max-h-[55dvh] sm:max-h-none sm:max-w-none sm:flex-row sm:overflow-visible\"\n (keydown)=\"onCalendarKeydown($event)\">\n @if (zQuickSelect() && zMode() === 'range') {\n <div class=\"border-border hidden shrink-0 flex-col gap-0 space-y-1 overflow-y-auto border-r p-2 sm:flex\">\n @for (preset of quickSelectPresets; track preset.key) {\n @let presetDisabled = preset | zIsPresetDisabled: zDisabledDate();\n <button\n type=\"button\"\n class=\"cursor-pointer rounded-sm px-3 py-1.5 text-left text-sm whitespace-nowrap transition-colors\"\n [class.hover:bg-muted]=\"activePresetKey() !== preset.key && !presetDisabled\"\n [class.bg-primary]=\"activePresetKey() === preset.key\"\n [class.text-primary-foreground]=\"activePresetKey() === preset.key\"\n [class.font-medium]=\"activePresetKey() === preset.key\"\n [class.opacity-40]=\"presetDisabled\"\n [class.cursor-not-allowed]=\"presetDisabled\"\n [disabled]=\"presetDisabled\"\n (click)=\"onQuickSelect(preset)\">\n {{ preset.label | translate }}\n </button>\n }\n </div>\n }\n <div\n class=\"flex min-h-0 flex-1 flex-col items-center overflow-hidden pb-0 sm:overflow-visible sm:py-2\"\n [class]=\"\n !isRangeMode()\n ? 'w-[17.75rem] max-w-[calc(100vw-1.5rem)]'\n : 'w-[17.75rem] max-w-[calc(100vw-1.5rem)] sm:w-auto sm:max-w-none'\n \">\n @if (zQuickSelect() && zMode() === 'range') {\n <div class=\"border-border w-full border-b px-2 pt-2 pb-2 sm:hidden\">\n <z-select\n class=\"w-full\"\n zSize=\"sm\"\n zPosition=\"bottom-left\"\n [zShowSearch]=\"false\"\n [zAllowClear]=\"false\"\n [zOptions]=\"quickSelectOptions()\"\n [ngModel]=\"activePresetKey()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"onQuickSelectKeyChange($event)\" />\n </div>\n }\n <div class=\"min-h-0 w-full flex-1 overflow-x-hidden overflow-y-auto pt-2 sm:overflow-visible sm:pt-0\">\n @if (!isTimeMode()) {\n <div\n class=\"z-calendars-wrapper flex w-full flex-col items-center gap-0 sm:flex-row sm:items-stretch sm:justify-center\">\n <!-- First Calendar -->\n <div class=\"z-calendar-section flex w-[17.5rem] shrink-0 flex-col\">\n @if (!isTimeMode()) {\n <!-- Header -->\n <div class=\"border-border flex w-full items-center justify-between gap-0.5 px-2\">\n <!-- Double left arrow (always visible) -->\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zWave]=\"false\"\n (click)=\"navigatePreviousFast()\">\n <z-icon zType=\"lucideChevronsLeft\" zSize=\"18\" />\n </button>\n\n <!-- Single left arrow (hidden in month/year view) -->\n @if (currentView() === 'day') {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zWave]=\"false\"\n (click)=\"navigatePrevious()\">\n <z-icon zType=\"lucideChevronLeft\" zSize=\"18\" />\n </button>\n }\n\n <!-- Header content -->\n <div class=\"flex flex-1 shrink-0 items-center justify-center gap-0\">\n @if (currentView() === 'day') {\n <!-- Day view: Month + Year -->\n @if (!isYearMode() && !isQuarterMode()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n (click)=\"setView('month')\">\n {{ currentMonthName() }}\n </button>\n }\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n [zDisabled]=\"isYearMode()\"\n (click)=\"setView('year')\">\n {{ currentYear() }}\n </button>\n } @else if (currentView() === 'month') {\n <!-- Month view: Only Year -->\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n (click)=\"setView('year')\">\n {{ currentYear() }}\n </button>\n } @else if (currentView() === 'year') {\n <!-- Year view: Year Range -->\n <span class=\"text-sm font-medium\">\n {{ yearRange()[0] }} - {{ yearRange()[yearRange().length - 1] }}\n </span>\n } @else if (currentView() === 'quarter') {\n <!-- Quarter view: Only Year -->\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n (click)=\"setView('year')\">\n {{ currentYear() }}\n </button>\n }\n </div>\n\n <!-- Single right arrow (hidden in month/year view) -->\n @if (currentView() === 'day') {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zDisabled]=\"!canNavigateStartNext()\"\n [zWave]=\"false\"\n (click)=\"navigateNext()\">\n <z-icon zType=\"lucideChevronRight\" zSize=\"18\" />\n </button>\n }\n\n <!-- Double right arrow (always visible) -->\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zDisabled]=\"!canNavigateStartNext()\"\n [zWave]=\"false\"\n (click)=\"navigateNextFast()\">\n <z-icon zType=\"lucideChevronsRight\" zSize=\"18\" />\n </button>\n </div>\n\n <!-- Body -->\n <div\n class=\"flex h-full w-full flex-col items-center justify-center p-2\"\n [class.min-h-[14rem]]=\"!isQuarterMode()\"\n [class.h-[14rem]]=\"\n !isYearMode() &&\n !isMonthMode() &&\n !isQuarterMode() &&\n (currentView() === 'month' || currentView() === 'year')\n \"\n [class.min-h-[6.25rem]]=\"isQuarterMode()\"\n [class.!min-h-auto]=\"isYearMode() || isMonthMode() || isQuarterMode()\"\n [class.!h-auto]=\"isYearMode() || isMonthMode() || isQuarterMode()\">\n @if (currentView() === 'day') {\n <div\n class=\"flex h-full w-full flex-1 flex-col gap-1\"\n [class.animate-calendar-enter]=\"uiState().hasViewChanged\">\n <!-- Weekday headers -->\n <div class=\"flex w-full flex-1 justify-center gap-1\">\n @for (weekday of weekdayNames(); track weekday) {\n <div\n class=\"text-muted-foreground flex h-[1.875rem] w-[2.0313rem] items-center justify-center text-xs font-medium\">\n {{ weekday }}\n </div>\n }\n </div>\n\n <!-- Date rows -->\n @for (week of calendarDays(); track $index) {\n <div class=\"flex w-full flex-1 justify-center gap-1\">\n @for (day of week; track day.date.getTime()) {\n <button\n type=\"button\"\n [class]=\"day | zDayClasses\"\n class=\"h-[1.875rem] !w-[2.0313rem] !text-sm\"\n [disabled]=\"day.isDisabled\"\n (click)=\"onDayClick(day)\"\n (mouseenter)=\"onDayHover(day)\"\n (mouseleave)=\"onDayLeave()\">\n {{ day.day }}\n </button>\n }\n </div>\n }\n </div>\n }\n @if (currentView() === 'month') {\n <div\n class=\"grid h-full w-full grid-cols-3 grid-rows-4 gap-2.5 gap-y-5!\"\n [class.animate-calendar-enter]=\"uiState().hasViewChanged\">\n @for (month of monthNames(); track month; let i = $index) {\n @let monthDisabled = i | zIsStartMonthDisabled: startMonthDisabledContext();\n <div class=\"flex flex-1 items-center justify-center\">\n <button\n type=\"button\"\n [class]=\"i | zMonthClasses: selectedMonthIndex() : todayMonthIndex()\"\n class=\"!h-7 !w-full !text-sm\"\n [disabled]=\"monthDisabled\"\n [class.opacity-30]=\"monthDisabled\"\n [class.cursor-not-allowed]=\"monthDisabled\"\n (click)=\"onMonthSelect(i)\">\n {{ month }}\n </button>\n </div>\n }\n </div>\n }\n\n @if (currentView() === 'year') {\n <div\n class=\"grid h-full w-full grid-cols-3 grid-rows-4 gap-2.5 gap-y-5!\"\n [class.animate-calendar-enter]=\"uiState().hasViewChanged\">\n @for (year of yearRange(); track year) {\n @let yearDisabled = year | zIsStartYearDisabled: startYearDisabledContext();\n <div class=\"flex flex-1 items-center justify-center\">\n <button\n type=\"button\"\n [class]=\"year | zYearClasses: selectedYear() : todayYear()\"\n class=\"!h-7 !w-full !text-sm\"\n [disabled]=\"yearDisabled\"\n [class.opacity-30]=\"yearDisabled\"\n [class.cursor-not-allowed]=\"yearDisabled\"\n (click)=\"onYearClick(year)\">\n {{ year }}\n </button>\n </div>\n }\n </div>\n }\n\n @if (currentView() === 'quarter') {\n <div\n class=\"grid h-full w-full grid-cols-2 grid-rows-2 gap-2 p-1\"\n [class.animate-calendar-enter]=\"uiState().hasViewChanged\">\n @for (quarter of quarterNames; track quarter; let i = $index) {\n <div class=\"flex flex-1 items-center justify-center\">\n <button\n type=\"button\"\n [class]=\"i | zQuarterClasses: selectedQuarterIndex() : todayQuarterIndex()\"\n class=\"!h-8 !w-full !text-sm\"\n (click)=\"onQuarterClick(i)\">\n {{ quarter }}\n </button>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Second Calendar (Range Mode Only) -->\n @if (isRangeMode()) {\n <!-- Divider -->\n <div class=\"border-border bg-border hidden self-stretch sm:block sm:w-px\"></div>\n <div class=\"border-border bg-border block h-px w-full sm:hidden\"></div>\n\n <div class=\"z-calendar-section flex w-[17.5rem] shrink-0 flex-col pt-2 sm:pt-0\">\n <!-- Header -->\n <div class=\"border-border flex w-full items-center justify-between gap-0.5 px-2\">\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zDisabled]=\"!canNavigateEndPrev()\"\n [zWave]=\"false\"\n (click)=\"navigateEndPreviousFast()\">\n <z-icon zType=\"lucideChevronsLeft\" zSize=\"18\" />\n </button>\n\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zDisabled]=\"!canNavigateEndPrev()\"\n [zWave]=\"false\"\n (click)=\"navigateEndPrevious()\">\n <z-icon zType=\"lucideChevronLeft\" zSize=\"18\" />\n </button>\n\n <div class=\"flex w-[7.5rem] shrink-0 items-center justify-center gap-0\">\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n (click)=\"setEndView('month')\">\n {{ endMonthName() }}\n </button>\n\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n (click)=\"setEndView('year')\">\n {{ endMonthYear() }}\n </button>\n </div>\n\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zWave]=\"false\"\n [zWave]=\"false\"\n (click)=\"navigateEndNext()\">\n <z-icon zType=\"lucideChevronRight\" zSize=\"18\" />\n </button>\n\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zWave]=\"false\"\n [zWave]=\"false\"\n (click)=\"navigateEndNextFast()\">\n <z-icon zType=\"lucideChevronsRight\" zSize=\"18\" />\n </button>\n </div>\n\n <!-- Body -->\n <div\n class=\"flex h-full min-h-[14rem] w-full flex-col items-center justify-center p-2\"\n [class.h-[14rem]]=\"endView() === 'month' || endView() === 'year'\">\n @if (endView() === 'day') {\n <div\n class=\"flex h-full w-full flex-1 flex-col gap-1\"\n [class.animate-calendar-enter]=\"uiState().hasEndViewChanged\">\n <!-- Weekday headers -->\n <div class=\"flex w-full flex-1 justify-center gap-1\">\n @for (weekday of weekdayNames(); track weekday) {\n <div\n class=\"text-muted-foreground flex h-[1.875rem] w-[2.0313rem] items-center justify-center text-xs font-medium\">\n {{ weekday }}\n </div>\n }\n </div>\n\n <!-- Date rows -->\n @for (week of calendarDaysEnd(); track $index) {\n <div class=\"flex w-full flex-1 justify-center gap-1\">\n @for (day of week; track day.date.getTime()) {\n <button\n type=\"button\"\n [class]=\"day | zDayClasses\"\n class=\"h-[1.875rem] !w-[2.0313rem] !text-sm\"\n [disabled]=\"day.isDisabled\"\n (click)=\"onDayClick(day)\"\n (mouseenter)=\"onDayHover(day)\"\n (mouseleave)=\"onDayLeave()\">\n {{ day.day }}\n </button>\n }\n </div>\n }\n </div>\n }\n @if (endView() === 'month') {\n <div\n class=\"grid h-full w-full grid-cols-3 grid-rows-4 gap-2.5 gap-y-5!\"\n [class.animate-calendar-enter]=\"uiState().hasEndViewChanged\">\n @for (month of monthNames(); track month; let i = $index) {\n @let endMonthDisabled = i | zIsEndMonthDisabled: endMonthDisabledContext();\n <div class=\"flex flex-1 items-center justify-center\">\n <button\n type=\"button\"\n [class]=\"i | zMonthClasses: endMonth().getMonth() : -1\"\n class=\"!h-7 !w-full !text-sm\"\n [disabled]=\"endMonthDisabled\"\n [class.opacity-30]=\"endMonthDisabled\"\n [class.cursor-not-allowed]=\"endMonthDisabled\"\n (click)=\"onEndMonthClick(i)\">\n {{ month }}\n </button>\n </div>\n }\n </div>\n }\n\n @if (endView() === 'year') {\n <div\n class=\"grid h-full w-full grid-cols-3 grid-rows-4 gap-2.5 gap-y-5!\"\n [class.animate-calendar-enter]=\"uiState().hasEndViewChanged\">\n @for (year of endYearRange(); track year) {\n @let endYearDisabled = year | zIsEndYearDisabled: endYearDisabledContext();\n <div class=\"flex flex-1 items-center justify-center\">\n <button\n type=\"button\"\n [class]=\"year | zYearClasses: endMonth().getFullYear() : -1\"\n class=\"!h-7 !w-full !text-sm\"\n [disabled]=\"endYearDisabled\"\n [class.opacity-30]=\"endYearDisabled\"\n [class.cursor-not-allowed]=\"endYearDisabled\"\n (click)=\"onEndYearClick(year)\">\n {{ year }}\n </button>\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n\n <!-- Compact Time Picker Below Calendar (Single Date) -->\n @if (!isRangeMode() && zShowTime()) {\n <div class=\"border-border w-full border-t text-center\">\n <div\n class=\"hover:bg-muted my-1 inline-flex cursor-pointer items-center rounded-sm px-2 py-1 transition-colors\"\n z-popover\n [zPopoverContent]=\"timeDropdownTpl\"\n zPosition=\"bottom\"\n zPopoverWidth=\"auto\"\n [zOffset]=\"4\"\n zTrigger=\"click\"\n zClass=\"border-border shadow-md\"\n (zShow)=\"onTimeDropdownShow()\">\n <div class=\"flex items-center justify-center gap-1\">\n <!-- Hour -->\n @if (zShowHour()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedHour() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowHour() && zShowMinute()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Minute -->\n @if (zShowMinute()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedMinute() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowMinute() && zShowSecond()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Second -->\n @if (zShowSecond()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedSecond() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n <!-- AM/PM Toggle -->\n @if (zTimeFormat() === '12h') {\n <button\n type=\"button\"\n class=\"bg-primary/10 text-primary hover:bg-primary/20 active:bg-primary/30 ml-1 flex w-8 cursor-pointer items-center justify-center rounded-sm border-none px-2 py-1 text-xs font-semibold transition-colors\"\n (click)=\"togglePeriod(); $event.stopPropagation()\">\n {{ period() }}\n </button>\n }\n </div>\n </div>\n </div>\n }\n\n <!-- Compact Time Pickers Below Calendars (Range Mode) -->\n @if (isRangeMode() && zShowTime()) {\n <div class=\"border-border flex w-full flex-col border-t sm:flex-row\">\n <!-- Start Time -->\n <div class=\"flex w-full flex-col items-center justify-center gap-1\">\n <div\n class=\"hover:bg-muted my-1 inline-flex cursor-pointer items-center rounded-sm px-2 py-1 transition-colors\"\n z-popover\n [zPopoverContent]=\"timeDropdownTpl\"\n zPosition=\"bottom\"\n zPopoverWidth=\"auto\"\n [zOffset]=\"4\"\n zTrigger=\"click\"\n zClass=\"border-border shadow-md\"\n (zShow)=\"onTimeDropdownShow()\">\n <div class=\"flex items-center justify-center gap-1\">\n <!-- Hour -->\n @if (zShowHour()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedHour() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowHour() && zShowMinute()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Minute -->\n @if (zShowMinute()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedMinute() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowMinute() && zShowSecond()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Second -->\n @if (zShowSecond()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedSecond() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n <!-- AM/PM Toggle -->\n @if (zTimeFormat() === '12h') {\n <button\n type=\"button\"\n class=\"bg-primary/10 text-primary hover:bg-primary/20 active:bg-primary/30 ml-1 flex w-8 cursor-pointer items-center justify-center rounded-sm border-none px-2 py-1 text-xs font-semibold transition-colors\"\n (click)=\"togglePeriod(); $event.stopPropagation()\">\n {{ period() }}\n </button>\n }\n </div>\n </div>\n </div>\n\n <!-- Divider space -->\n <div class=\"border-border bg-border h-px self-stretch sm:block sm:h-full sm:w-px\"></div>\n\n <!-- End Time -->\n <div class=\"flex w-full flex-col items-center justify-center gap-1\">\n <div\n class=\"hover:bg-muted my-1 inline-flex cursor-pointer items-center rounded-sm px-2 py-1 transition-colors\"\n z-popover\n [zPopoverContent]=\"timeDropdownEndTpl\"\n zPosition=\"bottom\"\n zPopoverWidth=\"auto\"\n [zOffset]=\"4\"\n zTrigger=\"click\"\n zClass=\"border-border shadow-md\"\n (zShow)=\"onTimeDropdownEndShow()\">\n <div class=\"flex items-center justify-center gap-1\">\n <!-- Hour -->\n @if (zShowHour()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementHourEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedHourEnd() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementHourEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowHour() && zShowMinute()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Minute -->\n @if (zShowMinute()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementMinuteEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedMinuteEnd() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementMinuteEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowMinute() && zShowSecond()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Second -->\n @if (zShowSecond()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementSecondEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedSecondEnd() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementSecondEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n <!-- AM/PM Toggle -->\n @if (zTimeFormat() === '12h') {\n <button\n type=\"button\"\n class=\"bg-primary/10 text-primary hover:bg-primary/20 active:bg-primary/30 ml-1 flex w-8 cursor-pointer items-center justify-center rounded-sm border-none px-2 py-1 text-xs font-semibold transition-colors\"\n (click)=\"togglePeriodEnd(); $event.stopPropagation()\">\n {{ periodEnd() }}\n </button>\n }\n </div>\n </div>\n </div>\n </div>\n }\n } @else {\n <!-- Time Only Mode - Compact Display -->\n <div class=\"flex flex-col items-center gap-3 pb-2\">\n <div\n class=\"hover:bg-muted inline-flex cursor-pointer items-center rounded-sm px-3 py-2 transition-colors\"\n z-popover\n [zPopoverContent]=\"timeDropdownTpl\"\n zPosition=\"bottom\"\n zPopoverWidth=\"auto\"\n [zOffset]=\"4\"\n zTrigger=\"click\"\n zClass=\"border-border shadow-md\"\n (zShow)=\"onTimeDropdownShow()\">\n <div class=\"flex items-center justify-center gap-1.5\">\n <!-- Hour -->\n @if (zShowHour()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-9 cursor-pointer flex-col items-center gap-0 rounded-sm px-1.5 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"16\" />\n </button>\n <span class=\"text-foreground min-w-6 text-center text-base leading-tight font-medium select-none\">\n {{ formattedHour() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"16\" />\n </button>\n </div>\n }\n @if (zShowHour() && zShowMinute()) {\n <span class=\"text-muted-foreground text-base font-medium\">:</span>\n }\n <!-- Minute -->\n @if (zShowMinute()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-9 cursor-pointer flex-col items-center gap-0 rounded-sm px-1.5 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"16\" />\n </button>\n <span class=\"text-foreground min-w-6 text-center text-base leading-tight font-medium select-none\">\n {{ formattedMinute() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"16\" />\n </button>\n </div>\n }\n @if (zShowMinute() && zShowSecond()) {\n <span class=\"text-muted-foreground text-base font-medium\">:</span>\n }\n <!-- Second -->\n @if (zShowSecond()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-9 cursor-pointer flex-col items-center gap-0 rounded-sm px-1.5 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"16\" />\n </button>\n <span class=\"text-foreground min-w-6 text-center text-base leading-tight font-medium select-none\">\n {{ formattedSecond() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"16\" />\n </button>\n </div>\n }\n <!-- AM/PM Toggle -->\n @if (zTimeFormat() === '12h') {\n <button\n type=\"button\"\n class=\"bg-primary/10 text-primary hover:bg-primary/20 active:bg-primary/30 ml-1 flex w-10 cursor-pointer items-center justify-center rounded-sm border-none px-2.5 py-1.5 text-sm font-semibold transition-colors\"\n (click)=\"togglePeriod(); $event.stopPropagation()\">\n {{ period() }}\n </button>\n }\n </div>\n </div>\n </div>\n }\n </div>\n\n @if (!(zQuickSelect() && zMode() === 'range' && !showOkButton() && !showCancelButton())) {\n <div\n class=\"bg-popover border-border z-10 flex w-full shrink-0 items-center justify-between gap-2 border-t px-2 py-2 shadow-[0_-2px_8px_-2px_rgb(0_0_0_/_10%)] sm:pt-2 sm:pb-0 sm:shadow-none\">\n @if (!zQuickSelect() || zMode() !== 'range') {\n <button type=\"button\" z-button zType=\"secondary\" zSize=\"sm\" [zWave]=\"false\" (click)=\"onTodayClick()\">\n {{ todayButtonText() }}\n </button>\n } @else {\n <div></div>\n }\n\n @if (showOkButton() || showCancelButton()) {\n <div class=\"flex items-center gap-2\">\n @if (showCancelButton()) {\n <button type=\"button\" z-button zType=\"outline\" zSize=\"sm\" (click)=\"onCancelClick()\">\n {{ zCancelText() ?? ('i18n_z_ui_calendar_cancel' | translate) }}\n </button>\n }\n @if (showOkButton()) {\n <button type=\"button\" z-button zSize=\"sm\" [zDisabled]=\"!canApply()\" (click)=\"onOkClick()\">\n {{ zOkText() ?? ('i18n_z_ui_calendar_ok' | translate) }}\n </button>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n</ng-template>\n\n<ng-template #timeDropdownTpl>\n <div class=\"bg-popover flex overflow-hidden rounded-sm\">\n @if (zShowHour()) {\n <div\n class=\"flex flex-col\"\n [class.border-r]=\"zShowMinute() || zShowSecond()\"\n [class.border-border]=\"zShowMinute() || zShowSecond()\">\n <ng-scrollbar\n class=\"z-time-scroll-hour h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowMinute() && !zShowSecond()\"\n [class.rounded-l-sm]=\"zShowMinute() || zShowSecond()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (hr of hourOptions(); track hr) {\n @let hrSelected = hr === displayHour();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 cursor-pointer items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!hrSelected\"\n [class.bg-primary]=\"hrSelected\"\n [class.text-primary-foreground]=\"hrSelected\"\n [class.font-medium]=\"hrSelected\"\n (click)=\"selectHour(hr)\">\n {{ hr | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n @if (zShowMinute()) {\n <div class=\"flex flex-col\" [class.border-r]=\"zShowSecond()\" [class.border-border]=\"zShowSecond()\">\n <ng-scrollbar\n class=\"z-time-scroll-minute h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowHour() && !zShowSecond()\"\n [class.rounded-l-sm]=\"!zShowHour() && zShowSecond()\"\n [class.rounded-r-sm]=\"zShowHour() && !zShowSecond()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (min of minuteOptions; track min) {\n @let minSelected = min === minute();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 cursor-pointer items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!minSelected\"\n [class.bg-primary]=\"minSelected\"\n [class.text-primary-foreground]=\"minSelected\"\n [class.font-medium]=\"minSelected\"\n (click)=\"selectMinute(min)\">\n {{ min | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n @if (zShowSecond()) {\n <div class=\"flex flex-col\">\n <ng-scrollbar\n class=\"z-time-scroll-second h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowHour() && !zShowMinute()\"\n [class.rounded-r-sm]=\"zShowHour() || zShowMinute()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (sec of secondOptions; track sec) {\n @let secSelected = sec === second();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 cursor-pointer items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!secSelected\"\n [class.bg-primary]=\"secSelected\"\n [class.text-primary-foreground]=\"secSelected\"\n [class.font-medium]=\"secSelected\"\n (click)=\"selectSecond(sec)\">\n {{ sec | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n </div>\n</ng-template>\n\n<ng-template #timeDropdownEndTpl>\n <div class=\"bg-popover flex overflow-hidden rounded-sm\">\n @if (zShowHour()) {\n <div\n class=\"flex flex-col\"\n [class.border-r]=\"zShowMinute() || zShowSecond()\"\n [class.border-border]=\"zShowMinute() || zShowSecond()\">\n <ng-scrollbar\n class=\"z-time-scroll-hour-end h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowMinute() && !zShowSecond()\"\n [class.rounded-l-sm]=\"zShowMinute() || zShowSecond()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (hr of hourOptions(); track hr) {\n @let hrDisabled = hr | zIsEndHourDisabled: endTimeContext();\n @let hrEndSelected = hr === displayHourEnd();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!hrDisabled && !hrEndSelected\"\n [class.cursor-pointer]=\"!hrDisabled\"\n [class.bg-primary]=\"hrEndSelected\"\n [class.text-primary-foreground]=\"hrEndSelected\"\n [class.font-medium]=\"hrEndSelected\"\n [class.opacity-30]=\"hrDisabled\"\n [class.cursor-not-allowed]=\"hrDisabled\"\n [disabled]=\"hrDisabled\"\n (click)=\"selectHourEnd(hr)\">\n {{ hr | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n @if (zShowMinute()) {\n <div class=\"flex flex-col\" [class.border-r]=\"zShowSecond()\" [class.border-border]=\"zShowSecond()\">\n <ng-scrollbar\n class=\"z-time-scroll-minute-end h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowHour() && !zShowSecond()\"\n [class.rounded-l-sm]=\"!zShowHour() && zShowSecond()\"\n [class.rounded-r-sm]=\"zShowHour() && !zShowSecond()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (min of minuteOptions; track min) {\n @let minDisabled = min | zIsEndMinuteDisabled: endTimeContext();\n @let minEndSelected = min === minuteEnd();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!minDisabled && !minEndSelected\"\n [class.cursor-pointer]=\"!minDisabled\"\n [class.bg-primary]=\"minEndSelected\"\n [class.text-primary-foreground]=\"minEndSelected\"\n [class.font-medium]=\"minEndSelected\"\n [class.opacity-30]=\"minDisabled\"\n [class.cursor-not-allowed]=\"minDisabled\"\n [disabled]=\"minDisabled\"\n (click)=\"selectMinuteEnd(min)\">\n {{ min | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n @if (zShowSecond()) {\n <div class=\"flex flex-col\">\n <ng-scrollbar\n class=\"z-time-scroll-second-end h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowHour() && !zShowMinute()\"\n [class.rounded-r-sm]=\"zShowHour() || zShowMinute()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (sec of secondOptions; track sec) {\n @let secDisabled = sec | zIsEndSecondDisabled: endTimeContext();\n @let secEndSelected = sec === secondEnd();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!secDisabled && !secEndSelected\"\n [class.cursor-pointer]=\"!secDisabled\"\n [class.bg-primary]=\"secEndSelected\"\n [class.text-primary-foreground]=\"secEndSelected\"\n [class.font-medium]=\"secEndSelected\"\n [class.opacity-30]=\"secDisabled\"\n [class.cursor-not-allowed]=\"secDisabled\"\n [disabled]=\"secDisabled\"\n (click)=\"selectSecondEnd(sec)\">\n {{ sec | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n </div>\n</ng-template>\n", styles: [".animate-calendar-enter{animation:z-calendar-view-enter .2s ease-out}@keyframes z-calendar-view-enter{0%{opacity:0;transform:scale(.95) translateY(.25rem)}to{opacity:1;transform:scale(1) translateY(0)}}.z-calendar input{text-overflow:ellipsis;overflow:hidden}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: NgScrollbar, selector: "ng-scrollbar:not([externalViewport]), [ngScrollbar]", exportAs: ["ngScrollbar"] }, { kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zSize", "zStrokeWidth", "zSvg"] }, { kind: "component", type: ZSelectComponent, selector: "z-select", inputs: ["class", "zMode", "zSize", "zLabel", "zLabelClass", "zPlaceholder", "zRequired", "zDisabled", "zReadonly", "zLoading", "zPrefix", "zAllowClear", "zWrap", "zShowSearch", "zPlaceholderSearch", "zDebounce", "zNotFoundText", "zEmptyText", "zEmptyIcon", "zMaxTagCount", "zDropdownMaxHeight", "zOptionHeight", "zVirtualScroll", "zShowAction", "zOptions", "zConfig", "zTranslateLabels", "zKey", "zSearchServer", "zLoadingMore", "zEnableLoadMore", "zScrollDistance", "zMaxVisible", "zScrollClose", "zPosition", "zSelectedTemplate", "zOptionTemplate", "zActionTemplate", "zAsyncValidators", "zAsyncDebounce", "zAsyncValidateOn", "zValidators"], outputs: ["zOnSearch", "zOnLoadMore", "zOnBlur", "zOnFocus", "zControl", "zEvent"], exportAs: ["zSelect"] }, { kind: "directive", type: ZPopoverDirective, selector: "[z-popover]", inputs: ["zPopoverContent", "zPosition", "zTrigger", "zClass", "zShowDelay", "zHideDelay", "zDisabled", "zOffset", "zPopoverWidth", "zManualClose", "zScrollClose", "zShowArrow"], outputs: ["zShow", "zHide", "zHideStart", "zControl", "zPositionChange"], exportAs: ["zPopover"] }, { kind: "component", type: ZButtonComponent, selector: "z-button, button[z-button], a[z-button]", inputs: ["class", "zType", "zSize", "zShape", "zLabel", "zLoading", "zDisabled", "zTypeIcon", "zSizeIcon", "zStrokeWidthIcon", "zWave"], exportAs: ["zButton"] }, { kind: "pipe", type: DecimalPipe, name: "number" }, { kind: "pipe", type: ZDayClassesPipe, name: "zDayClasses" }, { kind: "pipe", type: ZMonthClassesPipe, name: "zMonthClasses" }, { kind: "pipe", type: ZQuarterClassesPipe, name: "zQuarterClasses" }, { kind: "pipe", type: ZYearClassesPipe, name: "zYearClasses" }, { kind: "pipe", type: ZIsPresetDisabledPipe, name: "zIsPresetDisabled" }, { kind: "pipe", type: ZIsEndHourDisabledPipe, name: "zIsEndHourDisabled" }, { kind: "pipe", type: ZIsEndMinuteDisabledPipe, name: "zIsEndMinuteDisabled" }, { kind: "pipe", type: ZIsEndSecondDisabledPipe, name: "zIsEndSecondDisabled" }, { kind: "pipe", type: ZIsStartMonthDisabledPipe, name: "zIsStartMonthDisabled" }, { kind: "pipe", type: ZIsEndMonthDisabledPipe, name: "zIsEndMonthDisabled" }, { kind: "pipe", type: ZIsStartYearDisabledPipe, name: "zIsStartYearDisabled" }, { kind: "pipe", type: ZIsEndYearDisabledPipe, name: "zIsEndYearDisabled" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2995
3032
  }
2996
3033
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZCalendarComponent, decorators: [{
2997
3034
  type: Component,
2998
3035
  args: [{ selector: 'z-calendar', imports: [
2999
3036
  DecimalPipe,
3037
+ FormsModule,
3000
3038
  NgScrollbar,
3001
3039
  ZIconComponent,
3040
+ ZSelectComponent,
3002
3041
  ZPopoverDirective,
3003
3042
  ZButtonComponent,
3004
3043
  ZDayClassesPipe,
@@ -3023,7 +3062,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImpor
3023
3062
  TranslatePipe,
3024
3063
  ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
3025
3064
  class: 'block min-w-0',
3026
- }, exportAs: 'zCalendar', template: "<div class=\"z-calendar-wrapper flex w-full flex-col gap-2\">\n @if (zLabel()) {\n <label [for]=\"pickerId\" class=\"text-xs leading-none font-medium\" [class]=\"zLabelClass()\">\n {{ zLabel() }}\n @if (zRequired()) {\n <span class=\"text-destructive! ml-0.5\">*</span>\n }\n </label>\n }\n\n <div class=\"relative\">\n <div\n #triggerEl\n z-popover\n [zPopoverContent]=\"calendarTpl\"\n zPosition=\"bottom-left\"\n zPopoverWidth=\"auto\"\n [zOffset]=\"6\"\n [zDisabled]=\"isDisabled() || zReadonly()\"\n [zManualClose]=\"showCancelButton()\"\n [zScrollClose]=\"zScrollClose()\"\n zTrigger=\"click\"\n zClass=\"border-0 shadow-none p-0\"\n (zHideStart)=\"onPopoverHide()\"\n (zShow)=\"onPopoverShow()\"\n (zControl)=\"onPopoverControl($event)\"\n [id]=\"pickerId\"\n [class]=\"triggerClasses()\"\n (keydown)=\"onTriggerKeydown($event)\">\n <z-icon\n [zType]=\"isRangeMode() ? 'lucideCalendarRange' : 'lucideCalendar'\"\n zSize=\"16\"\n class=\"text-muted-foreground shrink-0 cursor-pointer\"\n (click)=\"$event.stopPropagation(); toggle()\" />\n\n @if (isRangeMode()) {\n <input\n type=\"text\"\n data-range-type=\"start\"\n class=\"placeholder:text-muted-foreground w-0 min-w-0 flex-1 truncate bg-transparent text-center text-sm outline-none\"\n [placeholder]=\"'i18n_z_ui_calendar_start_date' | translate\"\n [value]=\"inputDisplayStart()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"zReadonly()\"\n (click)=\"isOpen() && $event.stopPropagation()\"\n (focus)=\"onInputFocus($event)\"\n (input)=\"onStartInputChange($event)\"\n (blur)=\"onInputBlur($event)\"\n (keydown.enter)=\"onStartInputEnter($event)\"\n (keydown.escape)=\"onStartInputEscape()\" />\n <span class=\"text-muted-foreground text-sm\">-</span>\n <input\n type=\"text\"\n data-range-type=\"end\"\n class=\"placeholder:text-muted-foreground w-0 min-w-0 flex-1 truncate bg-transparent text-center text-sm outline-none\"\n [placeholder]=\"'i18n_z_ui_calendar_end_date' | translate\"\n [value]=\"inputDisplayEnd()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"zReadonly()\"\n (click)=\"isOpen() && $event.stopPropagation()\"\n (focus)=\"onInputFocus($event)\"\n (input)=\"onEndInputChange($event)\"\n (blur)=\"onInputBlur($event)\"\n (keydown.enter)=\"onEndInputEnter($event)\"\n (keydown.escape)=\"onEndInputEscape()\" />\n } @else {\n <input\n #inputEl\n type=\"text\"\n class=\"placeholder:text-muted-foreground w-0 min-w-0 flex-1 truncate bg-transparent text-sm outline-none\"\n [placeholder]=\"effectivePlaceholder()\"\n [value]=\"inputDisplayValue()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"zReadonly()\"\n (click)=\"isOpen() && $event.stopPropagation()\"\n (focus)=\"onInputFocus($event)\"\n (input)=\"onInputChange($event)\"\n (blur)=\"onInputBlur($event)\"\n (keydown.enter)=\"onInputEnter($event)\"\n (keydown.escape)=\"onInputEscape()\" />\n }\n\n @if (zAllowClear() && !isDisabled() && !zReadonly()) {\n <button\n type=\"button\"\n tabindex=\"-1\"\n class=\"text-muted-foreground hover:text-foreground flex size-5 shrink-0 cursor-pointer items-center justify-center rounded-sm transition-all\"\n [class.opacity-0]=\"!hasValue()\"\n [class.pointer-events-none]=\"!hasValue()\"\n (click)=\"onClear($event)\">\n <z-icon zType=\"lucideX\" zSize=\"18\" />\n </button>\n }\n </div>\n </div>\n\n @if (hasError()) {\n <p class=\"text-destructive animate-in fade-in slide-in-from-top-1 m-0 text-xs duration-200\">\n {{ errorMessage() }}\n </p>\n }\n</div>\n\n<ng-template #calendarTpl>\n <div\n class=\"z-calendar-calendar bg-popover border-border flex max-h-[50dvh] max-w-[95vw] overflow-auto rounded-sm border shadow-lg min-[480px]:max-h-[55dvh] sm:max-h-none sm:max-w-none sm:flex-row sm:overflow-visible\"\n [class.flex-col]=\"!(zQuickSelect() && zMode() === 'range')\"\n [class.flex-row]=\"zQuickSelect() && zMode() === 'range'\"\n (keydown)=\"onCalendarKeydown($event)\">\n @if (zQuickSelect() && zMode() === 'range') {\n <div class=\"border-border flex shrink-0 flex-col gap-0 space-y-1 overflow-y-auto border-r p-2\">\n @for (preset of quickSelectPresets; track preset.key) {\n @let presetDisabled = preset | zIsPresetDisabled: zDisabledDate();\n <button\n type=\"button\"\n class=\"cursor-pointer rounded-sm px-3 py-1.5 text-left text-sm whitespace-nowrap transition-colors\"\n [class.hover:bg-muted]=\"activePresetKey() !== preset.key && !presetDisabled\"\n [class.bg-primary]=\"activePresetKey() === preset.key\"\n [class.text-primary-foreground]=\"activePresetKey() === preset.key\"\n [class.font-medium]=\"activePresetKey() === preset.key\"\n [class.opacity-40]=\"presetDisabled\"\n [class.cursor-not-allowed]=\"presetDisabled\"\n [disabled]=\"presetDisabled\"\n (click)=\"onQuickSelect(preset)\">\n {{ preset.label | translate }}\n </button>\n }\n </div>\n }\n <div\n class=\"flex flex-1 flex-col items-center overflow-auto py-2 sm:overflow-visible\"\n [class]=\"!isRangeMode() ? 'w-[17.5rem]' : ''\">\n @if (!isTimeMode()) {\n <div\n class=\"z-calendars-wrapper flex w-full flex-col items-center gap-3 sm:flex-row sm:items-stretch sm:justify-center sm:gap-0\">\n <!-- First Calendar -->\n <div class=\"z-calendar-section flex w-[17.5rem] shrink-0 flex-col\">\n @if (!isTimeMode()) {\n <!-- Header -->\n <div class=\"border-border flex w-full items-center justify-between gap-0.5 px-2\">\n <!-- Double left arrow (always visible) -->\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zWave]=\"false\"\n (click)=\"navigatePreviousFast()\">\n <z-icon zType=\"lucideChevronsLeft\" zSize=\"18\" />\n </button>\n\n <!-- Single left arrow (hidden in month/year view) -->\n @if (currentView() === 'day') {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zWave]=\"false\"\n (click)=\"navigatePrevious()\">\n <z-icon zType=\"lucideChevronLeft\" zSize=\"18\" />\n </button>\n }\n\n <!-- Header content -->\n <div class=\"flex flex-1 shrink-0 items-center justify-center gap-0\">\n @if (currentView() === 'day') {\n <!-- Day view: Month + Year -->\n @if (!isYearMode() && !isQuarterMode()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n (click)=\"setView('month')\">\n {{ currentMonthName() }}\n </button>\n }\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n [zDisabled]=\"isYearMode()\"\n (click)=\"setView('year')\">\n {{ currentYear() }}\n </button>\n } @else if (currentView() === 'month') {\n <!-- Month view: Only Year -->\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n (click)=\"setView('year')\">\n {{ currentYear() }}\n </button>\n } @else if (currentView() === 'year') {\n <!-- Year view: Year Range -->\n <span class=\"text-sm font-medium\">\n {{ yearRange()[0] }} - {{ yearRange()[yearRange().length - 1] }}\n </span>\n } @else if (currentView() === 'quarter') {\n <!-- Quarter view: Only Year -->\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n (click)=\"setView('year')\">\n {{ currentYear() }}\n </button>\n }\n </div>\n\n <!-- Single right arrow (hidden in month/year view) -->\n @if (currentView() === 'day') {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zDisabled]=\"!canNavigateStartNext()\"\n [zWave]=\"false\"\n (click)=\"navigateNext()\">\n <z-icon zType=\"lucideChevronRight\" zSize=\"18\" />\n </button>\n }\n\n <!-- Double right arrow (always visible) -->\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zDisabled]=\"!canNavigateStartNext()\"\n [zWave]=\"false\"\n (click)=\"navigateNextFast()\">\n <z-icon zType=\"lucideChevronsRight\" zSize=\"18\" />\n </button>\n </div>\n\n <!-- Body -->\n <div\n class=\"flex h-full w-full flex-col items-center justify-center p-2\"\n [class.min-h-[14rem]]=\"!isQuarterMode()\"\n [class.h-[14rem]]=\"\n !isYearMode() &&\n !isMonthMode() &&\n !isQuarterMode() &&\n (currentView() === 'month' || currentView() === 'year')\n \"\n [class.min-h-[6.25rem]]=\"isQuarterMode()\"\n [class.!min-h-auto]=\"isYearMode() || isMonthMode() || isQuarterMode()\"\n [class.!h-auto]=\"isYearMode() || isMonthMode() || isQuarterMode()\">\n @if (currentView() === 'day') {\n <div\n class=\"flex h-full w-full flex-1 flex-col gap-1\"\n [class.animate-calendar-enter]=\"uiState().hasViewChanged\">\n <!-- Weekday headers -->\n <div class=\"flex w-full flex-1 justify-center gap-1\">\n @for (weekday of weekdayNames(); track weekday) {\n <div\n class=\"text-muted-foreground flex h-[1.875rem] w-[2.0313rem] items-center justify-center text-xs font-medium\">\n {{ weekday }}\n </div>\n }\n </div>\n\n <!-- Date rows -->\n @for (week of calendarDays(); track $index) {\n <div class=\"flex w-full flex-1 justify-center gap-1\">\n @for (day of week; track day.date.getTime()) {\n <button\n type=\"button\"\n [class]=\"day | zDayClasses\"\n class=\"h-[1.875rem] !w-[2.0313rem] !text-sm\"\n [disabled]=\"day.isDisabled\"\n (click)=\"onDayClick(day)\"\n (mouseenter)=\"onDayHover(day)\"\n (mouseleave)=\"onDayLeave()\">\n {{ day.day }}\n </button>\n }\n </div>\n }\n </div>\n }\n @if (currentView() === 'month') {\n <div\n class=\"grid h-full w-full grid-cols-3 grid-rows-4 gap-2.5 gap-y-5!\"\n [class.animate-calendar-enter]=\"uiState().hasViewChanged\">\n @for (month of monthNames(); track month; let i = $index) {\n @let monthDisabled = i | zIsStartMonthDisabled: startMonthDisabledContext();\n <div class=\"flex flex-1 items-center justify-center\">\n <button\n type=\"button\"\n [class]=\"i | zMonthClasses: selectedMonthIndex() : todayMonthIndex()\"\n class=\"!h-7 !w-full !text-sm\"\n [disabled]=\"monthDisabled\"\n [class.opacity-30]=\"monthDisabled\"\n [class.cursor-not-allowed]=\"monthDisabled\"\n (click)=\"onMonthSelect(i)\">\n {{ month }}\n </button>\n </div>\n }\n </div>\n }\n\n @if (currentView() === 'year') {\n <div\n class=\"grid h-full w-full grid-cols-3 grid-rows-4 gap-2.5 gap-y-5!\"\n [class.animate-calendar-enter]=\"uiState().hasViewChanged\">\n @for (year of yearRange(); track year) {\n @let yearDisabled = year | zIsStartYearDisabled: startYearDisabledContext();\n <div class=\"flex flex-1 items-center justify-center\">\n <button\n type=\"button\"\n [class]=\"year | zYearClasses: selectedYear() : todayYear()\"\n class=\"!h-7 !w-full !text-sm\"\n [disabled]=\"yearDisabled\"\n [class.opacity-30]=\"yearDisabled\"\n [class.cursor-not-allowed]=\"yearDisabled\"\n (click)=\"onYearClick(year)\">\n {{ year }}\n </button>\n </div>\n }\n </div>\n }\n\n @if (currentView() === 'quarter') {\n <div\n class=\"grid h-full w-full grid-cols-2 grid-rows-2 gap-2 p-1\"\n [class.animate-calendar-enter]=\"uiState().hasViewChanged\">\n @for (quarter of quarterNames; track quarter; let i = $index) {\n <div class=\"flex flex-1 items-center justify-center\">\n <button\n type=\"button\"\n [class]=\"i | zQuarterClasses: selectedQuarterIndex() : todayQuarterIndex()\"\n class=\"!h-8 !w-full !text-sm\"\n (click)=\"onQuarterClick(i)\">\n {{ quarter }}\n </button>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Second Calendar (Range Mode Only) -->\n @if (isRangeMode()) {\n <!-- Divider -->\n <div class=\"border-border bg-border hidden self-stretch sm:block sm:w-px\"></div>\n <div class=\"border-border bg-border block h-px w-full sm:hidden\"></div>\n\n <div class=\"z-calendar-section flex w-[17.5rem] shrink-0 flex-col\">\n <!-- Header -->\n <div class=\"border-border flex w-full items-center justify-between gap-0.5 px-2\">\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zDisabled]=\"!canNavigateEndPrev()\"\n [zWave]=\"false\"\n (click)=\"navigateEndPreviousFast()\">\n <z-icon zType=\"lucideChevronsLeft\" zSize=\"18\" />\n </button>\n\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zDisabled]=\"!canNavigateEndPrev()\"\n [zWave]=\"false\"\n (click)=\"navigateEndPrevious()\">\n <z-icon zType=\"lucideChevronLeft\" zSize=\"18\" />\n </button>\n\n <div class=\"flex w-[7.5rem] shrink-0 items-center justify-center gap-0\">\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n (click)=\"setEndView('month')\">\n {{ endMonthName() }}\n </button>\n\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n (click)=\"setEndView('year')\">\n {{ endMonthYear() }}\n </button>\n </div>\n\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zWave]=\"false\"\n [zWave]=\"false\"\n (click)=\"navigateEndNext()\">\n <z-icon zType=\"lucideChevronRight\" zSize=\"18\" />\n </button>\n\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zWave]=\"false\"\n [zWave]=\"false\"\n (click)=\"navigateEndNextFast()\">\n <z-icon zType=\"lucideChevronsRight\" zSize=\"18\" />\n </button>\n </div>\n\n <!-- Body -->\n <div\n class=\"flex h-full min-h-[14rem] w-full flex-col items-center justify-center p-2\"\n [class.h-[14rem]]=\"endView() === 'month' || endView() === 'year'\">\n @if (endView() === 'day') {\n <div\n class=\"flex h-full w-full flex-1 flex-col gap-1\"\n [class.animate-calendar-enter]=\"uiState().hasEndViewChanged\">\n <!-- Weekday headers -->\n <div class=\"flex w-full flex-1 justify-center gap-1\">\n @for (weekday of weekdayNames(); track weekday) {\n <div\n class=\"text-muted-foreground flex h-[1.875rem] w-[2.0313rem] items-center justify-center text-xs font-medium\">\n {{ weekday }}\n </div>\n }\n </div>\n\n <!-- Date rows -->\n @for (week of calendarDaysEnd(); track $index) {\n <div class=\"flex w-full flex-1 justify-center gap-1\">\n @for (day of week; track day.date.getTime()) {\n <button\n type=\"button\"\n [class]=\"day | zDayClasses\"\n class=\"h-[1.875rem] !w-[2.0313rem] !text-sm\"\n [disabled]=\"day.isDisabled\"\n (click)=\"onDayClick(day)\"\n (mouseenter)=\"onDayHover(day)\"\n (mouseleave)=\"onDayLeave()\">\n {{ day.day }}\n </button>\n }\n </div>\n }\n </div>\n }\n @if (endView() === 'month') {\n <div\n class=\"grid h-full w-full grid-cols-3 grid-rows-4 gap-2.5 gap-y-5!\"\n [class.animate-calendar-enter]=\"uiState().hasEndViewChanged\">\n @for (month of monthNames(); track month; let i = $index) {\n @let endMonthDisabled = i | zIsEndMonthDisabled: endMonthDisabledContext();\n <div class=\"flex flex-1 items-center justify-center\">\n <button\n type=\"button\"\n [class]=\"i | zMonthClasses: endMonth().getMonth() : -1\"\n class=\"!h-7 !w-full !text-sm\"\n [disabled]=\"endMonthDisabled\"\n [class.opacity-30]=\"endMonthDisabled\"\n [class.cursor-not-allowed]=\"endMonthDisabled\"\n (click)=\"onEndMonthClick(i)\">\n {{ month }}\n </button>\n </div>\n }\n </div>\n }\n\n @if (endView() === 'year') {\n <div\n class=\"grid h-full w-full grid-cols-3 grid-rows-4 gap-2.5 gap-y-5!\"\n [class.animate-calendar-enter]=\"uiState().hasEndViewChanged\">\n @for (year of endYearRange(); track year) {\n @let endYearDisabled = year | zIsEndYearDisabled: endYearDisabledContext();\n <div class=\"flex flex-1 items-center justify-center\">\n <button\n type=\"button\"\n [class]=\"year | zYearClasses: endMonth().getFullYear() : -1\"\n class=\"!h-7 !w-full !text-sm\"\n [disabled]=\"endYearDisabled\"\n [class.opacity-30]=\"endYearDisabled\"\n [class.cursor-not-allowed]=\"endYearDisabled\"\n (click)=\"onEndYearClick(year)\">\n {{ year }}\n </button>\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n\n <!-- Compact Time Picker Below Calendar (Single Date) -->\n @if (!isRangeMode() && zShowTime()) {\n <div class=\"border-border w-full border-t text-center\">\n <div\n class=\"hover:bg-muted my-1 inline-flex cursor-pointer items-center rounded-sm px-2 py-1 transition-colors\"\n z-popover\n [zPopoverContent]=\"timeDropdownTpl\"\n zPosition=\"bottom\"\n zPopoverWidth=\"auto\"\n [zOffset]=\"4\"\n zTrigger=\"click\"\n zClass=\"border-border shadow-md\"\n (zShow)=\"onTimeDropdownShow()\">\n <div class=\"flex items-center justify-center gap-1\">\n <!-- Hour -->\n @if (zShowHour()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedHour() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowHour() && zShowMinute()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Minute -->\n @if (zShowMinute()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedMinute() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowMinute() && zShowSecond()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Second -->\n @if (zShowSecond()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedSecond() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n <!-- AM/PM Toggle -->\n @if (zTimeFormat() === '12h') {\n <button\n type=\"button\"\n class=\"bg-primary/10 text-primary hover:bg-primary/20 active:bg-primary/30 ml-1 flex w-8 cursor-pointer items-center justify-center rounded-sm border-none px-2 py-1 text-xs font-semibold transition-colors\"\n (click)=\"togglePeriod(); $event.stopPropagation()\">\n {{ period() }}\n </button>\n }\n </div>\n </div>\n </div>\n }\n\n <!-- Compact Time Pickers Below Calendars (Range Mode) -->\n @if (isRangeMode() && zShowTime()) {\n <div class=\"border-border flex w-full flex-col border-t sm:flex-row\">\n <!-- Start Time -->\n <div class=\"flex w-full flex-col items-center justify-center gap-1\">\n <div\n class=\"hover:bg-muted my-1 inline-flex cursor-pointer items-center rounded-sm px-2 py-1 transition-colors\"\n z-popover\n [zPopoverContent]=\"timeDropdownTpl\"\n zPosition=\"bottom\"\n zPopoverWidth=\"auto\"\n [zOffset]=\"4\"\n zTrigger=\"click\"\n zClass=\"border-border shadow-md\"\n (zShow)=\"onTimeDropdownShow()\">\n <div class=\"flex items-center justify-center gap-1\">\n <!-- Hour -->\n @if (zShowHour()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedHour() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowHour() && zShowMinute()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Minute -->\n @if (zShowMinute()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedMinute() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowMinute() && zShowSecond()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Second -->\n @if (zShowSecond()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedSecond() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n <!-- AM/PM Toggle -->\n @if (zTimeFormat() === '12h') {\n <button\n type=\"button\"\n class=\"bg-primary/10 text-primary hover:bg-primary/20 active:bg-primary/30 ml-1 flex w-8 cursor-pointer items-center justify-center rounded-sm border-none px-2 py-1 text-xs font-semibold transition-colors\"\n (click)=\"togglePeriod(); $event.stopPropagation()\">\n {{ period() }}\n </button>\n }\n </div>\n </div>\n </div>\n\n <!-- Divider space -->\n <div class=\"border-border bg-border h-px self-stretch sm:block sm:h-full sm:w-px\"></div>\n\n <!-- End Time -->\n <div class=\"flex w-full flex-col items-center justify-center gap-1\">\n <div\n class=\"hover:bg-muted my-1 inline-flex cursor-pointer items-center rounded-sm px-2 py-1 transition-colors\"\n z-popover\n [zPopoverContent]=\"timeDropdownEndTpl\"\n zPosition=\"bottom\"\n zPopoverWidth=\"auto\"\n [zOffset]=\"4\"\n zTrigger=\"click\"\n zClass=\"border-border shadow-md\"\n (zShow)=\"onTimeDropdownEndShow()\">\n <div class=\"flex items-center justify-center gap-1\">\n <!-- Hour -->\n @if (zShowHour()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementHourEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedHourEnd() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementHourEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowHour() && zShowMinute()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Minute -->\n @if (zShowMinute()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementMinuteEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedMinuteEnd() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementMinuteEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowMinute() && zShowSecond()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Second -->\n @if (zShowSecond()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementSecondEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedSecondEnd() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementSecondEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n <!-- AM/PM Toggle -->\n @if (zTimeFormat() === '12h') {\n <button\n type=\"button\"\n class=\"bg-primary/10 text-primary hover:bg-primary/20 active:bg-primary/30 ml-1 flex w-8 cursor-pointer items-center justify-center rounded-sm border-none px-2 py-1 text-xs font-semibold transition-colors\"\n (click)=\"togglePeriodEnd(); $event.stopPropagation()\">\n {{ periodEnd() }}\n </button>\n }\n </div>\n </div>\n </div>\n </div>\n }\n } @else {\n <!-- Time Only Mode - Compact Display -->\n <div class=\"flex flex-col items-center gap-3 pb-2\">\n <div\n class=\"hover:bg-muted inline-flex cursor-pointer items-center rounded-sm px-3 py-2 transition-colors\"\n z-popover\n [zPopoverContent]=\"timeDropdownTpl\"\n zPosition=\"bottom\"\n zPopoverWidth=\"auto\"\n [zOffset]=\"4\"\n zTrigger=\"click\"\n zClass=\"border-border shadow-md\"\n (zShow)=\"onTimeDropdownShow()\">\n <div class=\"flex items-center justify-center gap-1.5\">\n <!-- Hour -->\n @if (zShowHour()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-9 cursor-pointer flex-col items-center gap-0 rounded-sm px-1.5 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"16\" />\n </button>\n <span class=\"text-foreground min-w-6 text-center text-base leading-tight font-medium select-none\">\n {{ formattedHour() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"16\" />\n </button>\n </div>\n }\n @if (zShowHour() && zShowMinute()) {\n <span class=\"text-muted-foreground text-base font-medium\">:</span>\n }\n <!-- Minute -->\n @if (zShowMinute()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-9 cursor-pointer flex-col items-center gap-0 rounded-sm px-1.5 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"16\" />\n </button>\n <span class=\"text-foreground min-w-6 text-center text-base leading-tight font-medium select-none\">\n {{ formattedMinute() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"16\" />\n </button>\n </div>\n }\n @if (zShowMinute() && zShowSecond()) {\n <span class=\"text-muted-foreground text-base font-medium\">:</span>\n }\n <!-- Second -->\n @if (zShowSecond()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-9 cursor-pointer flex-col items-center gap-0 rounded-sm px-1.5 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"16\" />\n </button>\n <span class=\"text-foreground min-w-6 text-center text-base leading-tight font-medium select-none\">\n {{ formattedSecond() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"16\" />\n </button>\n </div>\n }\n <!-- AM/PM Toggle -->\n @if (zTimeFormat() === '12h') {\n <button\n type=\"button\"\n class=\"bg-primary/10 text-primary hover:bg-primary/20 active:bg-primary/30 ml-1 flex w-10 cursor-pointer items-center justify-center rounded-sm border-none px-2.5 py-1.5 text-sm font-semibold transition-colors\"\n (click)=\"togglePeriod(); $event.stopPropagation()\">\n {{ period() }}\n </button>\n }\n </div>\n </div>\n </div>\n }\n\n @if (!(zQuickSelect() && zMode() === 'range' && !showOkButton() && !showCancelButton())) {\n <div class=\"border-border flex w-full items-center justify-between gap-2 border-t px-2 pt-2\">\n @if (!zQuickSelect() || zMode() !== 'range') {\n <button type=\"button\" z-button zType=\"secondary\" zSize=\"sm\" [zWave]=\"false\" (click)=\"onTodayClick()\">\n {{ todayButtonText() }}\n </button>\n } @else {\n <div></div>\n }\n\n @if (showOkButton() || showCancelButton()) {\n <div class=\"flex items-center gap-2\">\n @if (showCancelButton()) {\n <button type=\"button\" z-button zType=\"outline\" zSize=\"sm\" (click)=\"onCancelClick()\">\n {{ zCancelText() ?? ('i18n_z_ui_calendar_cancel' | translate) }}\n </button>\n }\n @if (showOkButton()) {\n <button type=\"button\" z-button zSize=\"sm\" [zDisabled]=\"!canApply()\" (click)=\"onOkClick()\">\n {{ zOkText() ?? ('i18n_z_ui_calendar_ok' | translate) }}\n </button>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n</ng-template>\n\n<ng-template #timeDropdownTpl>\n <div class=\"bg-popover flex overflow-hidden rounded-sm\">\n @if (zShowHour()) {\n <div\n class=\"flex flex-col\"\n [class.border-r]=\"zShowMinute() || zShowSecond()\"\n [class.border-border]=\"zShowMinute() || zShowSecond()\">\n <ng-scrollbar\n class=\"z-time-scroll-hour h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowMinute() && !zShowSecond()\"\n [class.rounded-l-sm]=\"zShowMinute() || zShowSecond()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (hr of hourOptions(); track hr) {\n @let hrSelected = hr === displayHour();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 cursor-pointer items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!hrSelected\"\n [class.bg-primary]=\"hrSelected\"\n [class.text-primary-foreground]=\"hrSelected\"\n [class.font-medium]=\"hrSelected\"\n (click)=\"selectHour(hr)\">\n {{ hr | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n @if (zShowMinute()) {\n <div class=\"flex flex-col\" [class.border-r]=\"zShowSecond()\" [class.border-border]=\"zShowSecond()\">\n <ng-scrollbar\n class=\"z-time-scroll-minute h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowHour() && !zShowSecond()\"\n [class.rounded-l-sm]=\"!zShowHour() && zShowSecond()\"\n [class.rounded-r-sm]=\"zShowHour() && !zShowSecond()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (min of minuteOptions; track min) {\n @let minSelected = min === minute();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 cursor-pointer items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!minSelected\"\n [class.bg-primary]=\"minSelected\"\n [class.text-primary-foreground]=\"minSelected\"\n [class.font-medium]=\"minSelected\"\n (click)=\"selectMinute(min)\">\n {{ min | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n @if (zShowSecond()) {\n <div class=\"flex flex-col\">\n <ng-scrollbar\n class=\"z-time-scroll-second h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowHour() && !zShowMinute()\"\n [class.rounded-r-sm]=\"zShowHour() || zShowMinute()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (sec of secondOptions; track sec) {\n @let secSelected = sec === second();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 cursor-pointer items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!secSelected\"\n [class.bg-primary]=\"secSelected\"\n [class.text-primary-foreground]=\"secSelected\"\n [class.font-medium]=\"secSelected\"\n (click)=\"selectSecond(sec)\">\n {{ sec | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n </div>\n</ng-template>\n\n<ng-template #timeDropdownEndTpl>\n <div class=\"bg-popover flex overflow-hidden rounded-sm\">\n @if (zShowHour()) {\n <div\n class=\"flex flex-col\"\n [class.border-r]=\"zShowMinute() || zShowSecond()\"\n [class.border-border]=\"zShowMinute() || zShowSecond()\">\n <ng-scrollbar\n class=\"z-time-scroll-hour-end h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowMinute() && !zShowSecond()\"\n [class.rounded-l-sm]=\"zShowMinute() || zShowSecond()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (hr of hourOptions(); track hr) {\n @let hrDisabled = hr | zIsEndHourDisabled: endTimeContext();\n @let hrEndSelected = hr === displayHourEnd();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!hrDisabled && !hrEndSelected\"\n [class.cursor-pointer]=\"!hrDisabled\"\n [class.bg-primary]=\"hrEndSelected\"\n [class.text-primary-foreground]=\"hrEndSelected\"\n [class.font-medium]=\"hrEndSelected\"\n [class.opacity-30]=\"hrDisabled\"\n [class.cursor-not-allowed]=\"hrDisabled\"\n [disabled]=\"hrDisabled\"\n (click)=\"selectHourEnd(hr)\">\n {{ hr | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n @if (zShowMinute()) {\n <div class=\"flex flex-col\" [class.border-r]=\"zShowSecond()\" [class.border-border]=\"zShowSecond()\">\n <ng-scrollbar\n class=\"z-time-scroll-minute-end h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowHour() && !zShowSecond()\"\n [class.rounded-l-sm]=\"!zShowHour() && zShowSecond()\"\n [class.rounded-r-sm]=\"zShowHour() && !zShowSecond()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (min of minuteOptions; track min) {\n @let minDisabled = min | zIsEndMinuteDisabled: endTimeContext();\n @let minEndSelected = min === minuteEnd();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!minDisabled && !minEndSelected\"\n [class.cursor-pointer]=\"!minDisabled\"\n [class.bg-primary]=\"minEndSelected\"\n [class.text-primary-foreground]=\"minEndSelected\"\n [class.font-medium]=\"minEndSelected\"\n [class.opacity-30]=\"minDisabled\"\n [class.cursor-not-allowed]=\"minDisabled\"\n [disabled]=\"minDisabled\"\n (click)=\"selectMinuteEnd(min)\">\n {{ min | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n @if (zShowSecond()) {\n <div class=\"flex flex-col\">\n <ng-scrollbar\n class=\"z-time-scroll-second-end h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowHour() && !zShowMinute()\"\n [class.rounded-r-sm]=\"zShowHour() || zShowMinute()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (sec of secondOptions; track sec) {\n @let secDisabled = sec | zIsEndSecondDisabled: endTimeContext();\n @let secEndSelected = sec === secondEnd();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!secDisabled && !secEndSelected\"\n [class.cursor-pointer]=\"!secDisabled\"\n [class.bg-primary]=\"secEndSelected\"\n [class.text-primary-foreground]=\"secEndSelected\"\n [class.font-medium]=\"secEndSelected\"\n [class.opacity-30]=\"secDisabled\"\n [class.cursor-not-allowed]=\"secDisabled\"\n [disabled]=\"secDisabled\"\n (click)=\"selectSecondEnd(sec)\">\n {{ sec | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n </div>\n</ng-template>\n", styles: [".animate-calendar-enter{animation:z-calendar-view-enter .2s ease-out}@keyframes z-calendar-view-enter{0%{opacity:0;transform:scale(.95) translateY(.25rem)}to{opacity:1;transform:scale(1) translateY(0)}}.z-calendar input{text-overflow:ellipsis;overflow:hidden}\n"] }]
3065
+ }, exportAs: 'zCalendar', template: "<div class=\"z-calendar-wrapper flex w-full flex-col gap-2\">\n @if (zLabel()) {\n <label [for]=\"pickerId\" class=\"text-xs leading-none font-medium\" [class]=\"zLabelClass()\">\n {{ zLabel() }}\n @if (zRequired()) {\n <span class=\"text-destructive! ml-0.5\">*</span>\n }\n </label>\n }\n\n <div class=\"relative\">\n <div\n #triggerEl\n z-popover\n [zPopoverContent]=\"calendarTpl\"\n zPosition=\"bottom-left\"\n zPopoverWidth=\"auto\"\n [zOffset]=\"6\"\n [zDisabled]=\"isDisabled() || zReadonly()\"\n [zManualClose]=\"showCancelButton()\"\n [zScrollClose]=\"zScrollClose()\"\n zTrigger=\"click\"\n zClass=\"border-0 shadow-none p-0\"\n (zHideStart)=\"onPopoverHide()\"\n (zShow)=\"onPopoverShow()\"\n (zControl)=\"onPopoverControl($event)\"\n [id]=\"pickerId\"\n [class]=\"triggerClasses()\"\n (keydown)=\"onTriggerKeydown($event)\">\n <z-icon\n [zType]=\"isRangeMode() ? 'lucideCalendarRange' : 'lucideCalendar'\"\n zSize=\"16\"\n class=\"text-muted-foreground shrink-0 cursor-pointer\"\n (click)=\"$event.stopPropagation(); toggle()\" />\n\n @if (isRangeMode()) {\n <input\n type=\"text\"\n data-range-type=\"start\"\n class=\"placeholder:text-muted-foreground w-0 min-w-0 flex-1 truncate bg-transparent text-center text-sm outline-none\"\n [placeholder]=\"'i18n_z_ui_calendar_start_date' | translate\"\n [value]=\"inputDisplayStart()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"zReadonly()\"\n (click)=\"isOpen() && $event.stopPropagation()\"\n (focus)=\"onInputFocus($event)\"\n (input)=\"onStartInputChange($event)\"\n (blur)=\"onInputBlur($event)\"\n (keydown.enter)=\"onStartInputEnter($event)\"\n (keydown.escape)=\"onStartInputEscape()\" />\n <span class=\"text-muted-foreground text-sm\">-</span>\n <input\n type=\"text\"\n data-range-type=\"end\"\n class=\"placeholder:text-muted-foreground w-0 min-w-0 flex-1 truncate bg-transparent text-center text-sm outline-none\"\n [placeholder]=\"'i18n_z_ui_calendar_end_date' | translate\"\n [value]=\"inputDisplayEnd()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"zReadonly()\"\n (click)=\"isOpen() && $event.stopPropagation()\"\n (focus)=\"onInputFocus($event)\"\n (input)=\"onEndInputChange($event)\"\n (blur)=\"onInputBlur($event)\"\n (keydown.enter)=\"onEndInputEnter($event)\"\n (keydown.escape)=\"onEndInputEscape()\" />\n } @else {\n <input\n #inputEl\n type=\"text\"\n class=\"placeholder:text-muted-foreground w-0 min-w-0 flex-1 truncate bg-transparent text-sm outline-none\"\n [placeholder]=\"effectivePlaceholder()\"\n [value]=\"inputDisplayValue()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"zReadonly()\"\n (click)=\"isOpen() && $event.stopPropagation()\"\n (focus)=\"onInputFocus($event)\"\n (input)=\"onInputChange($event)\"\n (blur)=\"onInputBlur($event)\"\n (keydown.enter)=\"onInputEnter($event)\"\n (keydown.escape)=\"onInputEscape()\" />\n }\n\n @if (zAllowClear() && !isDisabled() && !zReadonly()) {\n <button\n type=\"button\"\n tabindex=\"-1\"\n class=\"text-muted-foreground hover:text-foreground flex size-5 shrink-0 cursor-pointer items-center justify-center rounded-sm transition-all\"\n [class.opacity-0]=\"!hasValue()\"\n [class.pointer-events-none]=\"!hasValue()\"\n (click)=\"onClear($event)\">\n <z-icon zType=\"lucideX\" zSize=\"18\" />\n </button>\n }\n </div>\n </div>\n\n @if (hasError()) {\n <p class=\"text-destructive animate-in fade-in slide-in-from-top-1 m-0 text-xs duration-200\">\n {{ errorMessage() }}\n </p>\n }\n</div>\n\n<ng-template #calendarTpl>\n <div\n class=\"z-calendar-calendar bg-popover border-border flex max-h-[50dvh] max-w-[calc(100vw-1.5rem)] flex-col overflow-hidden rounded-sm border shadow-lg min-[480px]:max-h-[55dvh] sm:max-h-none sm:max-w-none sm:flex-row sm:overflow-visible\"\n (keydown)=\"onCalendarKeydown($event)\">\n @if (zQuickSelect() && zMode() === 'range') {\n <div class=\"border-border hidden shrink-0 flex-col gap-0 space-y-1 overflow-y-auto border-r p-2 sm:flex\">\n @for (preset of quickSelectPresets; track preset.key) {\n @let presetDisabled = preset | zIsPresetDisabled: zDisabledDate();\n <button\n type=\"button\"\n class=\"cursor-pointer rounded-sm px-3 py-1.5 text-left text-sm whitespace-nowrap transition-colors\"\n [class.hover:bg-muted]=\"activePresetKey() !== preset.key && !presetDisabled\"\n [class.bg-primary]=\"activePresetKey() === preset.key\"\n [class.text-primary-foreground]=\"activePresetKey() === preset.key\"\n [class.font-medium]=\"activePresetKey() === preset.key\"\n [class.opacity-40]=\"presetDisabled\"\n [class.cursor-not-allowed]=\"presetDisabled\"\n [disabled]=\"presetDisabled\"\n (click)=\"onQuickSelect(preset)\">\n {{ preset.label | translate }}\n </button>\n }\n </div>\n }\n <div\n class=\"flex min-h-0 flex-1 flex-col items-center overflow-hidden pb-0 sm:overflow-visible sm:py-2\"\n [class]=\"\n !isRangeMode()\n ? 'w-[17.75rem] max-w-[calc(100vw-1.5rem)]'\n : 'w-[17.75rem] max-w-[calc(100vw-1.5rem)] sm:w-auto sm:max-w-none'\n \">\n @if (zQuickSelect() && zMode() === 'range') {\n <div class=\"border-border w-full border-b px-2 pt-2 pb-2 sm:hidden\">\n <z-select\n class=\"w-full\"\n zSize=\"sm\"\n zPosition=\"bottom-left\"\n [zShowSearch]=\"false\"\n [zAllowClear]=\"false\"\n [zOptions]=\"quickSelectOptions()\"\n [ngModel]=\"activePresetKey()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"onQuickSelectKeyChange($event)\" />\n </div>\n }\n <div class=\"min-h-0 w-full flex-1 overflow-x-hidden overflow-y-auto pt-2 sm:overflow-visible sm:pt-0\">\n @if (!isTimeMode()) {\n <div\n class=\"z-calendars-wrapper flex w-full flex-col items-center gap-0 sm:flex-row sm:items-stretch sm:justify-center\">\n <!-- First Calendar -->\n <div class=\"z-calendar-section flex w-[17.5rem] shrink-0 flex-col\">\n @if (!isTimeMode()) {\n <!-- Header -->\n <div class=\"border-border flex w-full items-center justify-between gap-0.5 px-2\">\n <!-- Double left arrow (always visible) -->\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zWave]=\"false\"\n (click)=\"navigatePreviousFast()\">\n <z-icon zType=\"lucideChevronsLeft\" zSize=\"18\" />\n </button>\n\n <!-- Single left arrow (hidden in month/year view) -->\n @if (currentView() === 'day') {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zWave]=\"false\"\n (click)=\"navigatePrevious()\">\n <z-icon zType=\"lucideChevronLeft\" zSize=\"18\" />\n </button>\n }\n\n <!-- Header content -->\n <div class=\"flex flex-1 shrink-0 items-center justify-center gap-0\">\n @if (currentView() === 'day') {\n <!-- Day view: Month + Year -->\n @if (!isYearMode() && !isQuarterMode()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n (click)=\"setView('month')\">\n {{ currentMonthName() }}\n </button>\n }\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n [zDisabled]=\"isYearMode()\"\n (click)=\"setView('year')\">\n {{ currentYear() }}\n </button>\n } @else if (currentView() === 'month') {\n <!-- Month view: Only Year -->\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n (click)=\"setView('year')\">\n {{ currentYear() }}\n </button>\n } @else if (currentView() === 'year') {\n <!-- Year view: Year Range -->\n <span class=\"text-sm font-medium\">\n {{ yearRange()[0] }} - {{ yearRange()[yearRange().length - 1] }}\n </span>\n } @else if (currentView() === 'quarter') {\n <!-- Quarter view: Only Year -->\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n (click)=\"setView('year')\">\n {{ currentYear() }}\n </button>\n }\n </div>\n\n <!-- Single right arrow (hidden in month/year view) -->\n @if (currentView() === 'day') {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zDisabled]=\"!canNavigateStartNext()\"\n [zWave]=\"false\"\n (click)=\"navigateNext()\">\n <z-icon zType=\"lucideChevronRight\" zSize=\"18\" />\n </button>\n }\n\n <!-- Double right arrow (always visible) -->\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zDisabled]=\"!canNavigateStartNext()\"\n [zWave]=\"false\"\n (click)=\"navigateNextFast()\">\n <z-icon zType=\"lucideChevronsRight\" zSize=\"18\" />\n </button>\n </div>\n\n <!-- Body -->\n <div\n class=\"flex h-full w-full flex-col items-center justify-center p-2\"\n [class.min-h-[14rem]]=\"!isQuarterMode()\"\n [class.h-[14rem]]=\"\n !isYearMode() &&\n !isMonthMode() &&\n !isQuarterMode() &&\n (currentView() === 'month' || currentView() === 'year')\n \"\n [class.min-h-[6.25rem]]=\"isQuarterMode()\"\n [class.!min-h-auto]=\"isYearMode() || isMonthMode() || isQuarterMode()\"\n [class.!h-auto]=\"isYearMode() || isMonthMode() || isQuarterMode()\">\n @if (currentView() === 'day') {\n <div\n class=\"flex h-full w-full flex-1 flex-col gap-1\"\n [class.animate-calendar-enter]=\"uiState().hasViewChanged\">\n <!-- Weekday headers -->\n <div class=\"flex w-full flex-1 justify-center gap-1\">\n @for (weekday of weekdayNames(); track weekday) {\n <div\n class=\"text-muted-foreground flex h-[1.875rem] w-[2.0313rem] items-center justify-center text-xs font-medium\">\n {{ weekday }}\n </div>\n }\n </div>\n\n <!-- Date rows -->\n @for (week of calendarDays(); track $index) {\n <div class=\"flex w-full flex-1 justify-center gap-1\">\n @for (day of week; track day.date.getTime()) {\n <button\n type=\"button\"\n [class]=\"day | zDayClasses\"\n class=\"h-[1.875rem] !w-[2.0313rem] !text-sm\"\n [disabled]=\"day.isDisabled\"\n (click)=\"onDayClick(day)\"\n (mouseenter)=\"onDayHover(day)\"\n (mouseleave)=\"onDayLeave()\">\n {{ day.day }}\n </button>\n }\n </div>\n }\n </div>\n }\n @if (currentView() === 'month') {\n <div\n class=\"grid h-full w-full grid-cols-3 grid-rows-4 gap-2.5 gap-y-5!\"\n [class.animate-calendar-enter]=\"uiState().hasViewChanged\">\n @for (month of monthNames(); track month; let i = $index) {\n @let monthDisabled = i | zIsStartMonthDisabled: startMonthDisabledContext();\n <div class=\"flex flex-1 items-center justify-center\">\n <button\n type=\"button\"\n [class]=\"i | zMonthClasses: selectedMonthIndex() : todayMonthIndex()\"\n class=\"!h-7 !w-full !text-sm\"\n [disabled]=\"monthDisabled\"\n [class.opacity-30]=\"monthDisabled\"\n [class.cursor-not-allowed]=\"monthDisabled\"\n (click)=\"onMonthSelect(i)\">\n {{ month }}\n </button>\n </div>\n }\n </div>\n }\n\n @if (currentView() === 'year') {\n <div\n class=\"grid h-full w-full grid-cols-3 grid-rows-4 gap-2.5 gap-y-5!\"\n [class.animate-calendar-enter]=\"uiState().hasViewChanged\">\n @for (year of yearRange(); track year) {\n @let yearDisabled = year | zIsStartYearDisabled: startYearDisabledContext();\n <div class=\"flex flex-1 items-center justify-center\">\n <button\n type=\"button\"\n [class]=\"year | zYearClasses: selectedYear() : todayYear()\"\n class=\"!h-7 !w-full !text-sm\"\n [disabled]=\"yearDisabled\"\n [class.opacity-30]=\"yearDisabled\"\n [class.cursor-not-allowed]=\"yearDisabled\"\n (click)=\"onYearClick(year)\">\n {{ year }}\n </button>\n </div>\n }\n </div>\n }\n\n @if (currentView() === 'quarter') {\n <div\n class=\"grid h-full w-full grid-cols-2 grid-rows-2 gap-2 p-1\"\n [class.animate-calendar-enter]=\"uiState().hasViewChanged\">\n @for (quarter of quarterNames; track quarter; let i = $index) {\n <div class=\"flex flex-1 items-center justify-center\">\n <button\n type=\"button\"\n [class]=\"i | zQuarterClasses: selectedQuarterIndex() : todayQuarterIndex()\"\n class=\"!h-8 !w-full !text-sm\"\n (click)=\"onQuarterClick(i)\">\n {{ quarter }}\n </button>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Second Calendar (Range Mode Only) -->\n @if (isRangeMode()) {\n <!-- Divider -->\n <div class=\"border-border bg-border hidden self-stretch sm:block sm:w-px\"></div>\n <div class=\"border-border bg-border block h-px w-full sm:hidden\"></div>\n\n <div class=\"z-calendar-section flex w-[17.5rem] shrink-0 flex-col pt-2 sm:pt-0\">\n <!-- Header -->\n <div class=\"border-border flex w-full items-center justify-between gap-0.5 px-2\">\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zDisabled]=\"!canNavigateEndPrev()\"\n [zWave]=\"false\"\n (click)=\"navigateEndPreviousFast()\">\n <z-icon zType=\"lucideChevronsLeft\" zSize=\"18\" />\n </button>\n\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zDisabled]=\"!canNavigateEndPrev()\"\n [zWave]=\"false\"\n (click)=\"navigateEndPrevious()\">\n <z-icon zType=\"lucideChevronLeft\" zSize=\"18\" />\n </button>\n\n <div class=\"flex w-[7.5rem] shrink-0 items-center justify-center gap-0\">\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n (click)=\"setEndView('month')\">\n {{ endMonthName() }}\n </button>\n\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"h-7 px-1.5 text-sm!\"\n [zWave]=\"false\"\n (click)=\"setEndView('year')\">\n {{ endMonthYear() }}\n </button>\n </div>\n\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zWave]=\"false\"\n [zWave]=\"false\"\n (click)=\"navigateEndNext()\">\n <z-icon zType=\"lucideChevronRight\" zSize=\"18\" />\n </button>\n\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n class=\"size-7 shrink-0 p-0!\"\n [zWave]=\"false\"\n [zWave]=\"false\"\n (click)=\"navigateEndNextFast()\">\n <z-icon zType=\"lucideChevronsRight\" zSize=\"18\" />\n </button>\n </div>\n\n <!-- Body -->\n <div\n class=\"flex h-full min-h-[14rem] w-full flex-col items-center justify-center p-2\"\n [class.h-[14rem]]=\"endView() === 'month' || endView() === 'year'\">\n @if (endView() === 'day') {\n <div\n class=\"flex h-full w-full flex-1 flex-col gap-1\"\n [class.animate-calendar-enter]=\"uiState().hasEndViewChanged\">\n <!-- Weekday headers -->\n <div class=\"flex w-full flex-1 justify-center gap-1\">\n @for (weekday of weekdayNames(); track weekday) {\n <div\n class=\"text-muted-foreground flex h-[1.875rem] w-[2.0313rem] items-center justify-center text-xs font-medium\">\n {{ weekday }}\n </div>\n }\n </div>\n\n <!-- Date rows -->\n @for (week of calendarDaysEnd(); track $index) {\n <div class=\"flex w-full flex-1 justify-center gap-1\">\n @for (day of week; track day.date.getTime()) {\n <button\n type=\"button\"\n [class]=\"day | zDayClasses\"\n class=\"h-[1.875rem] !w-[2.0313rem] !text-sm\"\n [disabled]=\"day.isDisabled\"\n (click)=\"onDayClick(day)\"\n (mouseenter)=\"onDayHover(day)\"\n (mouseleave)=\"onDayLeave()\">\n {{ day.day }}\n </button>\n }\n </div>\n }\n </div>\n }\n @if (endView() === 'month') {\n <div\n class=\"grid h-full w-full grid-cols-3 grid-rows-4 gap-2.5 gap-y-5!\"\n [class.animate-calendar-enter]=\"uiState().hasEndViewChanged\">\n @for (month of monthNames(); track month; let i = $index) {\n @let endMonthDisabled = i | zIsEndMonthDisabled: endMonthDisabledContext();\n <div class=\"flex flex-1 items-center justify-center\">\n <button\n type=\"button\"\n [class]=\"i | zMonthClasses: endMonth().getMonth() : -1\"\n class=\"!h-7 !w-full !text-sm\"\n [disabled]=\"endMonthDisabled\"\n [class.opacity-30]=\"endMonthDisabled\"\n [class.cursor-not-allowed]=\"endMonthDisabled\"\n (click)=\"onEndMonthClick(i)\">\n {{ month }}\n </button>\n </div>\n }\n </div>\n }\n\n @if (endView() === 'year') {\n <div\n class=\"grid h-full w-full grid-cols-3 grid-rows-4 gap-2.5 gap-y-5!\"\n [class.animate-calendar-enter]=\"uiState().hasEndViewChanged\">\n @for (year of endYearRange(); track year) {\n @let endYearDisabled = year | zIsEndYearDisabled: endYearDisabledContext();\n <div class=\"flex flex-1 items-center justify-center\">\n <button\n type=\"button\"\n [class]=\"year | zYearClasses: endMonth().getFullYear() : -1\"\n class=\"!h-7 !w-full !text-sm\"\n [disabled]=\"endYearDisabled\"\n [class.opacity-30]=\"endYearDisabled\"\n [class.cursor-not-allowed]=\"endYearDisabled\"\n (click)=\"onEndYearClick(year)\">\n {{ year }}\n </button>\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n\n <!-- Compact Time Picker Below Calendar (Single Date) -->\n @if (!isRangeMode() && zShowTime()) {\n <div class=\"border-border w-full border-t text-center\">\n <div\n class=\"hover:bg-muted my-1 inline-flex cursor-pointer items-center rounded-sm px-2 py-1 transition-colors\"\n z-popover\n [zPopoverContent]=\"timeDropdownTpl\"\n zPosition=\"bottom\"\n zPopoverWidth=\"auto\"\n [zOffset]=\"4\"\n zTrigger=\"click\"\n zClass=\"border-border shadow-md\"\n (zShow)=\"onTimeDropdownShow()\">\n <div class=\"flex items-center justify-center gap-1\">\n <!-- Hour -->\n @if (zShowHour()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedHour() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowHour() && zShowMinute()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Minute -->\n @if (zShowMinute()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedMinute() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowMinute() && zShowSecond()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Second -->\n @if (zShowSecond()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedSecond() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n <!-- AM/PM Toggle -->\n @if (zTimeFormat() === '12h') {\n <button\n type=\"button\"\n class=\"bg-primary/10 text-primary hover:bg-primary/20 active:bg-primary/30 ml-1 flex w-8 cursor-pointer items-center justify-center rounded-sm border-none px-2 py-1 text-xs font-semibold transition-colors\"\n (click)=\"togglePeriod(); $event.stopPropagation()\">\n {{ period() }}\n </button>\n }\n </div>\n </div>\n </div>\n }\n\n <!-- Compact Time Pickers Below Calendars (Range Mode) -->\n @if (isRangeMode() && zShowTime()) {\n <div class=\"border-border flex w-full flex-col border-t sm:flex-row\">\n <!-- Start Time -->\n <div class=\"flex w-full flex-col items-center justify-center gap-1\">\n <div\n class=\"hover:bg-muted my-1 inline-flex cursor-pointer items-center rounded-sm px-2 py-1 transition-colors\"\n z-popover\n [zPopoverContent]=\"timeDropdownTpl\"\n zPosition=\"bottom\"\n zPopoverWidth=\"auto\"\n [zOffset]=\"4\"\n zTrigger=\"click\"\n zClass=\"border-border shadow-md\"\n (zShow)=\"onTimeDropdownShow()\">\n <div class=\"flex items-center justify-center gap-1\">\n <!-- Hour -->\n @if (zShowHour()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedHour() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowHour() && zShowMinute()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Minute -->\n @if (zShowMinute()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedMinute() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowMinute() && zShowSecond()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Second -->\n @if (zShowSecond()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedSecond() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n <!-- AM/PM Toggle -->\n @if (zTimeFormat() === '12h') {\n <button\n type=\"button\"\n class=\"bg-primary/10 text-primary hover:bg-primary/20 active:bg-primary/30 ml-1 flex w-8 cursor-pointer items-center justify-center rounded-sm border-none px-2 py-1 text-xs font-semibold transition-colors\"\n (click)=\"togglePeriod(); $event.stopPropagation()\">\n {{ period() }}\n </button>\n }\n </div>\n </div>\n </div>\n\n <!-- Divider space -->\n <div class=\"border-border bg-border h-px self-stretch sm:block sm:h-full sm:w-px\"></div>\n\n <!-- End Time -->\n <div class=\"flex w-full flex-col items-center justify-center gap-1\">\n <div\n class=\"hover:bg-muted my-1 inline-flex cursor-pointer items-center rounded-sm px-2 py-1 transition-colors\"\n z-popover\n [zPopoverContent]=\"timeDropdownEndTpl\"\n zPosition=\"bottom\"\n zPopoverWidth=\"auto\"\n [zOffset]=\"4\"\n zTrigger=\"click\"\n zClass=\"border-border shadow-md\"\n (zShow)=\"onTimeDropdownEndShow()\">\n <div class=\"flex items-center justify-center gap-1\">\n <!-- Hour -->\n @if (zShowHour()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementHourEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedHourEnd() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementHourEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowHour() && zShowMinute()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Minute -->\n @if (zShowMinute()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementMinuteEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedMinuteEnd() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementMinuteEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n @if (zShowMinute() && zShowSecond()) {\n <span class=\"text-muted-foreground text-sm font-medium\">:</span>\n }\n <!-- Second -->\n @if (zShowSecond()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-7 cursor-pointer flex-col items-center gap-0 rounded-sm px-1 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementSecondEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"18\" />\n </button>\n <span class=\"text-foreground min-w-5 text-center text-sm leading-tight font-medium select-none\">\n {{ formattedSecondEnd() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-0.5 flex h-4 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementSecondEnd(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"18\" />\n </button>\n </div>\n }\n <!-- AM/PM Toggle -->\n @if (zTimeFormat() === '12h') {\n <button\n type=\"button\"\n class=\"bg-primary/10 text-primary hover:bg-primary/20 active:bg-primary/30 ml-1 flex w-8 cursor-pointer items-center justify-center rounded-sm border-none px-2 py-1 text-xs font-semibold transition-colors\"\n (click)=\"togglePeriodEnd(); $event.stopPropagation()\">\n {{ periodEnd() }}\n </button>\n }\n </div>\n </div>\n </div>\n </div>\n }\n } @else {\n <!-- Time Only Mode - Compact Display -->\n <div class=\"flex flex-col items-center gap-3 pb-2\">\n <div\n class=\"hover:bg-muted inline-flex cursor-pointer items-center rounded-sm px-3 py-2 transition-colors\"\n z-popover\n [zPopoverContent]=\"timeDropdownTpl\"\n zPosition=\"bottom\"\n zPopoverWidth=\"auto\"\n [zOffset]=\"4\"\n zTrigger=\"click\"\n zClass=\"border-border shadow-md\"\n (zShow)=\"onTimeDropdownShow()\">\n <div class=\"flex items-center justify-center gap-1.5\">\n <!-- Hour -->\n @if (zShowHour()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-9 cursor-pointer flex-col items-center gap-0 rounded-sm px-1.5 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"16\" />\n </button>\n <span class=\"text-foreground min-w-6 text-center text-base leading-tight font-medium select-none\">\n {{ formattedHour() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementHour(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"16\" />\n </button>\n </div>\n }\n @if (zShowHour() && zShowMinute()) {\n <span class=\"text-muted-foreground text-base font-medium\">:</span>\n }\n <!-- Minute -->\n @if (zShowMinute()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-9 cursor-pointer flex-col items-center gap-0 rounded-sm px-1.5 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"16\" />\n </button>\n <span class=\"text-foreground min-w-6 text-center text-base leading-tight font-medium select-none\">\n {{ formattedMinute() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementMinute(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"16\" />\n </button>\n </div>\n }\n @if (zShowMinute() && zShowSecond()) {\n <span class=\"text-muted-foreground text-base font-medium\">:</span>\n }\n <!-- Second -->\n @if (zShowSecond()) {\n <div\n class=\"hover:bg-muted/50 flex min-w-9 cursor-pointer flex-col items-center gap-0 rounded-sm px-1.5 transition-colors\">\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mb-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"decrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"16\" />\n </button>\n <span class=\"text-foreground min-w-6 text-center text-base leading-tight font-medium select-none\">\n {{ formattedSecond() }}\n </span>\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground active:bg-accent mt-1 flex h-5 w-full cursor-pointer items-center justify-center rounded-sm border-none bg-transparent transition-colors\"\n (click)=\"incrementSecond(); $event.stopPropagation()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"16\" />\n </button>\n </div>\n }\n <!-- AM/PM Toggle -->\n @if (zTimeFormat() === '12h') {\n <button\n type=\"button\"\n class=\"bg-primary/10 text-primary hover:bg-primary/20 active:bg-primary/30 ml-1 flex w-10 cursor-pointer items-center justify-center rounded-sm border-none px-2.5 py-1.5 text-sm font-semibold transition-colors\"\n (click)=\"togglePeriod(); $event.stopPropagation()\">\n {{ period() }}\n </button>\n }\n </div>\n </div>\n </div>\n }\n </div>\n\n @if (!(zQuickSelect() && zMode() === 'range' && !showOkButton() && !showCancelButton())) {\n <div\n class=\"bg-popover border-border z-10 flex w-full shrink-0 items-center justify-between gap-2 border-t px-2 py-2 shadow-[0_-2px_8px_-2px_rgb(0_0_0_/_10%)] sm:pt-2 sm:pb-0 sm:shadow-none\">\n @if (!zQuickSelect() || zMode() !== 'range') {\n <button type=\"button\" z-button zType=\"secondary\" zSize=\"sm\" [zWave]=\"false\" (click)=\"onTodayClick()\">\n {{ todayButtonText() }}\n </button>\n } @else {\n <div></div>\n }\n\n @if (showOkButton() || showCancelButton()) {\n <div class=\"flex items-center gap-2\">\n @if (showCancelButton()) {\n <button type=\"button\" z-button zType=\"outline\" zSize=\"sm\" (click)=\"onCancelClick()\">\n {{ zCancelText() ?? ('i18n_z_ui_calendar_cancel' | translate) }}\n </button>\n }\n @if (showOkButton()) {\n <button type=\"button\" z-button zSize=\"sm\" [zDisabled]=\"!canApply()\" (click)=\"onOkClick()\">\n {{ zOkText() ?? ('i18n_z_ui_calendar_ok' | translate) }}\n </button>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n</ng-template>\n\n<ng-template #timeDropdownTpl>\n <div class=\"bg-popover flex overflow-hidden rounded-sm\">\n @if (zShowHour()) {\n <div\n class=\"flex flex-col\"\n [class.border-r]=\"zShowMinute() || zShowSecond()\"\n [class.border-border]=\"zShowMinute() || zShowSecond()\">\n <ng-scrollbar\n class=\"z-time-scroll-hour h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowMinute() && !zShowSecond()\"\n [class.rounded-l-sm]=\"zShowMinute() || zShowSecond()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (hr of hourOptions(); track hr) {\n @let hrSelected = hr === displayHour();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 cursor-pointer items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!hrSelected\"\n [class.bg-primary]=\"hrSelected\"\n [class.text-primary-foreground]=\"hrSelected\"\n [class.font-medium]=\"hrSelected\"\n (click)=\"selectHour(hr)\">\n {{ hr | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n @if (zShowMinute()) {\n <div class=\"flex flex-col\" [class.border-r]=\"zShowSecond()\" [class.border-border]=\"zShowSecond()\">\n <ng-scrollbar\n class=\"z-time-scroll-minute h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowHour() && !zShowSecond()\"\n [class.rounded-l-sm]=\"!zShowHour() && zShowSecond()\"\n [class.rounded-r-sm]=\"zShowHour() && !zShowSecond()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (min of minuteOptions; track min) {\n @let minSelected = min === minute();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 cursor-pointer items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!minSelected\"\n [class.bg-primary]=\"minSelected\"\n [class.text-primary-foreground]=\"minSelected\"\n [class.font-medium]=\"minSelected\"\n (click)=\"selectMinute(min)\">\n {{ min | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n @if (zShowSecond()) {\n <div class=\"flex flex-col\">\n <ng-scrollbar\n class=\"z-time-scroll-second h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowHour() && !zShowMinute()\"\n [class.rounded-r-sm]=\"zShowHour() || zShowMinute()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (sec of secondOptions; track sec) {\n @let secSelected = sec === second();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 cursor-pointer items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!secSelected\"\n [class.bg-primary]=\"secSelected\"\n [class.text-primary-foreground]=\"secSelected\"\n [class.font-medium]=\"secSelected\"\n (click)=\"selectSecond(sec)\">\n {{ sec | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n </div>\n</ng-template>\n\n<ng-template #timeDropdownEndTpl>\n <div class=\"bg-popover flex overflow-hidden rounded-sm\">\n @if (zShowHour()) {\n <div\n class=\"flex flex-col\"\n [class.border-r]=\"zShowMinute() || zShowSecond()\"\n [class.border-border]=\"zShowMinute() || zShowSecond()\">\n <ng-scrollbar\n class=\"z-time-scroll-hour-end h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowMinute() && !zShowSecond()\"\n [class.rounded-l-sm]=\"zShowMinute() || zShowSecond()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (hr of hourOptions(); track hr) {\n @let hrDisabled = hr | zIsEndHourDisabled: endTimeContext();\n @let hrEndSelected = hr === displayHourEnd();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!hrDisabled && !hrEndSelected\"\n [class.cursor-pointer]=\"!hrDisabled\"\n [class.bg-primary]=\"hrEndSelected\"\n [class.text-primary-foreground]=\"hrEndSelected\"\n [class.font-medium]=\"hrEndSelected\"\n [class.opacity-30]=\"hrDisabled\"\n [class.cursor-not-allowed]=\"hrDisabled\"\n [disabled]=\"hrDisabled\"\n (click)=\"selectHourEnd(hr)\">\n {{ hr | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n @if (zShowMinute()) {\n <div class=\"flex flex-col\" [class.border-r]=\"zShowSecond()\" [class.border-border]=\"zShowSecond()\">\n <ng-scrollbar\n class=\"z-time-scroll-minute-end h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowHour() && !zShowSecond()\"\n [class.rounded-l-sm]=\"!zShowHour() && zShowSecond()\"\n [class.rounded-r-sm]=\"zShowHour() && !zShowSecond()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (min of minuteOptions; track min) {\n @let minDisabled = min | zIsEndMinuteDisabled: endTimeContext();\n @let minEndSelected = min === minuteEnd();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!minDisabled && !minEndSelected\"\n [class.cursor-pointer]=\"!minDisabled\"\n [class.bg-primary]=\"minEndSelected\"\n [class.text-primary-foreground]=\"minEndSelected\"\n [class.font-medium]=\"minEndSelected\"\n [class.opacity-30]=\"minDisabled\"\n [class.cursor-not-allowed]=\"minDisabled\"\n [disabled]=\"minDisabled\"\n (click)=\"selectMinuteEnd(min)\">\n {{ min | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n @if (zShowSecond()) {\n <div class=\"flex flex-col\">\n <ng-scrollbar\n class=\"z-time-scroll-second-end h-[12.5rem] w-12\"\n [class.rounded-sm]=\"!zShowHour() && !zShowMinute()\"\n [class.rounded-r-sm]=\"zShowHour() || zShowMinute()\"\n track=\"vertical\">\n <div class=\"flex flex-col\">\n @for (sec of secondOptions; track sec) {\n @let secDisabled = sec | zIsEndSecondDisabled: endTimeContext();\n @let secEndSelected = sec === secondEnd();\n <button\n type=\"button\"\n class=\"flex h-7 shrink-0 items-center justify-center text-sm transition-colors\"\n [class.hover:bg-muted]=\"!secDisabled && !secEndSelected\"\n [class.cursor-pointer]=\"!secDisabled\"\n [class.bg-primary]=\"secEndSelected\"\n [class.text-primary-foreground]=\"secEndSelected\"\n [class.font-medium]=\"secEndSelected\"\n [class.opacity-30]=\"secDisabled\"\n [class.cursor-not-allowed]=\"secDisabled\"\n [disabled]=\"secDisabled\"\n (click)=\"selectSecondEnd(sec)\">\n {{ sec | number: '2.0-0' }}\n </button>\n }\n </div>\n </ng-scrollbar>\n </div>\n }\n </div>\n</ng-template>\n", styles: [".animate-calendar-enter{animation:z-calendar-view-enter .2s ease-out}@keyframes z-calendar-view-enter{0%{opacity:0;transform:scale(.95) translateY(.25rem)}to{opacity:1;transform:scale(1) translateY(0)}}.z-calendar input{text-overflow:ellipsis;overflow:hidden}\n"] }]
3027
3066
  }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], zMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "zMode", required: false }] }], zSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSize", required: false }] }], zLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "zLabel", required: false }] }], zLabelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "zLabelClass", required: false }] }], zPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "zPlaceholder", required: false }] }], zRequired: [{ type: i0.Input, args: [{ isSignal: true, alias: "zRequired", required: false }] }], zDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "zDisabled", required: false }] }], zReadonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "zReadonly", required: false }] }], zShowTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "zShowTime", required: false }] }], zTimeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "zTimeFormat", required: false }] }], zShowHour: [{ type: i0.Input, args: [{ isSignal: true, alias: "zShowHour", required: false }] }], zShowMinute: [{ type: i0.Input, args: [{ isSignal: true, alias: "zShowMinute", required: false }] }], zShowSecond: [{ type: i0.Input, args: [{ isSignal: true, alias: "zShowSecond", required: false }] }], zQuickSelect: [{ type: i0.Input, args: [{ isSignal: true, alias: "zQuickSelect", required: false }] }], zAllowClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAllowClear", required: false }] }], zFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "zFormat", required: false }] }], zMinDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "zMinDate", required: false }] }], zMaxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "zMaxDate", required: false }] }], zValueType: [{ type: i0.Input, args: [{ isSignal: true, alias: "zValueType", required: false }] }], zValidators: [{ type: i0.Input, args: [{ isSignal: true, alias: "zValidators", required: false }] }], zShowOk: [{ type: i0.Input, args: [{ isSignal: true, alias: "zShowOk", required: false }] }], zOkText: [{ type: i0.Input, args: [{ isSignal: true, alias: "zOkText", required: false }] }], zShowCancel: [{ type: i0.Input, args: [{ isSignal: true, alias: "zShowCancel", required: false }] }], zCancelText: [{ type: i0.Input, args: [{ isSignal: true, alias: "zCancelText", required: false }] }], zDisabledDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "zDisabledDate", required: false }] }], zScrollClose: [{ type: i0.Input, args: [{ isSignal: true, alias: "zScrollClose", required: false }] }], zDefaultTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "zDefaultTime", required: false }] }], zRangeDefaultTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "zRangeDefaultTime", required: false }] }], zControl: [{ type: i0.Output, args: ["zControl"] }], zChange: [{ type: i0.Output, args: ["zChange"] }], zOnBlur: [{ type: i0.Output, args: ["zOnBlur"] }], zOnFocus: [{ type: i0.Output, args: ["zOnFocus"] }], zEvent: [{ type: i0.Output, args: ["zEvent"] }], triggerRef: [{ type: i0.ViewChild, args: ['triggerEl', { isSignal: true }] }], inputRef: [{ type: i0.ViewChild, args: ['inputEl', { isSignal: true }] }] } });
3028
3067
 
3029
3068
  /**