UNPKG

ngxsmk-datepicker

Version:

<!-- SEO Keywords: Angular DatePicker, Angular Date Range Picker, Lightweight Calendar Component, Angular Signals DatePicker, SSR Ready DatePicker, Zoneless Angular, A11y DatePicker, Mobile-Friendly DatePicker, Ionic DatePicker Meta Description: The m

1,138 lines (1,123 loc) 106 kB
import * as i0 from '@angular/core'; import { EventEmitter, ElementRef, AfterViewInit, OnDestroy, TemplateRef, InjectionToken, EffectRef, Signal, OnInit, OnChanges, SimpleChanges } from '@angular/core'; import { ControlValueAccessor, NgControl } from '@angular/forms'; import { Subject } from 'rxjs'; declare function getStartOfDay(d: Date): Date; declare function getEndOfDay(d: Date): Date; declare function addMonths(d: Date, months: number): Date; declare function subtractDays(d: Date, days: number): Date; declare function getStartOfMonth(d: Date): Date; declare function getEndOfMonth(d: Date): Date; declare function isSameDay(d1: Date | null, d2: Date | null): boolean; declare function normalizeDate(date: DateInput | null): Date | null; type DateInput = Date | string | { toDate: () => Date; _isAMomentObject?: boolean; $d?: Date; }; interface HolidayProvider { isHoliday(date: Date): boolean; getHolidayLabel?(date: Date): string | null; } interface DateRange { [key: string]: [DateInput, DateInput]; } type DatepickerValue = Date | { start: Date | null; end: Date | null; } | Date[] | null; declare function generateMonthOptions(locale: string, year: number): { label: string; value: number; }[]; /** * Format a number using locale-aware number formatting. * Uses Intl.NumberFormat for proper localization of numeric separators and decimals. * * @param value - The number to format * @param locale - The locale to use for formatting (e.g., 'en-US', 'de-DE', 'fr-FR') * @param options - Optional Intl.NumberFormatOptions for customization * @returns Formatted number string */ declare function formatLocaleNumber(value: number, locale: string, options?: Intl.NumberFormatOptions): string; declare function generateYearOptions(currentYear: number, range?: number): { label: string; value: number; }[]; declare function generateTimeOptions(minuteInterval?: number, secondInterval?: number, includeSeconds?: boolean, use24Hour?: boolean): { hourOptions: { label: string; value: number; }[]; minuteOptions: { label: string; value: number; }[]; secondOptions?: { label: string; value: number; }[]; }; declare function generateWeekDays(locale: string, firstDayOfWeek?: number): string[]; declare function getFirstDayOfWeek(locale: string): number; declare function get24Hour(displayHour: number, isPm: boolean): number; declare function update12HourState(fullHour: number): { isPm: boolean; displayHour: number; }; declare function processDateRanges(ranges: DateRange | null): { [key: string]: [Date, Date]; } | null; declare function generateYearGrid(currentYear: number): number[]; declare function generateDecadeGrid(currentDecade: number): number[]; interface DatepickerClasses { wrapper?: string; inputGroup?: string; input?: string; clearBtn?: string; calendarBtn?: string; popover?: string; container?: string; calendar?: string; header?: string; navPrev?: string; navNext?: string; dayCell?: string; footer?: string; closeBtn?: string; } declare class NgxsmkDatepickerInputComponent { isNative: boolean; disabled: boolean; classes: DatepickerClasses | undefined; nativeInputType: string; formattedValue: string; placeholder: string; id: string; name: string; autocomplete: string; required: boolean; minDateNative: string | null; maxDateNative: string | null; ariaLabel: string; ariaDescribedBy: string; errorState: boolean; clearAriaLabel: string; clearLabel: string; isCalendarOpen: boolean; allowTyping: boolean; typedInputValue: string; displayValue: string; showCalendarButton: boolean; calendarAriaLabel: string; validationErrorMessage: string | null; nativeInputChange: EventEmitter<Event>; inputBlur: EventEmitter<FocusEvent>; clearValue: EventEmitter<MouseEvent>; toggleCalendar: EventEmitter<Event>; pointerDown: EventEmitter<PointerEvent>; pointerUp: EventEmitter<PointerEvent>; inputGroupFocus: EventEmitter<void>; inputKeyDown: EventEmitter<Event>; inputChange: EventEmitter<Event>; inputFocus: EventEmitter<FocusEvent>; nativeInput?: ElementRef<HTMLInputElement>; customInput?: ElementRef<HTMLInputElement>; focus(): void; onNativeInputChange(event: Event): void; onInputBlur(event: FocusEvent): void; onClearValue(event: MouseEvent): void; onToggleCalendar(event: Event): void; onPointerDown(event: PointerEvent): void; onPointerUp(event: PointerEvent): void; onInputGroupFocus(): void; onInputKeyDown(event: Event): void; onInputChange(event: Event): void; onInputFocus(event: FocusEvent): void; static ɵfac: i0.ɵɵFactoryDeclaration<NgxsmkDatepickerInputComponent, never>; static ɵcmp: i0.ɵɵComponentDeclaration<NgxsmkDatepickerInputComponent, "ngxsmk-datepicker-input", never, { "isNative": { "alias": "isNative"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "classes": { "alias": "classes"; "required": false; }; "nativeInputType": { "alias": "nativeInputType"; "required": false; }; "formattedValue": { "alias": "formattedValue"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "id": { "alias": "id"; "required": false; }; "name": { "alias": "name"; "required": false; }; "autocomplete": { "alias": "autocomplete"; "required": false; }; "required": { "alias": "required"; "required": false; }; "minDateNative": { "alias": "minDateNative"; "required": false; }; "maxDateNative": { "alias": "maxDateNative"; "required": false; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; }; "ariaDescribedBy": { "alias": "ariaDescribedBy"; "required": false; }; "errorState": { "alias": "errorState"; "required": false; }; "clearAriaLabel": { "alias": "clearAriaLabel"; "required": false; }; "clearLabel": { "alias": "clearLabel"; "required": false; }; "isCalendarOpen": { "alias": "isCalendarOpen"; "required": false; }; "allowTyping": { "alias": "allowTyping"; "required": false; }; "typedInputValue": { "alias": "typedInputValue"; "required": false; }; "displayValue": { "alias": "displayValue"; "required": false; }; "showCalendarButton": { "alias": "showCalendarButton"; "required": false; }; "calendarAriaLabel": { "alias": "calendarAriaLabel"; "required": false; }; "validationErrorMessage": { "alias": "validationErrorMessage"; "required": false; }; }, { "nativeInputChange": "nativeInputChange"; "inputBlur": "inputBlur"; "clearValue": "clearValue"; "toggleCalendar": "toggleCalendar"; "pointerDown": "pointerDown"; "pointerUp": "pointerUp"; "inputGroupFocus": "inputGroupFocus"; "inputKeyDown": "inputKeyDown"; "inputChange": "inputChange"; "inputFocus": "inputFocus"; }, never, never, true, never>; } declare class CustomSelectComponent implements AfterViewInit, OnDestroy { options: { label: string; value: unknown; }[]; value: unknown; disabled: boolean; valueChange: EventEmitter<unknown>; container: ElementRef<HTMLDivElement>; button: ElementRef<HTMLButtonElement>; panel: ElementRef<HTMLDivElement>; isOpen: boolean; private readonly elementRef; private readonly platformId; private readonly document; private readonly isBrowser; private resizeObserver; private scrollListener; ngAfterViewInit(): void; ngOnDestroy(): void; private setupResizeObserver; private setupScrollListener; private updatePanelPosition; onDocumentClick(event: MouseEvent | TouchEvent): void; onDocumentTouchStart(event: TouchEvent): void; get displayValue(): string; toggleDropdown(): void; private scrollToSelected; selectOption(option: { label: string; value: unknown; }): void; static ɵfac: i0.ɵɵFactoryDeclaration<CustomSelectComponent, never>; static ɵcmp: i0.ɵɵComponentDeclaration<CustomSelectComponent, "ngxsmk-custom-select", never, { "options": { "alias": "options"; "required": false; }; "value": { "alias": "value"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; }, { "valueChange": "valueChange"; }, never, never, true, never>; } declare class CalendarHeaderComponent { monthSelect?: CustomSelectComponent; yearSelect?: CustomSelectComponent; monthOptions: { label: string; value: number; }[]; yearOptions: { label: string; value: number; }[]; currentMonth: number; currentYear: number; disabled: boolean; isBackArrowDisabled: boolean; prevMonthAriaLabel: string; nextMonthAriaLabel: string; headerClass?: string; navPrevClass?: string; navNextClass?: string; currentYearChange: EventEmitter<number>; currentMonthChange: EventEmitter<number>; previousMonth: EventEmitter<void>; nextMonth: EventEmitter<void>; onMonthSelect(value: unknown): void; onYearSelect(value: unknown): void; static ɵfac: i0.ɵɵFactoryDeclaration<CalendarHeaderComponent, never>; static ɵcmp: i0.ɵɵComponentDeclaration<CalendarHeaderComponent, "ngxsmk-calendar-header", never, { "monthOptions": { "alias": "monthOptions"; "required": false; }; "yearOptions": { "alias": "yearOptions"; "required": false; }; "currentMonth": { "alias": "currentMonth"; "required": false; }; "currentYear": { "alias": "currentYear"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "isBackArrowDisabled": { "alias": "isBackArrowDisabled"; "required": false; }; "prevMonthAriaLabel": { "alias": "prevMonthAriaLabel"; "required": false; }; "nextMonthAriaLabel": { "alias": "nextMonthAriaLabel"; "required": false; }; "headerClass": { "alias": "headerClass"; "required": false; }; "navPrevClass": { "alias": "navPrevClass"; "required": false; }; "navNextClass": { "alias": "navNextClass"; "required": false; }; }, { "currentYearChange": "currentYearChange"; "currentMonthChange": "currentMonthChange"; "previousMonth": "previousMonth"; "nextMonth": "nextMonth"; }, never, never, true, never>; } /** * Complete translations interface for the datepicker component */ interface DatepickerTranslations { selectDate: string; selectTime: string; clear: string; close: string; today: string; selectEndDate: string; day: string; days: string; previousMonth: string; nextMonth: string; previousYear: string; nextYear: string; previousYears: string; nextYears: string; previousDecade: string; nextDecade: string; clearSelection: string; closeCalendar: string; closeCalendarOverlay: string; calendarFor: string; selectYear: string; selectDecade: string; datesSelected: string; timesSelected: string; time: string; startTime: string; endTime: string; from: string; to: string; holiday: string; month: string; year: string; decade: string; timeline: string; timeSlider: string; calendarOpened: string; calendarClosed: string; dateSelected: string; rangeSelected: string; monthChanged: string; yearChanged: string; calendarLoading: string; calendarReady: string; keyboardShortcuts: string; invalidDateFormat: string; dateBeforeMin: string; dateAfterMax: string; invalidDate: string; } /** * Partial translations - allows overriding only specific keys */ type PartialDatepickerTranslations = Partial<DatepickerTranslations>; declare class NgxsmkDatepickerContentComponent { isCalendarVisible: boolean; isCalendarOpen: boolean; isInlineMode: boolean; shouldAppendToBody: boolean; theme: string; popoverId: string; classes: DatepickerClasses | undefined; timeOnly: boolean; showTime: boolean; isMobile: boolean; mobileModalStyle: string; align: string; ariaLabel: string; isCalendarOpening: boolean; loadingMessage: string; showRanges: boolean; rangesArray: { key: string; value: [Date, Date]; }[]; mode: 'single' | 'range' | 'multiple' | 'week' | 'month' | 'quarter' | 'year' | 'timeRange'; disabled: boolean; calendarCount: number; calendarLayout: string; syncScrollEnabled: boolean; calendarMonths: { month: number; year: number; days: (Date | null)[]; }[]; weekDays: string[]; selectedDate: Date | null; startDate: Date | null; endDate: Date | null; focusedDate: Date | null; today: Date; dateTemplate: TemplateRef<unknown> | null; calendarViewMode: string; monthOptions: { label: string; value: number; }[]; currentMonth: number; yearOptions: { label: string; value: number; }[]; currentYear: number; isBackArrowDisabled: boolean; prevMonthAriaLabel: string; nextMonthAriaLabel: string; yearGrid: number[]; currentDecade: number; decadeGrid: number[]; timelineStartDate: Date | null; timelineEndDate: Date | null; timelineMonths: Date[]; minuteInterval: number; startTimeSlider: number; endTimeSlider: number; timeRangeMode: boolean; hourOptions: { label: string; value: number; }[]; minuteOptions: { label: string; value: number; }[]; secondOptions: { label: string; value: number; }[]; ampmOptions: { label: string; value: boolean; }[]; currentDisplayHour: number; currentMinute: number; currentSecond: number; isPm: boolean; showSeconds: boolean; use24Hour: boolean; startDisplayHour: number; startMinute: number; startSecond: number; startIsPm: boolean; endDisplayHour: number; endMinute: number; endSecond: number; endIsPm: boolean; clearAriaLabel: string; clearLabel: string; closeAriaLabel: string; closeLabel: string; translations: DatepickerTranslations | null; boundIsDateDisabled: (date: Date | null) => boolean; boundIsSameDay: (date1: Date | null, date2: Date | null) => boolean; boundIsHoliday: (date: Date | null) => boolean; boundIsMultipleSelected: (date: Date | null) => boolean; boundIsInRange: (date: Date | null) => boolean; boundIsPreviewInRange: (date: Date | null) => boolean; boundGetAriaLabel: (date: Date | null) => string; boundGetDayCellCustomClasses: (date: Date | null) => string | string[] | Set<string> | { [klass: string]: unknown; }; boundGetDayCellTooltip: (date: Date | null) => string | null; boundFormatDayNumber: (date: Date | null) => string; getMonthYearLabel: (month: number, year: number) => string; getCalendarAriaLabelForMonth: (month: number, year: number) => string; isTimelineMonthSelected: (date: Date) => boolean; formatTimeSliderValue: (value: number) => string; backdropClick: EventEmitter<Event>; touchStartContainer: EventEmitter<TouchEvent>; touchMoveContainer: EventEmitter<TouchEvent>; touchEndContainer: EventEmitter<TouchEvent>; rangeSelect: EventEmitter<[Date, Date]>; previousMonth: EventEmitter<void>; nextMonth: EventEmitter<void>; currentMonthChange: EventEmitter<number>; currentYearChange: EventEmitter<number>; dateClick: EventEmitter<Date>; dateHover: EventEmitter<Date | null>; dateFocus: EventEmitter<Date>; swipeStart: EventEmitter<TouchEvent>; swipeMove: EventEmitter<TouchEvent>; swipeEnd: EventEmitter<TouchEvent>; touchStart: EventEmitter<{ event: TouchEvent; day: Date | null; }>; touchMove: EventEmitter<TouchEvent>; touchEnd: EventEmitter<{ event: TouchEvent; day: Date | null; }>; viewModeChange: EventEmitter<"year" | "month" | "decade" | "timeline" | "time-slider">; changeYear: EventEmitter<number>; yearClick: EventEmitter<number>; changeDecade: EventEmitter<number>; decadeClick: EventEmitter<number>; timelineZoomOut: EventEmitter<void>; timelineZoomIn: EventEmitter<void>; timelineMonthClick: EventEmitter<Date>; startTimeSliderChange: EventEmitter<number>; endTimeSliderChange: EventEmitter<number>; currentDisplayHourChange: EventEmitter<number>; currentMinuteChange: EventEmitter<number>; currentSecondChange: EventEmitter<number>; isPmChange: EventEmitter<boolean>; timeChange: EventEmitter<void>; startDisplayHourChange: EventEmitter<number>; startMinuteChange: EventEmitter<number>; startSecondChange: EventEmitter<number>; startIsPmChange: EventEmitter<boolean>; endDisplayHourChange: EventEmitter<number>; endMinuteChange: EventEmitter<number>; endSecondChange: EventEmitter<number>; endIsPmChange: EventEmitter<boolean>; timeRangeChange: EventEmitter<void>; clearValue: EventEmitter<MouseEvent>; closeCalendar: EventEmitter<void>; escapeKey: EventEmitter<Event>; header?: CalendarHeaderComponent; popoverContainer?: ElementRef<HTMLElement>; timelineContainer?: ElementRef<HTMLElement>; closeAllSelects(): void; onTimelineMonthClick(month: Date, event: MouseEvent): void; onTimelineMonthSpace(month: Date, event: Event): void; onPopoverEscape(event: Event): void; static ɵfac: i0.ɵɵFactoryDeclaration<NgxsmkDatepickerContentComponent, never>; static ɵcmp: i0.ɵɵComponentDeclaration<NgxsmkDatepickerContentComponent, "ngxsmk-datepicker-content", never, { "isCalendarVisible": { "alias": "isCalendarVisible"; "required": false; }; "isCalendarOpen": { "alias": "isCalendarOpen"; "required": false; }; "isInlineMode": { "alias": "isInlineMode"; "required": false; }; "shouldAppendToBody": { "alias": "shouldAppendToBody"; "required": false; }; "theme": { "alias": "theme"; "required": false; }; "popoverId": { "alias": "popoverId"; "required": false; }; "classes": { "alias": "classes"; "required": false; }; "timeOnly": { "alias": "timeOnly"; "required": false; }; "showTime": { "alias": "showTime"; "required": false; }; "isMobile": { "alias": "isMobile"; "required": false; }; "mobileModalStyle": { "alias": "mobileModalStyle"; "required": false; }; "align": { "alias": "align"; "required": false; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; }; "isCalendarOpening": { "alias": "isCalendarOpening"; "required": false; }; "loadingMessage": { "alias": "loadingMessage"; "required": false; }; "showRanges": { "alias": "showRanges"; "required": false; }; "rangesArray": { "alias": "rangesArray"; "required": false; }; "mode": { "alias": "mode"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "calendarCount": { "alias": "calendarCount"; "required": false; }; "calendarLayout": { "alias": "calendarLayout"; "required": false; }; "syncScrollEnabled": { "alias": "syncScrollEnabled"; "required": false; }; "calendarMonths": { "alias": "calendarMonths"; "required": false; }; "weekDays": { "alias": "weekDays"; "required": false; }; "selectedDate": { "alias": "selectedDate"; "required": false; }; "startDate": { "alias": "startDate"; "required": false; }; "endDate": { "alias": "endDate"; "required": false; }; "focusedDate": { "alias": "focusedDate"; "required": false; }; "today": { "alias": "today"; "required": false; }; "dateTemplate": { "alias": "dateTemplate"; "required": false; }; "calendarViewMode": { "alias": "calendarViewMode"; "required": false; }; "monthOptions": { "alias": "monthOptions"; "required": false; }; "currentMonth": { "alias": "currentMonth"; "required": false; }; "yearOptions": { "alias": "yearOptions"; "required": false; }; "currentYear": { "alias": "currentYear"; "required": false; }; "isBackArrowDisabled": { "alias": "isBackArrowDisabled"; "required": false; }; "prevMonthAriaLabel": { "alias": "prevMonthAriaLabel"; "required": false; }; "nextMonthAriaLabel": { "alias": "nextMonthAriaLabel"; "required": false; }; "yearGrid": { "alias": "yearGrid"; "required": false; }; "currentDecade": { "alias": "currentDecade"; "required": false; }; "decadeGrid": { "alias": "decadeGrid"; "required": false; }; "timelineStartDate": { "alias": "timelineStartDate"; "required": false; }; "timelineEndDate": { "alias": "timelineEndDate"; "required": false; }; "timelineMonths": { "alias": "timelineMonths"; "required": false; }; "minuteInterval": { "alias": "minuteInterval"; "required": false; }; "startTimeSlider": { "alias": "startTimeSlider"; "required": false; }; "endTimeSlider": { "alias": "endTimeSlider"; "required": false; }; "timeRangeMode": { "alias": "timeRangeMode"; "required": false; }; "hourOptions": { "alias": "hourOptions"; "required": false; }; "minuteOptions": { "alias": "minuteOptions"; "required": false; }; "secondOptions": { "alias": "secondOptions"; "required": false; }; "ampmOptions": { "alias": "ampmOptions"; "required": false; }; "currentDisplayHour": { "alias": "currentDisplayHour"; "required": false; }; "currentMinute": { "alias": "currentMinute"; "required": false; }; "currentSecond": { "alias": "currentSecond"; "required": false; }; "isPm": { "alias": "isPm"; "required": false; }; "showSeconds": { "alias": "showSeconds"; "required": false; }; "use24Hour": { "alias": "use24Hour"; "required": false; }; "startDisplayHour": { "alias": "startDisplayHour"; "required": false; }; "startMinute": { "alias": "startMinute"; "required": false; }; "startSecond": { "alias": "startSecond"; "required": false; }; "startIsPm": { "alias": "startIsPm"; "required": false; }; "endDisplayHour": { "alias": "endDisplayHour"; "required": false; }; "endMinute": { "alias": "endMinute"; "required": false; }; "endSecond": { "alias": "endSecond"; "required": false; }; "endIsPm": { "alias": "endIsPm"; "required": false; }; "clearAriaLabel": { "alias": "clearAriaLabel"; "required": false; }; "clearLabel": { "alias": "clearLabel"; "required": false; }; "closeAriaLabel": { "alias": "closeAriaLabel"; "required": false; }; "closeLabel": { "alias": "closeLabel"; "required": false; }; "translations": { "alias": "translations"; "required": false; }; "boundIsDateDisabled": { "alias": "boundIsDateDisabled"; "required": false; }; "boundIsSameDay": { "alias": "boundIsSameDay"; "required": false; }; "boundIsHoliday": { "alias": "boundIsHoliday"; "required": false; }; "boundIsMultipleSelected": { "alias": "boundIsMultipleSelected"; "required": false; }; "boundIsInRange": { "alias": "boundIsInRange"; "required": false; }; "boundIsPreviewInRange": { "alias": "boundIsPreviewInRange"; "required": false; }; "boundGetAriaLabel": { "alias": "boundGetAriaLabel"; "required": false; }; "boundGetDayCellCustomClasses": { "alias": "boundGetDayCellCustomClasses"; "required": false; }; "boundGetDayCellTooltip": { "alias": "boundGetDayCellTooltip"; "required": false; }; "boundFormatDayNumber": { "alias": "boundFormatDayNumber"; "required": false; }; "getMonthYearLabel": { "alias": "getMonthYearLabel"; "required": false; }; "getCalendarAriaLabelForMonth": { "alias": "getCalendarAriaLabelForMonth"; "required": false; }; "isTimelineMonthSelected": { "alias": "isTimelineMonthSelected"; "required": false; }; "formatTimeSliderValue": { "alias": "formatTimeSliderValue"; "required": false; }; }, { "backdropClick": "backdropClick"; "touchStartContainer": "touchStartContainer"; "touchMoveContainer": "touchMoveContainer"; "touchEndContainer": "touchEndContainer"; "rangeSelect": "rangeSelect"; "previousMonth": "previousMonth"; "nextMonth": "nextMonth"; "currentMonthChange": "currentMonthChange"; "currentYearChange": "currentYearChange"; "dateClick": "dateClick"; "dateHover": "dateHover"; "dateFocus": "dateFocus"; "swipeStart": "swipeStart"; "swipeMove": "swipeMove"; "swipeEnd": "swipeEnd"; "touchStart": "touchStart"; "touchMove": "touchMove"; "touchEnd": "touchEnd"; "viewModeChange": "viewModeChange"; "changeYear": "changeYear"; "yearClick": "yearClick"; "changeDecade": "changeDecade"; "decadeClick": "decadeClick"; "timelineZoomOut": "timelineZoomOut"; "timelineZoomIn": "timelineZoomIn"; "timelineMonthClick": "timelineMonthClick"; "startTimeSliderChange": "startTimeSliderChange"; "endTimeSliderChange": "endTimeSliderChange"; "currentDisplayHourChange": "currentDisplayHourChange"; "currentMinuteChange": "currentMinuteChange"; "currentSecondChange": "currentSecondChange"; "isPmChange": "isPmChange"; "timeChange": "timeChange"; "startDisplayHourChange": "startDisplayHourChange"; "startMinuteChange": "startMinuteChange"; "startSecondChange": "startSecondChange"; "startIsPmChange": "startIsPmChange"; "endDisplayHourChange": "endDisplayHourChange"; "endMinuteChange": "endMinuteChange"; "endSecondChange": "endSecondChange"; "endIsPmChange": "endIsPmChange"; "timeRangeChange": "timeRangeChange"; "clearValue": "clearValue"; "closeCalendar": "closeCalendar"; "escapeKey": "escapeKey"; }, never, never, true, never>; } interface DayCellRenderHook { getDayCellClasses?(date: Date, isSelected: boolean, isDisabled: boolean, isToday: boolean, isHoliday: boolean): string[]; getDayCellTooltip?(date: Date, holidayLabel: string | null): string | null; formatDayNumber?(date: Date): string; } interface ValidationHook { validateDate?(date: Date, currentValue: DatepickerValue, mode: 'single' | 'range' | 'multiple' | 'week' | 'month' | 'quarter' | 'year' | 'timeRange'): boolean; validateRange?(startDate: Date, endDate: Date): boolean; getValidationError?(date: Date): string | null; } interface KeyboardShortcutHook { handleShortcut?(event: KeyboardEvent, context: KeyboardShortcutContext): boolean; getShortcutHelp?(): KeyboardShortcutHelp[]; } interface KeyboardShortcutContext { currentDate: Date; selectedDate: Date | null; startDate: Date | null; endDate: Date | null; selectedDates: Date[]; mode: 'single' | 'range' | 'multiple' | 'week' | 'month' | 'quarter' | 'year' | 'timeRange'; focusedDate: Date | null; isCalendarOpen: boolean; } interface KeyboardShortcutHelp { key: string; description: string; modifiers?: string[]; } interface DateFormatHook { formatDisplayValue?(value: DatepickerValue, mode: 'single' | 'range' | 'multiple' | 'week' | 'month' | 'quarter' | 'year' | 'timeRange'): string; formatAriaLabel?(date: Date): string; } interface EventHook { beforeDateSelect?(date: Date, currentValue: DatepickerValue): boolean; afterDateSelect?(date: Date, newValue: DatepickerValue): void; onCalendarOpen?(): void; onCalendarClose?(): void; } interface DatepickerHooks extends DayCellRenderHook, ValidationHook, KeyboardShortcutHook, DateFormatHook, EventHook { } /** * Date Adapter Interface * * Allows consumers to swap formatting/parsing logic with external date libraries * like date-fns, dayjs, or Luxon. */ interface DateAdapter { /** * Parse a date from a string or value * @param value - The value to parse (string, Date, or library-specific type) * @param onError - Optional callback for error handling. Called when parsing fails. * @returns A Date object or null if parsing fails */ parse(value: string | Date | number | unknown, onError?: (error: Error) => void): Date | null; /** * Format a date to a string * @param date - The date to format * @param format - Format string (library-specific) * @param locale - Locale string (e.g., 'en-US') * @returns Formatted date string */ format(date: Date, format?: string, locale?: string): string; /** * Check if a value is a valid date * @param value - The value to check * @returns True if the value is a valid date */ isValid(value: string | Date | number | unknown): boolean; /** * Get the start of day for a date * @param date - The date * @returns Date at start of day */ startOfDay(date: Date): Date; /** * Get the end of day for a date * @param date - The date * @returns Date at end of day */ endOfDay(date: Date): Date; /** * Add months to a date * @param date - The date * @param months - Number of months to add * @returns New date with months added */ addMonths(date: Date, months: number): Date; /** * Add days to a date * @param date - The date * @param days - Number of days to add * @returns New date with days added */ addDays(date: Date, days: number): Date; /** * Check if two dates are the same day * @param date1 - First date * @param date2 - Second date * @returns True if dates are the same day */ isSameDay(date1: Date | null, date2: Date | null): boolean; } /** * Default Date Adapter using native JavaScript Date */ declare class NativeDateAdapter implements DateAdapter { parse(value: string | Date | number | unknown, onError?: (error: Error) => void): Date | null; format(date: Date, _format?: string, locale?: string): string; isValid(value: string | Date | number | unknown): boolean; startOfDay(date: Date): Date; endOfDay(date: Date): Date; addMonths(date: Date, months: number): Date; addDays(date: Date, days: number): Date; isSameDay(date1: Date | null, date2: Date | null): boolean; } interface DatepickerConfig { weekStart?: number | null; minuteInterval?: number; holidayProvider?: HolidayProvider | null; yearRange?: number; locale?: string; timezone?: string; minDate?: Date | string | null; maxDate?: Date | string | null; dateAdapter?: DateAdapter; animations?: AnimationConfig; autoDetectMobile?: boolean; mobileModalStyle?: 'bottom-sheet' | 'center' | 'fullscreen'; } interface AnimationConfig { enabled?: boolean; duration?: number; easing?: string; property?: string; respectReducedMotion?: boolean; } declare const DEFAULT_ANIMATION_CONFIG: Required<AnimationConfig>; declare const DATEPICKER_CONFIG: InjectionToken<DatepickerConfig>; declare const DEFAULT_DATEPICKER_CONFIG: DatepickerConfig; declare function provideDatepickerConfig(config: DatepickerConfig): { provide: InjectionToken<DatepickerConfig>; useValue: { weekStart?: number | null; minuteInterval?: number; holidayProvider?: HolidayProvider | null; yearRange?: number; locale?: string; timezone?: string; minDate?: Date | string | null; maxDate?: Date | string | null; dateAdapter?: DateAdapter; animations?: AnimationConfig; autoDetectMobile?: boolean; mobileModalStyle?: "bottom-sheet" | "center" | "fullscreen"; }; }; interface ValidationError { kind: string; message?: string; } type SignalFormFieldConfig = { value?: DatepickerValue | string | (() => DatepickerValue | string) | { (): DatepickerValue | string; } | Signal<DatepickerValue | string>; disabled?: boolean | (() => boolean) | { (): boolean; } | Signal<boolean>; required?: boolean | (() => boolean) | { (): boolean; } | Signal<boolean>; errors?: ValidationError[] | (() => ValidationError[]) | { (): ValidationError[]; } | Signal<ValidationError[]>; valid?: boolean | (() => boolean) | { (): boolean; } | Signal<boolean>; invalid?: boolean | (() => boolean) | { (): boolean; } | Signal<boolean>; touched?: boolean | (() => boolean) | { (): boolean; } | Signal<boolean>; setValue?: (value: DatepickerValue | string) => void; updateValue?: (updater: () => DatepickerValue | string) => void; markAsDirty?: () => void; markAsTouched?: () => void; }; type SignalFormField = unknown; interface FieldSyncCallbacks { onValueChanged: (value: DatepickerValue) => void; onDisabledChanged: (disabled: boolean) => void; onRequiredChanged?: (required: boolean) => void; onErrorStateChanged?: (hasError: boolean) => void; onSyncError: (error: unknown) => void; normalizeValue: (value: unknown) => DatepickerValue; isValueEqual: (val1: DatepickerValue, val2: DatepickerValue) => boolean; onCalendarGenerated?: () => void; onStateChanged?: () => void; } declare class FieldSyncService { private _fieldEffectRef; private _lastKnownFieldValue; private _isUpdatingFromInternal; private readonly injector; private readFieldValue; private readDisabledState; private readFieldErrors; private readRequiredState; private hasValidationErrors; private resolveField; setupFieldSync(fieldInput: SignalFormField, callbacks: FieldSyncCallbacks): EffectRef | null; syncFieldValue(fieldInput: SignalFormField | Signal<SignalFormField> | (() => unknown) | unknown, callbacks: FieldSyncCallbacks): boolean; updateFieldFromInternal(value: DatepickerValue, fieldInput: SignalFormField | Signal<SignalFormField> | (() => unknown) | unknown): void; getLastKnownValue(): DatepickerValue | undefined; markAsTouched(fieldInput: SignalFormField | Signal<SignalFormField> | (() => unknown) | unknown): void; cleanup(): void; static ɵfac: i0.ɵɵFactoryDeclaration<FieldSyncService, never>; static ɵprov: i0.ɵɵInjectableDeclaration<FieldSyncService>; } interface TranslationService { translate(key: string, params?: Record<string, string | number>): string; getCurrentLocale(): string; } declare class DefaultTranslationService implements TranslationService { private translations; private locale; private readonly translationRegistry; constructor(); initialize(translations: DatepickerTranslations, locale?: string): void; initializeFromLocale(locale: string): void; translate(key: string, params?: Record<string, string | number>): string; getCurrentLocale(): string; static ɵfac: i0.ɵɵFactoryDeclaration<DefaultTranslationService, never>; static ɵprov: i0.ɵɵInjectableDeclaration<DefaultTranslationService>; } interface TouchGestureState { touchStartTime: number; touchStartElement: EventTarget | null; dateCellTouchStartTime: number; dateCellTouchStartDate: Date | null; dateCellTouchStartX: number; dateCellTouchStartY: number; isDateCellTouching: boolean; lastDateCellTouchDate: Date | null; dateCellTouchHandled: boolean; calendarSwipeStartX: number; calendarSwipeStartY: number; calendarSwipeStartTime: number; isCalendarSwiping: boolean; hoveredDate: Date | null; } /** Recurring date pattern configuration for disabled dates. */ type RecurringPatternInput = { pattern: 'daily' | 'weekly' | 'monthly' | 'yearly' | 'weekdays' | 'weekends'; startDate: Date; endDate?: Date; dayOfWeek?: number; dayOfMonth?: number; interval?: number; } | null; /** * Interface for Angular Material Form Field Control compatibility. * We define it here to avoid a direct dependency on @angular/material. */ interface MatFormFieldControlMock<T> { value: T | null; stateChanges: Subject<void>; id: string; placeholder: string; ngControl: NgControl | null; focused: boolean; empty: boolean; shouldLabelFloat: boolean; required: boolean; disabled: boolean; errorState: boolean; controlType?: string; autofilled?: boolean; userAriaDescribedBy?: string; setDescribedByIds(ids: string[]): void; onContainerClick(event: MouseEvent): void; } declare class NgxsmkDatepickerComponent implements OnInit, OnChanges, OnDestroy, AfterViewInit, ControlValueAccessor, MatFormFieldControlMock<DatepickerValue> { private static _idCounter; private static readonly _allInstances; private static _materialSupportRegistered; private static _patchMetadataArrays; static withMaterialSupport(matFormFieldControlToken: any, targetCmp?: any): void; _uniqueId: string; mode: 'single' | 'range' | 'multiple' | 'week' | 'month' | 'quarter' | 'year' | 'timeRange'; calendarViewMode: 'month' | 'year' | 'decade' | 'timeline' | 'time-slider'; isInvalidDate: (date: Date) => boolean; showRanges: boolean; showTime: boolean; timeOnly: boolean; timeRangeMode: boolean; showCalendarButton: boolean; minuteInterval: number; use24Hour: boolean; secondInterval: number; showSeconds: boolean; holidayProvider: HolidayProvider | null; disableHolidays: boolean; disabledDates: (string | Date)[]; disabledRanges: Array<{ start: Date | string; end: Date | string; }>; recurringPattern?: RecurringPatternInput; dateTemplate: TemplateRef<unknown> | null; private _placeholder; set placeholder(value: string | null); get placeholder(): string; inline: boolean | 'always' | 'auto'; private _inputId; set inputId(value: string); get inputId(): string; private _name; set name(value: string); get name(): string; private _autocomplete; set autocomplete(value: string); get autocomplete(): string; translations?: PartialDatepickerTranslations; translationService?: TranslationService; clearLabel: string; closeLabel: string; prevMonthAriaLabel: string; nextMonthAriaLabel: string; clearAriaLabel: string; closeAriaLabel: string; get _clearLabel(): string; get _closeLabel(): string; get _prevMonthAriaLabel(): string; get _nextMonthAriaLabel(): string; get _clearAriaLabel(): string; get _closeAriaLabel(): string; weekStart: number | null; private readonly _yearRange; set yearRange(value: number); get yearRange(): number; timezone?: string; hooks: DatepickerHooks | null; enableKeyboardShortcuts: boolean; customShortcuts: { [key: string]: (context: KeyboardShortcutContext) => boolean; } | null; autoApplyClose: boolean; /** * Range mode only: allow a one-day range by clicking the same date twice, or by closing the popover * with only a start date selected (start and end will both be that day). */ allowSameDay: boolean; displayFormat?: string; allowTyping: boolean; private _calendarCount; set calendarCount(value: number); get calendarCount(): number; calendarLayout: 'horizontal' | 'vertical' | 'auto'; defaultMonthOffset: number; /** * Configuration for synchronous scrolling in multi-calendar mode. * Keeps calendars in sync by enforcing consistent month offsets across visible calendars. * * @example * ```typescript * // Keep calendars exactly 1 month apart * <ngxsmk-datepicker * [calendarCount]="2" * [syncScroll]="{ enabled: true, monthGap: 1 }"> * </ngxsmk-datepicker> * * // Disable sync scroll (independent navigation) * <ngxsmk-datepicker * [calendarCount]="3" * [syncScroll]="{ enabled: false }"> * </ngxsmk-datepicker> * ``` */ syncScroll: { enabled?: boolean; monthGap?: number; }; align: 'left' | 'right' | 'center'; useNativePicker: boolean; enableHapticFeedback: boolean; mobileModalStyle: 'bottom-sheet' | 'center' | 'fullscreen'; mobileTimePickerStyle: 'wheel' | 'slider' | 'native'; enablePullToRefresh: boolean; mobileTheme: 'compact' | 'comfortable' | 'spacious'; enableVoiceInput: boolean; autoDetectMobile: boolean; disableFocusTrap: boolean; appendToBody: boolean; private readonly appRef; private readonly document; portalTemplate: TemplateRef<unknown>; private portalViewRef; get _shouldAppendToBody(): boolean; /** * Detects if the datepicker is rendered inside a modal/dialog so the calendar * can be appended to body and positioned above the modal. */ private isInsideModal; private readonly _isCalendarOpen; get isCalendarOpen(): boolean; set isCalendarOpen(value: boolean); private isOpeningCalendar; /** Public getter for template: true while calendar is opening/generating (loading state). */ get isCalendarOpening(): boolean; /** Returns translated "Loading calendar..." for template and ARIA. */ getCalendarLoadingMessage(): string; private openCalendarTimeoutId; private lastToggleTime; private touchStartTime; private touchStartElement; private pointerDownTime; private isPointerEvent; private previousFocusElement; private _value; set value(val: DatepickerValue); get value(): DatepickerValue; private _field; private _fieldEffectRef; set field(field: SignalFormField); get field(): SignalFormField; private syncFieldValue; private _startAtDate; set startAt(value: DateInput | null); private _locale; set locale(value: string); get locale(): string; theme: 'light' | 'dark'; get isDarkMode(): boolean; private _dateFormatPattern; private customDateFormatService; set dateFormatPattern(value: string | null); get dateFormatPattern(): string | null; private _animationConfig; /** * Animation configuration allowing customization of animation duration, easing, and reduction. * Supports prefers-reduced-motion accessibility preference automatically. * * @example * ```typescript * // Disable all animations * <ngxsmk-datepicker [animationConfig]="{ enabled: false }"></ngxsmk-datepicker> * * // Custom animation duration and easing * <ngxsmk-datepicker [animationConfig]="{ duration: 300, easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)' }"></ngxsmk-datepicker> * * // Disable specific animation properties * <ngxsmk-datepicker [animationConfig]="{ property: 'opacity' }"></ngxsmk-datepicker> * ``` */ set animationConfig(value: AnimationConfig | null); get animationConfig(): AnimationConfig | null; private _rtl; set rtl(value: boolean | null); get rtl(): boolean | null; get isRtl(): boolean; get rtlClass(): boolean; classes?: DatepickerClasses | undefined; private onChange; private onTouched; disabled: boolean; set disabledState(isDisabled: boolean); /** * Subject used for Material Form Field integration. * Emits when the component's state changes (disabled, required, error state, etc.) * * @remarks * This Subject is required for Angular Material's form field control interface. * It allows Material form fields to track state changes and update their appearance * accordingly (e.g., showing error states, floating labels, etc.). * * The Subject is properly cleaned up in ngOnDestroy() to prevent memory leaks. * It's marked as readonly to prevent external code from reassigning it. */ readonly stateChanges: Subject<void>; private _focused; private _required; private _errorState; get focused(): boolean; get empty(): boolean; get shouldLabelFloat(): boolean; get required(): boolean; set required(value: boolean); get errorState(): boolean; set errorState(value: boolean); get controlType(): string; get autofilled(): boolean; get id(): string; get describedBy(): string; /** * Aria describedby ID provided by the user or the parent form field. * Required for Angular Material form field control interface. */ userAriaDescribedBy: string; setDescribedByIds(ids: string[]): void; onContainerClick(_event: MouseEvent): void; valueChange: EventEmitter<DatepickerValue>; action: EventEmitter<{ type: string; payload?: unknown; }>; /** Emitted when validation fails (e.g. invalid typed date, date before min, after max). Message is translated. */ validationError: EventEmitter<{ code: string; message: string; }>; private _validationErrorMessage; /** User-facing validation error message when set (e.g. from typed input or min/max). */ get validationErrorMessage(): string | null; private setValidationError; private clearValidationError; private _minDate; set minDate(value: DateInput | null); get minDate(): DateInput | null; private _maxDate; set maxDate(value: DateInput | null); get maxDate(): DateInput | null; private _ranges; set ranges(value: DateRange | null); currentDate: Date; daysInMonth: (Date | null)[]; multiCalendarMonths: Array<{ month: number; year: number; days: (Date | null)[]; }>; /** * LRU (Least Recently Used) cache for calendar month generation. * Caches generated month arrays to avoid recalculating the same months. * * @remarks * Performance characteristics: * - Calendar generation: O(1) per month when cached * - Cache lookup: O(1) average case * - Cache eviction: O(n) where n = cache size (only when cache is full) * * The cache automatically evicts the least recently used entry when it reaches * MAX_CACHE_SIZE to prevent unbounded memory growth. This is especially important * for applications with many datepicker instances or long-running sessions. */ /** * Maximum number of months to cache before evicting LRU entries. * Now managed by CalendarGenerationService. */ weekDays: string[]; today: Date; selectedDate: Date | null; selectedDates: Date[]; startDate: Date | null; endDate: Date | null; hoveredDate: Date | null; rangesArray: { key: string; value: [Date, Date]; }[]; protected touchState: TouchGestureState; private dateCellTouchHandledTime; private touchHandledTimeout; private readonly activeTimeouts; private readonly activeAnimationFrames; private fieldSyncTimeoutId; private readonly touchListenersSetup; private readonly touchListenersAttached; private bottomSheetSwipeStartY; private bottomSheetSwipeCurrentY; private isBottomSheetSwiping; private readonly bottomSheetSwipeThreshold; private readonly SWIPE_THRESHOLD; private readonly SWIPE_TIME_THRESHOLD; private _currentMonth; _currentYear: number; _currentDecade: number; monthOptions: i0.Signal<{ label: string; value: number; }[]>; yearOptions: i0.Signal<{ label: string; value: number; }[]>; decadeOptions: { label: string; value: number; }[]; yearGrid: number[]; hourOptions: { label: string; value: number; }[]; minuteOptions: { label: string; value: number; }[]; secondOptions: { label: string; value: number; }[]; decadeGrid: number[]; private firstDayOfWeek; currentHour: number; currentMinute: number; currentSecond: number; currentDisplayHour: number; isPm: boolean; startHour: number; startMinute: number; startSecond: number; startDisplayHour: number; startIsPm: boolean; endHour: number; endMinute: number; endSecond: number; endDisplayHour: number; endIsPm: boolean; ampmOptions: { label: string; value: boolean; }[]; timelineMonths: Date[]; timelineStartDate: Date; timelineEndDate: Date; private timelineZoomLevel; startTimeSlider: number; endTimeSlider: number; private readonly elementRef; private readonly cdr; private readonly platformId; private readonly globalConfig; private readonly fieldSyncService; private readonly localeRegistry; private readonly translationRegistry; private readonly focusTrapService; private readonly ariaLiveService; private readonly hapticFeedbackService; private readonly calendarGenerationService; private readonly parsingService; private readonly touchService; private readonly popoverPositioningService; readonly ngControl: NgControl | null; private readonly isBrowser; private readonly dateComparator; constructor(); typedInputValue: string; private isTyping; popoverContainer?: ElementRef<HTMLElement>; readonly popoverId: string; datepickerInput?: NgxsmkDatepickerInputComponent; datepickerContent?: NgxsmkDatepickerContentComponent; private focusTrapCleanup; _translations: DatepickerTranslations | null; private _translationService; private _changeDetectionScheduled; /** * Schedules change detection to run in the next microtask. * Prevents multiple change detection cycles from being scheduled simultaneously. * * @remarks * This method is essential for zoneless compatibility. When Zone.js is not present, * Angular's automatic change detection doesn't run, so components using OnPush * strategy must manually trigger change detection when state changes. * * The debouncing mechanism prevents excessive change detection cycles when multiple * state changes occur in rapid succession (e.g., during user interactions or async * operations). Only one change detection cycle is scheduled per microtask queue. * * This pattern is compatible with both Zone.js and zoneless Angular applications. */ private scheduleChangeDetection; /** * Creates a tracked setTimeout that is automatically cleaned up on component destroy. * All timeouts created through this method are stored in activeTimeouts for proper cleanup. * * @param callback - Function to execute after delay * @param delay - Delay in milliseconds * @returns Timeout ID that can be used with clearTimeout */ private trackedSetTimeout; /** * Creates a tracked requestAnimationFrame that is automatically cancelled on component destroy. * All animation frames created through this method are stored in activeAnimationFrames for proper cleanup. * * @param callback - Function to execute on next animation frame * @r