UNPKG

@bimeister/pupakit.calendar

Version:
617 lines (584 loc) 102 kB
import * as i6 from '@angular/cdk/scrolling'; import { CdkVirtualScrollViewport, VIRTUAL_SCROLL_STRATEGY, ScrollingModule } from '@angular/cdk/scrolling'; import * as i3 from '@angular/common'; import { CommonModule } from '@angular/common'; import * as i0 from '@angular/core'; import { Component, ViewEncapsulation, ChangeDetectionStrategy, Input, InjectionToken, Injectable, Optional, Inject, EventEmitter, Output, Pipe, ViewChild, NgModule } from '@angular/core'; import * as i2 from '@bimeister/pupakit.common'; import { PupaDirectivesModule, PupaPipesModule } from '@bimeister/pupakit.common'; import * as i1 from '@bimeister/pupakit.icons'; import { PupaIconsModule, appChevronDownIcon, appChevronUpIcon, iosRadioButtonOffIcon } from '@bimeister/pupakit.icons'; import * as i5 from '@bimeister/pupakit.kit'; import { PupaButtonsModule, PupaScrollableModule } from '@bimeister/pupakit.kit'; import { BehaviorSubject, combineLatest, Subject, throwError, Subscription } from 'rxjs'; import { switchMap, map, startWith, take, distinctUntilChanged } from 'rxjs/operators'; import { isEmpty, isNil, filterNotNil, shareReplayWithRefCount, filterTruthy, filterNotEmpty } from '@bimeister/utilities'; import '@angular/cdk/collections'; import { trigger, transition, style, animate } from '@angular/animations'; class CalendarCellEmptyComponent { constructor() { this.isInRange = false; } } CalendarCellEmptyComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarCellEmptyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); CalendarCellEmptyComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: CalendarCellEmptyComponent, selector: "pupa-calendar-cell-empty", inputs: { isInRange: "isInRange" }, ngImport: i0, template: "<div class=\"cell\" [class.cell_in-range]=\"isInRange\"></div>\n", styles: [".cell{flex-shrink:0;display:flex;justify-content:center;align-items:center;height:7rem;width:7rem;content:\"\"}.cell_in-range{background-color:rgba(var(--semantic-color_surface-tertiary),var(--semantic-color-alpha_surface-tertiary))}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarCellEmptyComponent, decorators: [{ type: Component, args: [{ selector: 'pupa-calendar-cell-empty', encapsulation: ViewEncapsulation.Emulated, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"cell\" [class.cell_in-range]=\"isInRange\"></div>\n", styles: [".cell{flex-shrink:0;display:flex;justify-content:center;align-items:center;height:7rem;width:7rem;content:\"\"}.cell_in-range{background-color:rgba(var(--semantic-color_surface-tertiary),var(--semantic-color-alpha_surface-tertiary))}\n"] }] }], propDecorators: { isInRange: [{ type: Input }] } }); class CalendarCellSeparatorComponent { constructor() { this.isInRange = false; } } CalendarCellSeparatorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarCellSeparatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); CalendarCellSeparatorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: CalendarCellSeparatorComponent, selector: "pupa-calendar-cell-separator", inputs: { isInRange: "isInRange" }, ngImport: i0, template: "<div class=\"filler\" [class.filler_in-range]=\"isInRange\"></div>\n", styles: [":host{width:100%;height:100%;display:block;flex-grow:1}.filler{width:100%;height:100%;display:block;content:\"\"}.filler_in-range{background-color:rgba(var(--semantic-color_surface-tertiary),var(--semantic-color-alpha_surface-tertiary))}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarCellSeparatorComponent, decorators: [{ type: Component, args: [{ selector: 'pupa-calendar-cell-separator', encapsulation: ViewEncapsulation.Emulated, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"filler\" [class.filler_in-range]=\"isInRange\"></div>\n", styles: [":host{width:100%;height:100%;display:block;flex-grow:1}.filler{width:100%;height:100%;display:block;content:\"\"}.filler_in-range{background-color:rgba(var(--semantic-color_surface-tertiary),var(--semantic-color-alpha_surface-tertiary))}\n"] }] }], propDecorators: { isInRange: [{ type: Input }] } }); class CalendarCellComponent { } CalendarCellComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); CalendarCellComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: CalendarCellComponent, selector: "pupa-calendar-cell", inputs: { positionInRange: "positionInRange" }, ngImport: i0, template: "<div class=\"cell\" [ngClass]=\"'cell_in-range-' + positionInRange\">\n <ng-content></ng-content>\n</div>\n", styles: [".cell{flex-shrink:0;display:flex;justify-content:center;align-items:center;height:7rem;width:7rem}.cell_in-range-first{border-top-left-radius:1rem;border-bottom-left-radius:1rem;background-color:rgba(var(--semantic-color_surface-tertiary),var(--semantic-color-alpha_surface-tertiary))}.cell_in-range-inside{background-color:rgba(var(--semantic-color_surface-tertiary),var(--semantic-color-alpha_surface-tertiary))}.cell_in-range-last{border-top-right-radius:1rem;border-bottom-right-radius:1rem;background-color:rgba(var(--semantic-color_surface-tertiary),var(--semantic-color-alpha_surface-tertiary))}\n"], dependencies: [{ kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarCellComponent, decorators: [{ type: Component, args: [{ selector: 'pupa-calendar-cell', encapsulation: ViewEncapsulation.Emulated, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"cell\" [ngClass]=\"'cell_in-range-' + positionInRange\">\n <ng-content></ng-content>\n</div>\n", styles: [".cell{flex-shrink:0;display:flex;justify-content:center;align-items:center;height:7rem;width:7rem}.cell_in-range-first{border-top-left-radius:1rem;border-bottom-left-radius:1rem;background-color:rgba(var(--semantic-color_surface-tertiary),var(--semantic-color-alpha_surface-tertiary))}.cell_in-range-inside{background-color:rgba(var(--semantic-color_surface-tertiary),var(--semantic-color-alpha_surface-tertiary))}.cell_in-range-last{border-top-right-radius:1rem;border-bottom-right-radius:1rem;background-color:rgba(var(--semantic-color_surface-tertiary),var(--semantic-color-alpha_surface-tertiary))}\n"] }] }], propDecorators: { positionInRange: [{ type: Input }] } }); var CalendarQuickSelectMode; (function (CalendarQuickSelectMode) { CalendarQuickSelectMode["Month"] = "Month"; CalendarQuickSelectMode["Year"] = "Year"; })(CalendarQuickSelectMode || (CalendarQuickSelectMode = {})); var CalendarTextKey; (function (CalendarTextKey) { CalendarTextKey["SelectYear"] = "SelectYear"; CalendarTextKey["SelectMonth"] = "SelectMonth"; })(CalendarTextKey || (CalendarTextKey = {})); var DayOfWeek; (function (DayOfWeek) { DayOfWeek[DayOfWeek["Sunday"] = 0] = "Sunday"; DayOfWeek[DayOfWeek["Monday"] = 1] = "Monday"; DayOfWeek[DayOfWeek["Tuesday"] = 2] = "Tuesday"; DayOfWeek[DayOfWeek["Wednesday"] = 3] = "Wednesday"; DayOfWeek[DayOfWeek["Thursday"] = 4] = "Thursday"; DayOfWeek[DayOfWeek["Friday"] = 5] = "Friday"; DayOfWeek[DayOfWeek["Saturday"] = 6] = "Saturday"; })(DayOfWeek || (DayOfWeek = {})); const MONTHS_IN_YEAR = 12; const SMALL_CALENDAR_CYCLE_SIZE_IN_YEARS = 28; const DEFAULT_CALENDAR_CONFIG = { startWeekday: DayOfWeek.Monday, yearsRange: SMALL_CALENDAR_CYCLE_SIZE_IN_YEARS * 7, translations: { en: { weekdays: { [DayOfWeek.Sunday]: 'Su', [DayOfWeek.Monday]: 'Mo', [DayOfWeek.Tuesday]: 'Tu', [DayOfWeek.Wednesday]: 'We', [DayOfWeek.Thursday]: 'Th', [DayOfWeek.Friday]: 'Fr', [DayOfWeek.Saturday]: 'Sa', }, months: { [0]: 'January', [1]: 'February', [2]: 'March', [3]: 'April', [4]: 'May', [5]: 'June', [6]: 'July', [7]: 'August', [8]: 'September', [9]: 'October', [10]: 'November', [11]: 'December', }, texts: { [CalendarTextKey.SelectYear]: 'Select year', [CalendarTextKey.SelectMonth]: 'Select month', }, }, }, }; const CALENDAR_CONFIG_TOKEN = new InjectionToken('CALENDAR_CONFIG_TOKEN'); const LABEL_HEIGHT_PX = 16; const DIVIDER_HEIGHT_PX$1 = 12; const WEEK_HEIGHT_PX = 36; const BUFFER_PX = 500; class CalendarConfigService { constructor(config) { var _a, _b, _c; this.startWeekday = (_a = config === null || config === void 0 ? void 0 : config.startWeekday) !== null && _a !== void 0 ? _a : DEFAULT_CALENDAR_CONFIG.startWeekday; this.startYear = (_b = config === null || config === void 0 ? void 0 : config.startYear) !== null && _b !== void 0 ? _b : CalendarConfigService.getDefaultStartYear(); CalendarConfigService.validateYearsRange(config === null || config === void 0 ? void 0 : config.yearsRange); this.yearsRange = (_c = config === null || config === void 0 ? void 0 : config.yearsRange) !== null && _c !== void 0 ? _c : CalendarConfigService.getDefaultEndYear() - this.startYear; this.endYear = this.startYear + this.yearsRange; this.translations = !isEmpty(config === null || config === void 0 ? void 0 : config.translations) ? config.translations : DEFAULT_CALENDAR_CONFIG.translations; } get virtualScrollConfig() { return { bufferPx: BUFFER_PX, yearsRange: this.yearsRange, labelHeightPx: LABEL_HEIGHT_PX, dividerHeightPx: DIVIDER_HEIGHT_PX$1, weekHeightPx: WEEK_HEIGHT_PX, startWeekday: this.startWeekday, startYear: this.startYear, }; } static getDefaultStartYear() { return new Date().getFullYear() - Math.floor(DEFAULT_CALENDAR_CONFIG.yearsRange / 2); } static getDefaultEndYear() { return new Date().getFullYear() + Math.floor(DEFAULT_CALENDAR_CONFIG.yearsRange / 2); } static validateYearsRange(yearsRange) { const isValid = isNil(yearsRange) || yearsRange % SMALL_CALENDAR_CYCLE_SIZE_IN_YEARS === 0; if (isValid) { return; } throw new Error(`[CalendarConfigService] 'yearsRange' must be a multiple of ${SMALL_CALENDAR_CYCLE_SIZE_IN_YEARS}`); } } CalendarConfigService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarConfigService, deps: [{ token: CALENDAR_CONFIG_TOKEN, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); CalendarConfigService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarConfigService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarConfigService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [CALENDAR_CONFIG_TOKEN] }] }]; } }); class CalendarManipulatorService { constructor(calendarConfigService) { this.calendarConfigService = calendarConfigService; this.virtualScrollViewport$ = new BehaviorSubject(null); this.currentIndex$ = this.virtualScrollViewport$.pipe(filterNotNil(), switchMap((viewport) => viewport.scrolledIndexChange), shareReplayWithRefCount()); this.virtualScrollInitialized$ = this.currentIndex$.pipe(map(() => true), startWith(false), shareReplayWithRefCount()); this.currentCalendarMonth$ = this.currentIndex$.pipe(map((currentIndex) => { const monthIndex = currentIndex % MONTHS_IN_YEAR; const yearsCount = (currentIndex - monthIndex) / MONTHS_IN_YEAR; return { year: yearsCount + this.calendarConfigService.startYear, month: monthIndex, }; })); } get initialCalendarMonth() { const currentDate = new Date(); return { month: currentDate.getMonth(), year: currentDate.getFullYear(), }; } get initialMonthIndex() { const initialCalendarMonth = this.initialCalendarMonth; return ((initialCalendarMonth.year - this.calendarConfigService.startYear) * MONTHS_IN_YEAR + Number(initialCalendarMonth.month)); } setVirtualScrollViewport(viewport) { if (isNil(viewport)) { throw new Error('[CalendarStateService] viewport can not be null or undefined'); } this.virtualScrollViewport$.next(viewport); } clearVirtualScrollViewport() { this.virtualScrollViewport$.next(null); } resetScroll(behavior) { this.scrollToMonthByIndex(this.initialMonthIndex, behavior); } scrollToYear(year, behavior) { const yearFirstMonthIndex = (year - this.calendarConfigService.startYear) * MONTHS_IN_YEAR; this.scrollToMonthByIndex(yearFirstMonthIndex, behavior); } scrollToMonth(calendarMonth, behavior) { const monthIndex = (calendarMonth.year - this.calendarConfigService.startYear) * MONTHS_IN_YEAR + Number(calendarMonth.month); this.scrollToMonthByIndex(monthIndex, behavior); } scrollToNextMonth(behavior) { this.currentIndex$.pipe(take(1)).subscribe((currentIndex) => { this.scrollToMonthByIndex(currentIndex + 1, behavior); }); } scrollToPreviousMonth(behavior) { this.currentIndex$.pipe(take(1)).subscribe((currentIndex) => { this.scrollToMonthByIndex(currentIndex - 1, behavior); }); } scrollToMonthByIndex(index, behavior) { this.virtualScrollInitialized$ .pipe(filterTruthy(), switchMap(() => this.virtualScrollViewport$), take(1)) .subscribe((viewport) => requestAnimationFrame(() => viewport.scrollToIndex(index, behavior))); } } CalendarManipulatorService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarManipulatorService, deps: [{ token: CalendarConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); CalendarManipulatorService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarManipulatorService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarManipulatorService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: CalendarConfigService }]; } }); const DEFAULT_LOCALE = 'en'; class CalendarTranslationService { constructor(calendarConfigService, localeService) { this.calendarConfigService = calendarConfigService; this.localeService = localeService; this.locale$ = this.localeService.locale$.pipe(startWith(DEFAULT_LOCALE)); this.translation$ = this.locale$.pipe(map((locale) => this.getTranslationByLocale(locale)), filterNotEmpty()); } getTranslationByLocale(locale) { var _a, _b; return (_b = (_a = this.calendarConfigService.translations) === null || _a === void 0 ? void 0 : _a[locale]) !== null && _b !== void 0 ? _b : null; } } CalendarTranslationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarTranslationService, deps: [{ token: CalendarConfigService }, { token: i2.LocaleService }], target: i0.ɵɵFactoryTarget.Injectable }); CalendarTranslationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarTranslationService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarTranslationService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: CalendarConfigService }, { type: i2.LocaleService }]; } }); function getClearDate() { const date = new Date(null); date.setHours(0); date.setMinutes(0); date.setSeconds(0); date.setMilliseconds(0); return date; } function getSortedDates(dates, sortDirection) { const compareFn = (first, second) => sortDirection === 'ascending' ? first - second : second - first; return [...dates].sort((first, second) => compareFn(first.getTime(), second.getTime())); } const MULTI_SELECTION_DATES_COUNT = 2; function getDateWithClearedTime(date) { const clearDate = getClearDate(); clearDate.setFullYear(date.getFullYear()); clearDate.setMonth(date.getMonth()); clearDate.setDate(date.getDate()); return clearDate; } function findDateIndexInArray(array, date) { return array.findIndex((item) => item.getTime() === date.getTime()); } function getUniqDates(dates) { return dates.filter((date, index, array) => { const foundIndex = findDateIndexInArray(array, date); return foundIndex === index; }); } function getProcessedDates(dates) { return getSortedDates(getUniqDates(dates.map(getDateWithClearedTime)), 'ascending'); } class CalendarStateService { constructor() { this.isRange = false; this.selectedDates$ = new BehaviorSubject([]); this.quickSelectMode$ = new BehaviorSubject(null); } setSelectedDates(dates) { this.selectedDates$.next(getProcessedDates(dates)); } addSelectedDate(newDate) { const preparedDate = getDateWithClearedTime(newDate); this.selectedDates$.pipe(take(1)).subscribe((selectedDates) => { const updatedDates = this.isRange ? this.patchDatesForRangeSelection(selectedDates, preparedDate) : [preparedDate]; this.selectedDates$.next(updatedDates); }); } patchDatesForRangeSelection(dates, newDate) { const hasAlreadyAdded = findDateIndexInArray(dates, newDate) >= 0; const isResetNeeded = dates.length >= MULTI_SELECTION_DATES_COUNT; if (hasAlreadyAdded || isResetNeeded) { return [newDate]; } return getProcessedDates([...dates, newDate]); } setQuickSelectMode(mode) { this.quickSelectMode$.next(mode); } resetQuickSelectMode() { this.quickSelectMode$.next(null); } setIsRange(isRange) { this.isRange = isRange; } } CalendarStateService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); CalendarStateService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarStateService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarStateService, decorators: [{ type: Injectable }] }); class CalendarControlPanelComponent { constructor(calendarManipulatorService, calendarTranslationService, calendarStateService) { this.calendarManipulatorService = calendarManipulatorService; this.calendarTranslationService = calendarTranslationService; this.calendarStateService = calendarStateService; this.monthTranslationByIndex$ = this.calendarTranslationService.translation$.pipe(map((translation) => translation.months)); this.displayedMonth$ = combineLatest([ this.calendarManipulatorService.currentCalendarMonth$, this.monthTranslationByIndex$, ]).pipe(map(([calendarMonth, monthTranslationByIndex]) => ({ year: calendarMonth.year, month: monthTranslationByIndex[calendarMonth.month], }))); } resetScroll() { this.calendarManipulatorService.resetScroll('smooth'); } scrollToNextMonth() { this.calendarManipulatorService.scrollToNextMonth('smooth'); } scrollToPreviousMonth() { this.calendarManipulatorService.scrollToPreviousMonth('smooth'); } setQuickSelectModeMonth() { this.calendarStateService.setQuickSelectMode(CalendarQuickSelectMode.Month); } setQuickSelectModeYear() { this.calendarStateService.setQuickSelectMode(CalendarQuickSelectMode.Year); } } CalendarControlPanelComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarControlPanelComponent, deps: [{ token: CalendarManipulatorService }, { token: CalendarTranslationService }, { token: CalendarStateService }], target: i0.ɵɵFactoryTarget.Component }); CalendarControlPanelComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: CalendarControlPanelComponent, selector: "pupa-calendar-control-panel", ngImport: i0, template: "<div class=\"selection\" *ngIf=\"displayedMonth$ | async as displayedMonth\">\n <pupa-button (click)=\"setQuickSelectModeMonth()\" kind=\"secondary\">\n {{ displayedMonth.month }}\n </pupa-button>\n\n <pupa-button (click)=\"setQuickSelectModeYear()\" kind=\"secondary\">\n {{ displayedMonth.year }}\n </pupa-button>\n</div>\n\n<div class=\"navigation\">\n <pupa-button-icon size=\"m\" kind=\"secondary\" icon=\"app-chevron-down\" (click)=\"scrollToNextMonth()\"></pupa-button-icon>\n\n <pupa-button-icon size=\"m\" kind=\"secondary\" icon=\"ios-radio-button-off\" (click)=\"resetScroll()\"></pupa-button-icon>\n\n <pupa-button-icon\n size=\"m\"\n kind=\"secondary\"\n icon=\"app-chevron-up\"\n (click)=\"scrollToPreviousMonth()\"\n ></pupa-button-icon>\n</div>\n", styles: [":host{display:flex;align-items:center;justify-content:space-between;height:12rem;padding:0 3rem}.selection{display:flex}.navigation{display:flex;gap:1rem}\n"], dependencies: [{ kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i5.ButtonComponent, selector: "pupa-button", inputs: ["size", "kind", "type", "disabled", "icon", "iconPosition", "loading", "active", "tabIndex"] }, { kind: "component", type: i5.ButtonIconComponent, selector: "pupa-button-icon", inputs: ["size", "kind", "type", "disabled", "icon", "loading", "active", "tabIndex"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarControlPanelComponent, decorators: [{ type: Component, args: [{ selector: 'pupa-calendar-control-panel', encapsulation: ViewEncapsulation.Emulated, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"selection\" *ngIf=\"displayedMonth$ | async as displayedMonth\">\n <pupa-button (click)=\"setQuickSelectModeMonth()\" kind=\"secondary\">\n {{ displayedMonth.month }}\n </pupa-button>\n\n <pupa-button (click)=\"setQuickSelectModeYear()\" kind=\"secondary\">\n {{ displayedMonth.year }}\n </pupa-button>\n</div>\n\n<div class=\"navigation\">\n <pupa-button-icon size=\"m\" kind=\"secondary\" icon=\"app-chevron-down\" (click)=\"scrollToNextMonth()\"></pupa-button-icon>\n\n <pupa-button-icon size=\"m\" kind=\"secondary\" icon=\"ios-radio-button-off\" (click)=\"resetScroll()\"></pupa-button-icon>\n\n <pupa-button-icon\n size=\"m\"\n kind=\"secondary\"\n icon=\"app-chevron-up\"\n (click)=\"scrollToPreviousMonth()\"\n ></pupa-button-icon>\n</div>\n", styles: [":host{display:flex;align-items:center;justify-content:space-between;height:12rem;padding:0 3rem}.selection{display:flex}.navigation{display:flex;gap:1rem}\n"] }] }], ctorParameters: function () { return [{ type: CalendarManipulatorService }, { type: CalendarTranslationService }, { type: CalendarStateService }]; } }); class CalendarDayComponent { constructor() { this.value = null; this.isDisabled = false; this.isEmpty = false; this.isCurrent = false; this.isSelected = false; this.select = new EventEmitter(); } handleClick() { this.select.emit(); } } CalendarDayComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarDayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); CalendarDayComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: CalendarDayComponent, selector: "pupa-calendar-day", inputs: { value: "value", isDisabled: "isDisabled", isEmpty: "isEmpty", isCurrent: "isCurrent", isSelected: "isSelected" }, outputs: { select: "select" }, ngImport: i0, template: "<div\n class=\"day\"\n [class.day_disabled]=\"isDisabled\"\n [class.day_empty]=\"isEmpty\"\n [class.day_current]=\"isCurrent\"\n [class.day_selected]=\"isSelected\"\n (click)=\"handleClick()\"\n [tabindex]=\"isEmpty ? -1 : 0\"\n>\n {{ value }}\n</div>\n", styles: [":host{display:block;width:6rem;height:6rem;aspect-ratio:1/1}.day{display:flex;justify-content:center;align-items:center;flex-grow:0;flex-shrink:0;width:100%;height:100%;box-sizing:border-box;border-color:transparent;background-color:transparent;border-radius:1rem;cursor:pointer;transition:var(--transition-duration_shortest) var(--transition-timing-function_common);font-family:NotoSans,sans-serif;font-weight:400;font-size:11px;line-height:16px}@media (hover: hover){.day:hover{background-color:rgba(var(--semantic-color_kind-neutral-hover),var(--semantic-color-alpha_kind-neutral-hover))}}.day:active{background-color:rgba(var(--semantic-color_kind-neutral-pressed),var(--semantic-color-alpha_kind-neutral-pressed))}.day:focus-visible{border:1px solid rgba(var(--color_primary-600),var(--alpha-1000));outline:none}.day_current{border:1px solid rgba(var(--semantic-color_kind-primary-normal),var(--semantic-color-alpha_kind-primary-normal))}.day_selected{background-color:rgba(var(--semantic-color_kind-primary-normal),var(--semantic-color-alpha_kind-primary-normal));color:rgba(var(--semantic-color_text-inverse),var(--semantic-color-alpha_text-inverse));font-family:NotoSans,sans-serif;font-weight:500;font-size:11px;line-height:16px}@media (hover: hover){.day_selected:hover{background-color:rgba(var(--semantic-color_kind-primary-hover),var(--semantic-color-alpha_kind-primary-hover))}}.day_selected:active{background-color:rgba(var(--semantic-color_kind-primary-pressed),var(--semantic-color-alpha_kind-primary-pressed))}.day_disabled{color:rgba(var(--semantic-color_text-disabled),var(--semantic-color-alpha_text-disabled));background-color:transparent}@media (hover: hover){.day_disabled:hover{background-color:transparent}}.day_empty{cursor:default;background-color:transparent;color:transparent;border:none}@media (hover: hover){.day_empty:hover{border:none;background-color:transparent}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarDayComponent, decorators: [{ type: Component, args: [{ selector: 'pupa-calendar-day', encapsulation: ViewEncapsulation.Emulated, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"day\"\n [class.day_disabled]=\"isDisabled\"\n [class.day_empty]=\"isEmpty\"\n [class.day_current]=\"isCurrent\"\n [class.day_selected]=\"isSelected\"\n (click)=\"handleClick()\"\n [tabindex]=\"isEmpty ? -1 : 0\"\n>\n {{ value }}\n</div>\n", styles: [":host{display:block;width:6rem;height:6rem;aspect-ratio:1/1}.day{display:flex;justify-content:center;align-items:center;flex-grow:0;flex-shrink:0;width:100%;height:100%;box-sizing:border-box;border-color:transparent;background-color:transparent;border-radius:1rem;cursor:pointer;transition:var(--transition-duration_shortest) var(--transition-timing-function_common);font-family:NotoSans,sans-serif;font-weight:400;font-size:11px;line-height:16px}@media (hover: hover){.day:hover{background-color:rgba(var(--semantic-color_kind-neutral-hover),var(--semantic-color-alpha_kind-neutral-hover))}}.day:active{background-color:rgba(var(--semantic-color_kind-neutral-pressed),var(--semantic-color-alpha_kind-neutral-pressed))}.day:focus-visible{border:1px solid rgba(var(--color_primary-600),var(--alpha-1000));outline:none}.day_current{border:1px solid rgba(var(--semantic-color_kind-primary-normal),var(--semantic-color-alpha_kind-primary-normal))}.day_selected{background-color:rgba(var(--semantic-color_kind-primary-normal),var(--semantic-color-alpha_kind-primary-normal));color:rgba(var(--semantic-color_text-inverse),var(--semantic-color-alpha_text-inverse));font-family:NotoSans,sans-serif;font-weight:500;font-size:11px;line-height:16px}@media (hover: hover){.day_selected:hover{background-color:rgba(var(--semantic-color_kind-primary-hover),var(--semantic-color-alpha_kind-primary-hover))}}.day_selected:active{background-color:rgba(var(--semantic-color_kind-primary-pressed),var(--semantic-color-alpha_kind-primary-pressed))}.day_disabled{color:rgba(var(--semantic-color_text-disabled),var(--semantic-color-alpha_text-disabled));background-color:transparent}@media (hover: hover){.day_disabled:hover{background-color:transparent}}.day_empty{cursor:default;background-color:transparent;color:transparent;border:none}@media (hover: hover){.day_empty:hover{border:none;background-color:transparent}}\n"] }] }], propDecorators: { value: [{ type: Input }], isDisabled: [{ type: Input }], isEmpty: [{ type: Input }], isCurrent: [{ type: Input }], isSelected: [{ type: Input }], select: [{ type: Output }] } }); class CalendarHeaderComponent { } CalendarHeaderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); CalendarHeaderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: CalendarHeaderComponent, selector: "pupa-calendar-header", ngImport: i0, template: "<ng-content></ng-content>\n", styles: [":host{display:block;width:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarHeaderComponent, decorators: [{ type: Component, args: [{ selector: 'pupa-calendar-header', encapsulation: ViewEncapsulation.Emulated, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>\n", styles: [":host{display:block;width:100%}\n"] }] }] }); class CalendarLabelComponent { } CalendarLabelComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarLabelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); CalendarLabelComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: CalendarLabelComponent, selector: "pupa-calendar-label", ngImport: i0, template: "<ng-content></ng-content>\n", styles: [":host{display:block;font-size:12px;line-height:16px;font-family:NotoSans,sans-serif;font-weight:500}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarLabelComponent, decorators: [{ type: Component, args: [{ selector: 'pupa-calendar-label', encapsulation: ViewEncapsulation.Emulated, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>\n", styles: [":host{display:block;font-size:12px;line-height:16px;font-family:NotoSans,sans-serif;font-weight:500}\n"] }] }] }); class CalendarSelectorButtonComponent { constructor() { this.isCurrent = false; } } CalendarSelectorButtonComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarSelectorButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); CalendarSelectorButtonComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: CalendarSelectorButtonComponent, selector: "pupa-calendar-selector-button", inputs: { isCurrent: "isCurrent" }, ngImport: i0, template: "<button class=\"button\" [class.button_current]=\"isCurrent\">\n <ng-content></ng-content>\n</button>\n", styles: [".button{all:unset;display:flex;align-items:center;justify-content:center;width:100%;height:8rem;border-radius:1rem;box-sizing:border-box;-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-tap-highlight-color:transparent;pointer-events:auto;-webkit-user-select:none;user-select:none;cursor:pointer;font-family:NotoSans,sans-serif;font-weight:500;font-size:11px;line-height:16px;color:rgba(var(--semantic-color_text-primary),var(--semantic-color-alpha_text-primary));transition:var(--transition-duration_shortest) var(--transition-timing-function_common)}@media (hover: hover){.button:hover{background-color:rgba(var(--semantic-color_kind-primary-hover),var(--semantic-color-alpha_kind-primary-hover));color:rgba(var(--semantic-color_surface-primary),var(--semantic-color-alpha_surface-primary))}}.button:active{background-color:rgba(var(--semantic-color_kind-primary-active),var(--semantic-color-alpha_kind-primary-active))}.button_current{border:1px solid rgba(var(--semantic-color_kind-primary-active),var(--semantic-color-alpha_kind-primary-active))}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarSelectorButtonComponent, decorators: [{ type: Component, args: [{ selector: 'pupa-calendar-selector-button', encapsulation: ViewEncapsulation.Emulated, changeDetection: ChangeDetectionStrategy.OnPush, template: "<button class=\"button\" [class.button_current]=\"isCurrent\">\n <ng-content></ng-content>\n</button>\n", styles: [".button{all:unset;display:flex;align-items:center;justify-content:center;width:100%;height:8rem;border-radius:1rem;box-sizing:border-box;-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-tap-highlight-color:transparent;pointer-events:auto;-webkit-user-select:none;user-select:none;cursor:pointer;font-family:NotoSans,sans-serif;font-weight:500;font-size:11px;line-height:16px;color:rgba(var(--semantic-color_text-primary),var(--semantic-color-alpha_text-primary));transition:var(--transition-duration_shortest) var(--transition-timing-function_common)}@media (hover: hover){.button:hover{background-color:rgba(var(--semantic-color_kind-primary-hover),var(--semantic-color-alpha_kind-primary-hover));color:rgba(var(--semantic-color_surface-primary),var(--semantic-color-alpha_surface-primary))}}.button:active{background-color:rgba(var(--semantic-color_kind-primary-active),var(--semantic-color-alpha_kind-primary-active))}.button_current{border:1px solid rgba(var(--semantic-color_kind-primary-active),var(--semantic-color-alpha_kind-primary-active))}\n"] }] }], propDecorators: { isCurrent: [{ type: Input }] } }); function getCurrentCalendarMonth() { const date = new Date(); return { year: date.getFullYear(), month: date.getMonth(), }; } const currentCalendarMonth = getCurrentCalendarMonth(); class IsCurrentCalendarMonthPipe { transform({ year, month }) { return month === currentCalendarMonth.month && year === currentCalendarMonth.year; } } IsCurrentCalendarMonthPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: IsCurrentCalendarMonthPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); IsCurrentCalendarMonthPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "14.2.12", ngImport: i0, type: IsCurrentCalendarMonthPipe, name: "isCurrentCalendarMonth" }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: IsCurrentCalendarMonthPipe, decorators: [{ type: Pipe, args: [{ name: 'isCurrentCalendarMonth', pure: true, }] }] }); const DIVIDER_HEIGHT_PX = 12; const YEAR_LABEL_HEIGHT_PX = 16; const YEAR_TABLE_HEIGHT_PX = 188; const ITEM_HEIGHT_PX = DIVIDER_HEIGHT_PX * 2 + YEAR_LABEL_HEIGHT_PX + YEAR_TABLE_HEIGHT_PX; class CalendarMonthSelectorComponent { constructor(calendarTranslationService, calendarConfigService) { this.calendarTranslationService = calendarTranslationService; this.calendarConfigService = calendarConfigService; this.select = new EventEmitter(); this.virtualScrollViewport$ = new Subject(); this.headerTitle$ = this.calendarTranslationService.translation$.pipe(map((translation) => translation.texts[CalendarTextKey.SelectMonth])); this.itemHeight = ITEM_HEIGHT_PX; this.startYear = this.calendarConfigService.startYear; this.currentYearInScroll$ = this.virtualScrollViewport$.pipe(switchMap((viewport) => viewport.scrolledIndexChange), map((index) => index + this.startYear)); this.yearsIndexes = Array.from({ length: this.calendarConfigService.yearsRange, }); this.monthsIndexes = Array.from({ length: MONTHS_IN_YEAR }); this.monthNameByIndex$ = this.calendarTranslationService.translation$.pipe(map((translation) => translation.months)); } ngAfterViewInit() { this.scrollToCurrentYear(); if (!isNil(this.virtualScrollViewport)) { this.virtualScrollViewport$.next(this.virtualScrollViewport); } } selectMonth(year, month) { this.select.emit({ year, month, }); } scrollToCurrentYear() { if (isNil(this.virtualScrollViewport)) { return; } const currentYearIndex = new Date().getFullYear() - this.startYear; requestAnimationFrame(() => { this.virtualScrollViewport.scrollToIndex(currentYearIndex); }); } } CalendarMonthSelectorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarMonthSelectorComponent, deps: [{ token: CalendarTranslationService }, { token: CalendarConfigService }], target: i0.ɵɵFactoryTarget.Component }); CalendarMonthSelectorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: CalendarMonthSelectorComponent, selector: "pupa-calendar-month-selector", outputs: { select: "select" }, viewQueries: [{ propertyName: "virtualScrollViewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true }], ngImport: i0, template: "<pupa-calendar-header>\n <div class=\"header-content\">\n <h4 class=\"header-title\">\n {{ headerTitle$ | async }}\n </h4>\n\n <div class=\"year-label\">{{ currentYearInScroll$ | async }}</div>\n </div>\n</pupa-calendar-header>\n\n<div class=\"scroller-wrapper\">\n <cdk-virtual-scroll-viewport\n *pupaLet=\"monthNameByIndex$ | async as monthNameByIndex\"\n pupaScrollableContent\n class=\"scroller\"\n [itemSize]=\"itemHeight\"\n >\n <div\n class=\"scroller__item\"\n *cdkVirtualFor=\"let _ of yearsIndexes; templateCacheSize: 10; let isLast = last; let yearIndex = index\"\n >\n <div class=\"scroller__divider\"></div>\n\n <div class=\"year-table\">\n <div class=\"year-table__month\" *ngFor=\"let __ of monthsIndexes; let month = index\">\n <pupa-calendar-selector-button\n [isCurrent]=\"{ year: startYear + yearIndex, month } | isCurrentCalendarMonth\"\n (click)=\"selectMonth(startYear + yearIndex, month)\"\n >\n {{ monthNameByIndex[month] }}\n </pupa-calendar-selector-button>\n </div>\n </div>\n\n <ng-container *ngIf=\"!isLast\">\n <div class=\"scroller__divider\"></div>\n <div class=\"year-label\">{{ yearIndex + startYear + 1 }}</div>\n </ng-container>\n </div>\n </cdk-virtual-scroll-viewport>\n</div>\n", styles: [":host{display:flex;flex-direction:column;height:100%;width:100%;position:absolute;z-index:2;top:0;left:0;right:0;bottom:0;background-color:rgba(var(--semantic-color_surface-primary),var(--semantic-color-alpha_surface-primary))}.header-content{flex-direction:column;box-sizing:border-box;padding:0 4rem}.header-title{display:flex;align-items:center;margin:0;height:12rem}.scroller-wrapper{width:100%;height:100%;box-sizing:border-box;display:block}.scroller{width:100%;height:100%;display:block;box-sizing:border-box}.scroller__item{padding:0rem 4rem}.scroller__divider{display:block;width:100%;height:3rem}.year-label{font-family:NotoSans,sans-serif;font-weight:400;font-size:11px;line-height:16px}.year-table{display:grid;grid-template-columns:repeat(3,1fr);column-gap:2rem;row-gap:5rem}.year-table__month{width:100%}\n"], dependencies: [{ kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.ScrollableContentDirective, selector: "[pupaScrollableContent]" }, { kind: "directive", type: i2.LetDirective, selector: "[pupaLet]", inputs: ["pupaLet"] }, { kind: "directive", type: i6.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i6.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i6.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "component", type: CalendarHeaderComponent, selector: "pupa-calendar-header" }, { kind: "component", type: CalendarSelectorButtonComponent, selector: "pupa-calendar-selector-button", inputs: ["isCurrent"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: IsCurrentCalendarMonthPipe, name: "isCurrentCalendarMonth" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarMonthSelectorComponent, decorators: [{ type: Component, args: [{ selector: 'pupa-calendar-month-selector', encapsulation: ViewEncapsulation.Emulated, changeDetection: ChangeDetectionStrategy.OnPush, template: "<pupa-calendar-header>\n <div class=\"header-content\">\n <h4 class=\"header-title\">\n {{ headerTitle$ | async }}\n </h4>\n\n <div class=\"year-label\">{{ currentYearInScroll$ | async }}</div>\n </div>\n</pupa-calendar-header>\n\n<div class=\"scroller-wrapper\">\n <cdk-virtual-scroll-viewport\n *pupaLet=\"monthNameByIndex$ | async as monthNameByIndex\"\n pupaScrollableContent\n class=\"scroller\"\n [itemSize]=\"itemHeight\"\n >\n <div\n class=\"scroller__item\"\n *cdkVirtualFor=\"let _ of yearsIndexes; templateCacheSize: 10; let isLast = last; let yearIndex = index\"\n >\n <div class=\"scroller__divider\"></div>\n\n <div class=\"year-table\">\n <div class=\"year-table__month\" *ngFor=\"let __ of monthsIndexes; let month = index\">\n <pupa-calendar-selector-button\n [isCurrent]=\"{ year: startYear + yearIndex, month } | isCurrentCalendarMonth\"\n (click)=\"selectMonth(startYear + yearIndex, month)\"\n >\n {{ monthNameByIndex[month] }}\n </pupa-calendar-selector-button>\n </div>\n </div>\n\n <ng-container *ngIf=\"!isLast\">\n <div class=\"scroller__divider\"></div>\n <div class=\"year-label\">{{ yearIndex + startYear + 1 }}</div>\n </ng-container>\n </div>\n </cdk-virtual-scroll-viewport>\n</div>\n", styles: [":host{display:flex;flex-direction:column;height:100%;width:100%;position:absolute;z-index:2;top:0;left:0;right:0;bottom:0;background-color:rgba(var(--semantic-color_surface-primary),var(--semantic-color-alpha_surface-primary))}.header-content{flex-direction:column;box-sizing:border-box;padding:0 4rem}.header-title{display:flex;align-items:center;margin:0;height:12rem}.scroller-wrapper{width:100%;height:100%;box-sizing:border-box;display:block}.scroller{width:100%;height:100%;display:block;box-sizing:border-box}.scroller__item{padding:0rem 4rem}.scroller__divider{display:block;width:100%;height:3rem}.year-label{font-family:NotoSans,sans-serif;font-weight:400;font-size:11px;line-height:16px}.year-table{display:grid;grid-template-columns:repeat(3,1fr);column-gap:2rem;row-gap:5rem}.year-table__month{width:100%}\n"] }] }], ctorParameters: function () { return [{ type: CalendarTranslationService }, { type: CalendarConfigService }]; }, propDecorators: { select: [{ type: Output }], virtualScrollViewport: [{ type: ViewChild, args: [CdkVirtualScrollViewport] }] } }); function getDateFromCalendarDay({ year, month, day }) { return new Date(year, month, day); } class CalendarWeekComponent { } CalendarWeekComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarWeekComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); CalendarWeekComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: CalendarWeekComponent, selector: "pupa-calendar-week", ngImport: i0, template: "<ng-content></ng-content>\n", styles: [":host{display:flex;align-items:center;justify-content:space-between;width:100%;height:100%;box-sizing:border-box;padding:1rem 0;height:9rem}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: CalendarWeekComponent, decorators: [{ type: Component, args: [{ selector: 'pupa-calendar-week', encapsulation: ViewEncapsulation.Emulated, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>\n", styles: [":host{display:flex;align-items:center;justify-content:space-between;width:100%;height:100%;box-sizing:border-box;padding:1rem 0;height:9rem}\n"] }] }] }); const DAYS_IN_WEEK = 7; function getCurrentCalendarDay() { const date = new Date(); return { year: date.getFullYear(), month: date.getMonth(), day: date.getDate(), }; } function getDaysCountInMonth(monthIndex, isLeapYear) { switch (monthIndex) { case 1: return isLeapYear ? 29 : 28; case 3: case 5: case 8: case 10: return 30; default: return 31; } } const BIG_CALENDAR_CYCLE_SIZE_IN_YEARS = 400; const SMALL_CALENDAR_CYCLE_WEEKDAYS_SEQUENCE = [ DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Saturday, DayOfWeek.Sunday, DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Thursday, DayOfWeek.Friday, DayOfWeek.Saturday, DayOfWeek.Sunday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday, DayOfWeek.Sunday, DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Friday, DayOfWeek.Saturday, DayOfWeek.Sunday, DayOfWeek.Monday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday, DayOfWeek.Saturday, ]; function isLeapYear(year) { if (year % 400 === 0) { return true; } if (year % 100 === 0) { return false; } return year % 4 === 0; } const NORMAL_YEAR_OFFSETS_IN_SMALL_CYCLE = [0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5]; function getWeekdayIndex(yearNumber, monthIndex, dayNumber) { const daysOffset = getDaysOffset(yearNumber, monthIndex); const yearIndexInSmallCycle = getYearIndexInSmallCycle(yearNumber); const dayIndex = dayNumber - 1; const weekdayIndexInSmallCycle = SMALL_CALENDAR_CYCLE_WEEKDAYS_SEQUENCE[yearIndexInSmallCycle]; const weekdayIndex = (weekdayIndexInSmallCycle + daysOffset + dayIndex) % DAYS_IN_WEEK; return weekdayIndex; } function getYearIndexInSmallCycle(yearNumber) { const yearIndex = yearNumber - 1; const yearIndexInBigCycle = yearIndex % BIG_CALENDAR_CYCLE_SIZE_IN_YEARS; const centuryInBigCycle = Math.floor(yearIndexInBigCycle / 100); const yearIndexRestoredWithBigCycle = 4 * centuryInBigCycle + (yearIndexInBigCycle % 100); const yearIndexInSmallCycle = yearIndexRestoredWithBigCycle % SMALL_CALENDAR_CYCLE_SIZE_IN_YEARS; return yearIndexInSmallCycle; } function getDaysOffset(yearNumber, monthIndex) { const offset = NORMAL_YEAR_OFFSETS_IN_SMALL_CYCLE[monthIndex];