igniteui-angular
Version:
Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps
1,203 lines (1,195 loc) • 192 kB
JavaScript
import * as i0 from '@angular/core';
import { InjectionToken, inject, ElementRef, EventEmitter, HostListener, Output, Input, Directive, HostBinding, TemplateRef, NgZone, booleanAttribute, ViewChildren, Component, ChangeDetectionStrategy, Injectable, LOCALE_ID, ChangeDetectorRef, Pipe, DestroyRef, forwardRef, ContentChild, ViewChild, NgModule } from '@angular/core';
import { TitleCasePipe, getLocaleFirstDayOfWeek, NgTemplateOutlet, DatePipe } from '@angular/common';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { Subject, fromEvent, interval, noop } from 'rxjs';
import { debounce, takeUntil, tap, switchMap, skipLast } from 'rxjs/operators';
import { CalendarDay, PlatformUtil, isDate, getNextActiveDate, isDateInRanges, DateRangeType, calendarRange, areSameMonth, isPreviousMonth, isNextMonth, getYearRange, DateTimeUtil, getCurrentResourceStrings, CalendarResourceStringsEN, isEqual, THEME_TOKEN, getComponentTheme, getClosestActiveDate, getPreviousActiveDate, generateMonth, intoChunks, formatToParts } from 'igniteui-angular/core';
import { EventManager } from '@angular/platform-browser';
import { IgxIconComponent } from 'igniteui-angular/icon';
/**
* This file contains all the directives used by the @link IgxCalendarComponent.
* Except for the directives which are used for templating the calendar itself
* you should generally not use them directly.
*
* @preferred
*/
const IGX_CALENDAR_VIEW_ITEM = new InjectionToken('IgxCalendarViewItem');
class IgxCalendarViewBaseDirective {
constructor() {
this.elementRef = inject(ElementRef);
this.showActive = false;
this.itemSelection = new EventEmitter();
}
get nativeElement() {
return this.elementRef.nativeElement;
}
onMouseDown(event) {
event.preventDefault();
this.itemSelection.emit(this.value);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxCalendarViewBaseDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.2", type: IgxCalendarViewBaseDirective, isStandalone: true, inputs: { value: "value", date: "date", showActive: "showActive" }, outputs: { itemSelection: "itemSelection" }, host: { listeners: { "mousedown": "onMouseDown($event)" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxCalendarViewBaseDirective, decorators: [{
type: Directive
}], propDecorators: { value: [{
type: Input
}], date: [{
type: Input
}], showActive: [{
type: Input
}], itemSelection: [{
type: Output
}], onMouseDown: [{
type: HostListener,
args: ['mousedown', ['$event']]
}] } });
/**
* @hidden
*/
class IgxCalendarYearDirective extends IgxCalendarViewBaseDirective {
get isCurrent() {
return CalendarDay.today.year === this.value.getFullYear();
}
get isSelected() {
return this.value.getFullYear() === this.date.getFullYear();
}
get isActive() {
return this.isSelected && this.showActive;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxCalendarYearDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.2", type: IgxCalendarYearDirective, isStandalone: true, selector: "[igxCalendarYear]", host: { properties: { "class.igx-calendar-view__item--current": "this.isCurrent", "class.igx-calendar-view__item--selected": "this.isSelected", "class.igx-calendar-view__item--active": "this.isActive" } }, providers: [
{ provide: IGX_CALENDAR_VIEW_ITEM, useExisting: IgxCalendarYearDirective }
], exportAs: ["igxCalendarYear"], usesInheritance: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxCalendarYearDirective, decorators: [{
type: Directive,
args: [{
selector: '[igxCalendarYear]',
providers: [
{ provide: IGX_CALENDAR_VIEW_ITEM, useExisting: IgxCalendarYearDirective }
],
exportAs: 'igxCalendarYear',
standalone: true
}]
}], propDecorators: { isCurrent: [{
type: HostBinding,
args: ['class.igx-calendar-view__item--current']
}], isSelected: [{
type: HostBinding,
args: ['class.igx-calendar-view__item--selected']
}], isActive: [{
type: HostBinding,
args: ['class.igx-calendar-view__item--active']
}] } });
class IgxCalendarMonthDirective extends IgxCalendarViewBaseDirective {
get isCurrent() {
const today = CalendarDay.today;
const date = CalendarDay.from(this.value);
return date.year === today.year && date.month === today.month;
}
get isSelected() {
return (this.value.getFullYear() === this.date.getFullYear() &&
this.value.getMonth() === this.date.getMonth());
}
get isActive() {
return this.isSelected && this.showActive;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxCalendarMonthDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.2", type: IgxCalendarMonthDirective, isStandalone: true, selector: "[igxCalendarMonth]", host: { properties: { "class.igx-calendar-view__item--current": "this.isCurrent", "class.igx-calendar-view__item--selected": "this.isSelected", "class.igx-calendar-view__item--active": "this.isActive" } }, providers: [
{ provide: IGX_CALENDAR_VIEW_ITEM, useExisting: IgxCalendarMonthDirective }
], exportAs: ["igxCalendarMonth"], usesInheritance: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxCalendarMonthDirective, decorators: [{
type: Directive,
args: [{
selector: '[igxCalendarMonth]',
providers: [
{ provide: IGX_CALENDAR_VIEW_ITEM, useExisting: IgxCalendarMonthDirective }
],
exportAs: 'igxCalendarMonth',
standalone: true
}]
}], propDecorators: { isCurrent: [{
type: HostBinding,
args: ['class.igx-calendar-view__item--current']
}], isSelected: [{
type: HostBinding,
args: ['class.igx-calendar-view__item--selected']
}], isActive: [{
type: HostBinding,
args: ['class.igx-calendar-view__item--active']
}] } });
/**
* @hidden
*/
class IgxCalendarHeaderTitleTemplateDirective {
constructor() {
this.template = inject(TemplateRef);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxCalendarHeaderTitleTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.2", type: IgxCalendarHeaderTitleTemplateDirective, isStandalone: true, selector: "[igxCalendarHeaderTitle]", ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxCalendarHeaderTitleTemplateDirective, decorators: [{
type: Directive,
args: [{
selector: '[igxCalendarHeaderTitle]',
standalone: true
}]
}] });
/**
* @hidden
*/
class IgxCalendarHeaderTemplateDirective {
constructor() {
this.template = inject(TemplateRef);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxCalendarHeaderTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.2", type: IgxCalendarHeaderTemplateDirective, isStandalone: true, selector: "[igxCalendarHeader]", ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxCalendarHeaderTemplateDirective, decorators: [{
type: Directive,
args: [{
selector: '[igxCalendarHeader]',
standalone: true
}]
}] });
/**
* @hidden
*/
class IgxCalendarSubheaderTemplateDirective {
constructor() {
this.template = inject(TemplateRef);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxCalendarSubheaderTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.2", type: IgxCalendarSubheaderTemplateDirective, isStandalone: true, selector: "[igxCalendarSubheader]", ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxCalendarSubheaderTemplateDirective, decorators: [{
type: Directive,
args: [{
selector: '[igxCalendarSubheader]',
standalone: true
}]
}] });
/**
* @hidden
*/
class IgxCalendarScrollPageDirective {
constructor() {
this.element = inject(ElementRef);
this.zone = inject(NgZone);
this.platform = inject(PlatformUtil);
/**
* @hidden
*/
this.destroy$ = new Subject();
}
/**
* @hidden
*/
onMouseDown(event) {
event.preventDefault();
this.startScroll();
}
/**
* @hidden
*/
onMouseUp(event) {
this.stopScroll(event);
}
/**
* @hidden
*/
ngAfterViewInit() {
fromEvent(this.element.nativeElement, 'keyup').pipe(debounce(() => interval(100)), takeUntil(this.destroy$)).subscribe((event) => {
this.stopScroll(event);
});
this.zone.runOutsideAngular(() => {
fromEvent(this.element.nativeElement, 'keydown').pipe(tap((event) => {
if (this.platform.isActivationKey(event)) {
event.preventDefault();
event.stopPropagation();
}
}), debounce(() => interval(100)), takeUntil(this.destroy$)).subscribe((event) => {
if (this.platform.isActivationKey(event)) {
this.zone.run(() => this.startScroll(true));
}
});
});
}
/**
* @hidden
*/
ngOnDestroy() {
this.destroy$.next(true);
this.destroy$.complete();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxCalendarScrollPageDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.2", type: IgxCalendarScrollPageDirective, isStandalone: true, selector: "[igxCalendarScrollPage]", inputs: { startScroll: "startScroll", stopScroll: "stopScroll" }, host: { listeners: { "mousedown": "onMouseDown($event)", "mouseup": "onMouseUp($event)" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxCalendarScrollPageDirective, decorators: [{
type: Directive,
args: [{
selector: '[igxCalendarScrollPage]',
standalone: true
}]
}], propDecorators: { startScroll: [{
type: Input
}], stopScroll: [{
type: Input
}], onMouseDown: [{
type: HostListener,
args: ['mousedown', ['$event']]
}], onMouseUp: [{
type: HostListener,
args: ['mouseup', ['$event']]
}] } });
/**
* Sets the selection type - single, multi or range.
*/
const CalendarSelection = {
SINGLE: 'single',
MULTI: 'multi',
RANGE: 'range'
};
const IgxCalendarView = {
Month: 'month',
Year: 'year',
Decade: 'decade'
};
const MDAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
const FEBRUARY = 1;
const range = (start = 0, stop, step = 1) => {
const res = [];
const cur = (stop === undefined) ? 0 : start;
const max = (stop === undefined) ? start : stop;
for (let i = cur; step < 0 ? i > max : i < max; i += step) {
res.push(i);
}
return res;
};
/**
* Returns true for leap years, false for non-leap years.
*
* @export
* @param year
* @returns
*/
const isLeap = (year) => (year % 4 === 0) && ((year % 100 !== 0) || (year % 400 === 0));
const weekDay = (year, month, day) => new Date(year, month, day).getDay();
/**
* Return weekday and number of days for year, month.
*
* @export
* @param year
* @param month
* @returns
*/
const monthRange = (year, month) => {
if ((month < 0) || (month > 11)) {
throw new Error('Invalid month specified');
}
const day = weekDay(year, month, 1);
let nDays = MDAYS[month];
if ((month === FEBRUARY) && (isLeap(year))) {
nDays++;
}
return [day, nDays];
};
class Calendar {
timedelta(date, interval, units) {
const ret = new Date(date);
const checkRollover = () => {
if (ret.getDate() !== date.getDate()) {
ret.setDate(0);
}
};
switch (interval.toLowerCase()) {
case 'year':
ret.setFullYear(ret.getFullYear() + units);
checkRollover();
break;
case 'quarter':
ret.setMonth(ret.getMonth() + 3 * units);
checkRollover();
break;
case 'month':
ret.setMonth(ret.getMonth() + units);
checkRollover();
break;
case 'week':
ret.setDate(ret.getDate() + 7 * units);
break;
case 'day':
ret.setDate(ret.getDate() + units);
break;
case 'hour':
ret.setTime(ret.getTime() + units * 3600000);
break;
case 'minute':
ret.setTime(ret.getTime() + units * 60000);
break;
case 'second':
ret.setTime(ret.getTime() + units * 1000);
break;
default:
throw new Error('Invalid interval specifier');
}
return ret;
}
}
var IgxCalendarNavDirection;
(function (IgxCalendarNavDirection) {
IgxCalendarNavDirection[IgxCalendarNavDirection["NEXT"] = 1] = "NEXT";
IgxCalendarNavDirection[IgxCalendarNavDirection["PREV"] = -1] = "PREV";
})(IgxCalendarNavDirection || (IgxCalendarNavDirection = {}));
const DAY_INTERVAL_TOKEN = new InjectionToken("DAY_INTERVAL");
class IgxCalendarViewDirective {
get activeDescendant() {
if (this.tabIndex === -1)
return;
return this.date.getTime();
}
/**
* Gets/sets the selected date of the view.
* By default it's the current date.
* ```typescript
* let date = this.view.date;
* ```
*
* @memberof IgxYearsViewComponent
*/
set date(value) {
if (!isDate(value))
return;
this._date = value;
}
get date() {
return this._date;
}
/**
* Gets the `locale` of the view.
* Default value is `"en"`.
* ```typescript
* let locale = this.view.locale;
* ```
*
* @memberof IgxCalendarViewDirective
*/
get locale() {
return this._locale;
}
/**
* Sets the `locale` of the view.
* Expects a valid BCP 47 language tag.
* Default value is `"en"`.
*
* @memberof IgxCalendarViewDirective
*/
set locale(value) {
this._locale = value;
this.initFormatter();
}
constructor() {
this.dayInterval = inject(DAY_INTERVAL_TOKEN);
this.role = 'grid';
this.tabIndex = 0;
/**
* Applies styles to the active item on view focus.
*/
this.showActive = false;
/**
* Emits an event when a selection is made in the view.
* Provides reference the `date` property in the component.
* @memberof IgxCalendarViewDirective
*/
this.selected = new EventEmitter();
/**
* Emits an event when a page changes in the view.
* Provides reference the `date` property in the component.
* @memberof IgxCalendarViewDirective
* @hidden @internal
*/
this.pageChanged = new EventEmitter();
/**
* Emits an event when the active date has changed.
* @memberof IgxCalendarViewDirective
* @hidden @internal
*/
this.activeDateChanged = new EventEmitter();
/**
* @hidden
*/
this._locale = "en";
/**
* @hidden
* @internal
*/
this._date = new Date();
/**
* @hidden
*/
this._onTouchedCallback = noop;
/**
* @hidden
*/
this._onChangeCallback = noop;
this.initFormatter();
}
/**
* @hidden
*/
onKeydownArrowDown(event) {
this.navigateTo(event, IgxCalendarNavDirection.NEXT, 3);
}
/**
* @hidden
*/
onKeydownArrowUp(event) {
this.navigateTo(event, IgxCalendarNavDirection.PREV, 3);
}
/**
* @hidden
*/
onKeydownArrowRight(event) {
this.navigateTo(event, IgxCalendarNavDirection.NEXT, 1);
}
/**
* @hidden
*/
onKeydownArrowLeft(event) {
this.navigateTo(event, IgxCalendarNavDirection.PREV, 1);
}
/**
* @hidden
*/
onKeydownHome(event) {
event.preventDefault();
event.stopPropagation();
this.date = this.range.at(0);
this.activeDateChanged.emit(this.date);
}
/**
* @hidden
*/
onKeydownEnd(event) {
event.preventDefault();
event.stopPropagation();
this.date = this.range.at(-1);
this.activeDateChanged.emit(this.date);
}
/**
* @hidden
*/
onKeydownEnter(event) {
event.stopPropagation();
this.selected.emit(this.date);
this._onChangeCallback(this.date);
}
/**
* @hidden
*/
handleFocus() {
this.showActive = true;
}
/**
* @hidden
*/
handleBlur() {
this.showActive = false;
}
/**
* @hidden
*/
selectDate(value) {
this.date = value;
this.selected.emit(this.date);
this._onChangeCallback(this.date);
}
/**
* @hidden
*/
registerOnChange(fn) {
this._onChangeCallback = fn;
}
/**
* @hidden
*/
registerOnTouched(fn) {
this._onTouchedCallback = fn;
}
/**
* @hidden
*/
writeValue(value) {
if (value) {
this.date = value;
}
}
/**
* @hidden
*/
navigateTo(event, direction, delta) {
event.preventDefault();
event.stopPropagation();
const date = getNextActiveDate(CalendarDay.from(this.date).add(this.dayInterval, direction * delta), []);
const outOfRange = !isDateInRanges(date, [
{
type: DateRangeType.Between,
dateRange: [this.range.at(0), this.range.at(-1)],
},
]);
if (outOfRange) {
this.pageChanged.emit(date.native);
}
this.date = date.native;
this.activeDateChanged.emit(this.date);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxCalendarViewDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "21.0.2", type: IgxCalendarViewDirective, isStandalone: true, inputs: { role: "role", tabIndex: "tabIndex", formatView: ["formatView", "formatView", booleanAttribute], showActive: ["showActive", "showActive", booleanAttribute], date: "date", locale: "locale" }, outputs: { selected: "selected", pageChanged: "pageChanged", activeDateChanged: "activeDateChanged" }, host: { listeners: { "keydown.arrowdown": "onKeydownArrowDown($event)", "keydown.arrowup": "onKeydownArrowUp($event)", "keydown.arrowright": "onKeydownArrowRight($event)", "keydown.arrowleft": "onKeydownArrowLeft($event)", "keydown.home": "onKeydownHome($event)", "keydown.end": "onKeydownEnd($event)", "keydown.enter": "onKeydownEnter($event)", "focus": "handleFocus()", "blur": "handleBlur()" }, properties: { "attr.role": "this.role", "attr.tabIndex": "this.tabIndex", "attr.aria-activeDescendant": "this.activeDescendant" } }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: IgxCalendarViewDirective,
multi: true,
},
], viewQueries: [{ propertyName: "viewItems", predicate: IGX_CALENDAR_VIEW_ITEM, descendants: true, read: IGX_CALENDAR_VIEW_ITEM }], ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxCalendarViewDirective, decorators: [{
type: Directive,
args: [{
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: IgxCalendarViewDirective,
multi: true,
},
],
standalone: true,
}]
}], ctorParameters: () => [], propDecorators: { role: [{
type: HostBinding,
args: ["attr.role"]
}, {
type: Input
}], tabIndex: [{
type: HostBinding,
args: ["attr.tabIndex"]
}, {
type: Input
}], activeDescendant: [{
type: HostBinding,
args: ['attr.aria-activeDescendant']
}], formatView: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], showActive: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], selected: [{
type: Output
}], pageChanged: [{
type: Output
}], activeDateChanged: [{
type: Output
}], viewItems: [{
type: ViewChildren,
args: [IGX_CALENDAR_VIEW_ITEM, { read: IGX_CALENDAR_VIEW_ITEM }]
}], date: [{
type: Input
}], locale: [{
type: Input
}], onKeydownArrowDown: [{
type: HostListener,
args: ["keydown.arrowdown", ["$event"]]
}], onKeydownArrowUp: [{
type: HostListener,
args: ["keydown.arrowup", ["$event"]]
}], onKeydownArrowRight: [{
type: HostListener,
args: ["keydown.arrowright", ["$event"]]
}], onKeydownArrowLeft: [{
type: HostListener,
args: ["keydown.arrowleft", ["$event"]]
}], onKeydownHome: [{
type: HostListener,
args: ["keydown.home", ["$event"]]
}], onKeydownEnd: [{
type: HostListener,
args: ["keydown.end", ["$event"]]
}], onKeydownEnter: [{
type: HostListener,
args: ["keydown.enter", ["$event"]]
}], handleFocus: [{
type: HostListener,
args: ["focus"]
}], handleBlur: [{
type: HostListener,
args: ["blur"]
}] } });
let NEXT_ID$3 = 0;
class IgxMonthsViewComponent extends IgxCalendarViewDirective {
constructor() {
super(...arguments);
this.el = inject(ElementRef);
this.#standalone = true;
this.platform = inject(PlatformUtil);
/**
* Sets/gets the `id` of the months view.
* If not set, the `id` will have value `"igx-months-view-0"`.
* ```html
* <igx-months-view id="my-months-view"></igx-months-view>
* ```
* ```typescript
* let monthsViewId = this.monthsView.id;
* ```
*
* @memberof IgxMonthsViewComponent
*/
this.id = `igx-months-view-${NEXT_ID$3++}`;
/**
* The default css class applied to the component.
*
* @hidden
*/
this.viewClass = true;
/**
* Gets/sets whether the view should be rendered
* according to the locale and format, if any.
*/
this.formatView = true;
/**
* @hidden
*/
this._monthFormat = "short";
}
#standalone;
/**
* @hidden @internal
*/
get standalone() {
return this.#standalone;
}
set standalone(value) {
this.#standalone = value;
}
/**
* Gets the month format option of the months view.
* ```typescript
* let monthFormat = this.monthsView.monthFormat.
* ```
*/
get monthFormat() {
return this._monthFormat;
}
/**
* Sets the month format option of the months view.
* ```html
* <igx-months-view> [monthFormat]="short'"</igx-months-view>
* ```
*
* @memberof IgxMonthsViewComponent
*/
set monthFormat(value) {
this._monthFormat = value;
this.initFormatter();
}
/**
* Returns an array of date objects which are then used to
* properly render the month names.
*
* Used in the template of the component
*
* @hidden @internal
*/
get range() {
const start = CalendarDay.from(this.date).set({ date: 1, month: 0 });
const end = start.add(this.dayInterval, 12);
return Array.from(calendarRange({ start, end, unit: this.dayInterval })).map((m) => m.native);
}
/**
* @hidden
*/
onMouseDown() {
if (this.tabIndex !== -1 && this.platform.isBrowser && this.el?.nativeElement) {
this.el.nativeElement.focus();
}
}
/**
* Returns the locale representation of the month in the months view.
*
* @hidden
*/
formattedMonth(value) {
const rawFormatter = new Intl.DateTimeFormat(this.locale, {
month: "long",
year: "numeric",
});
if (this.formatView) {
return {
long: rawFormatter.format(value),
formatted: this._formatter.format(value),
};
}
return {
long: rawFormatter.format(value),
formatted: `${value.getMonth()}`,
};
}
/**
* @hidden
*/
monthTracker(_, item) {
return `${item.getMonth()}}`;
}
/**
* @hidden
*/
initFormatter() {
this._formatter = new Intl.DateTimeFormat(this._locale, {
month: this.monthFormat,
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxMonthsViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.2", type: IgxMonthsViewComponent, isStandalone: true, selector: "igx-months-view", inputs: { id: "id", standalone: "standalone", monthFormat: "monthFormat", formatView: ["formatView", "formatView", booleanAttribute] }, host: { properties: { "attr.id": "this.id", "class.igx-calendar-view": "this.viewClass", "class.igx-calendar-view--standalone": "this.standalone" } }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: IgxMonthsViewComponent,
multi: true,
},
{
provide: DAY_INTERVAL_TOKEN,
useValue: "month",
},
], usesInheritance: true, ngImport: i0, template: "<div class=\"igx-calendar-view__items\" role=\"row\">\n @for (month of range; track monthTracker($index, month)) {\n <span\n igxCalendarMonth\n #item=\"igxCalendarMonth\"\n class=\"igx-calendar-view__item\"\n role=\"gridcell\"\n [attr.id]=\"month.getTime()\"\n [attr.aria-label]=\"formattedMonth(month).long\"\n [attr.aria-selected]=\"item.isSelected\"\n [value]=\"month\"\n [date]=\"date\"\n [showActive]=\"showActive\"\n (itemSelection)=\"selectDate($event)\"\n (mousedown)=\"onMouseDown()\"\n >\n <span class=\"igx-calendar-view__item-inner\" aria-hidden=\"true\">\n {{ formattedMonth(month).formatted | titlecase }}\n </span>\n </span>\n }\n</div>\n", dependencies: [{ kind: "directive", type: IgxCalendarMonthDirective, selector: "[igxCalendarMonth]", exportAs: ["igxCalendarMonth"] }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxMonthsViewComponent, decorators: [{
type: Component,
args: [{ providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: IgxMonthsViewComponent,
multi: true,
},
{
provide: DAY_INTERVAL_TOKEN,
useValue: "month",
},
], selector: "igx-months-view", imports: [IgxCalendarMonthDirective, TitleCasePipe], template: "<div class=\"igx-calendar-view__items\" role=\"row\">\n @for (month of range; track monthTracker($index, month)) {\n <span\n igxCalendarMonth\n #item=\"igxCalendarMonth\"\n class=\"igx-calendar-view__item\"\n role=\"gridcell\"\n [attr.id]=\"month.getTime()\"\n [attr.aria-label]=\"formattedMonth(month).long\"\n [attr.aria-selected]=\"item.isSelected\"\n [value]=\"month\"\n [date]=\"date\"\n [showActive]=\"showActive\"\n (itemSelection)=\"selectDate($event)\"\n (mousedown)=\"onMouseDown()\"\n >\n <span class=\"igx-calendar-view__item-inner\" aria-hidden=\"true\">\n {{ formattedMonth(month).formatted | titlecase }}\n </span>\n </span>\n }\n</div>\n" }]
}], propDecorators: { id: [{
type: HostBinding,
args: ["attr.id"]
}, {
type: Input
}], viewClass: [{
type: HostBinding,
args: ["class.igx-calendar-view"]
}], standalone: [{
type: Input
}, {
type: HostBinding,
args: ["class.igx-calendar-view--standalone"]
}], monthFormat: [{
type: Input
}], formatView: [{
type: Input,
args: [{ transform: booleanAttribute }]
}] } });
class IgxYearsViewComponent extends IgxCalendarViewDirective {
constructor() {
super(...arguments);
this.el = inject(ElementRef);
this.#standalone = true;
this.platform = inject(PlatformUtil);
/**
* The default css class applied to the component.
*
* @hidden
*/
this.viewClass = true;
/**
* @hidden
*/
this._yearFormat = "numeric";
/**
* @hidden
*/
this._yearsPerPage = 15;
}
#standalone;
/**
* @hidden @internal
*/
get standalone() {
return this.#standalone;
}
set standalone(value) {
this.#standalone = value;
}
/**
* Gets the year format option of the years view.
* ```typescript
* let yearFormat = this.yearsView.yearFormat.
* ```
*/
get yearFormat() {
return this._yearFormat;
}
/**
* Sets the year format option of the years view.
* ```html
* <igx-years-view [yearFormat]="numeric"></igx-years-view>
* ```
*
* @memberof IgxYearsViewComponent
*/
set yearFormat(value) {
this._yearFormat = value;
this.initFormatter();
}
/**
* Returns an array of date objects which are then used to properly
* render the years.
*
* Used in the template of the component.
*
* @hidden @internal
*/
get range() {
const year = this.date.getFullYear();
const start = new CalendarDay({
year: Math.floor(year / this._yearsPerPage) * this._yearsPerPage,
month: this.date.getMonth(),
});
const end = start.add(this.dayInterval, this._yearsPerPage);
return Array.from(calendarRange({ start, end, unit: this.dayInterval })).map((m) => m.native);
}
/**
* Returns the locale representation of the year in the years view.
*
* @hidden
*/
formattedYear(value) {
const rawFormatter = new Intl.DateTimeFormat(this.locale, { year: 'numeric' });
if (this.formatView) {
return {
long: rawFormatter.format(value),
formatted: this._formatter.format(value)
};
}
return {
long: rawFormatter.format(value),
formatted: `${value.getFullYear()}`
};
}
/**
* @hidden
*/
yearTracker(_, item) {
return `${item.getFullYear()}}`;
}
/**
* @hidden
*/
initFormatter() {
this._formatter = new Intl.DateTimeFormat(this._locale, {
year: this.yearFormat,
});
}
/**
* @hidden
*/
onMouseDown() {
if (this.tabIndex !== -1 && this.platform.isBrowser && this.el?.nativeElement) {
this.el.nativeElement.focus();
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxYearsViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.2", type: IgxYearsViewComponent, isStandalone: true, selector: "igx-years-view", inputs: { standalone: "standalone", yearFormat: "yearFormat" }, host: { properties: { "class.igx-calendar-view": "this.viewClass", "class.igx-calendar-view--standalone": "this.standalone" } }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: IgxYearsViewComponent,
multi: true,
},
{
provide: DAY_INTERVAL_TOKEN,
useValue: "year",
},
], usesInheritance: true, ngImport: i0, template: "<div class=\"igx-calendar-view__items\" role=\"row\">\n @for (year of range; track yearTracker($index, year)) {\n <span\n igxCalendarYear\n #item=\"igxCalendarYear\"\n class=\"igx-calendar-view__item\"\n role=\"gridcell\"\n [attr.id]=\"year.getTime()\"\n [attr.aria-label]=\"formattedYear(year).long\"\n [attr.aria-selected]=\"item.isSelected\"\n [attr.aria-current]=\"item.isCurrent\"\n [value]=\"year\"\n [date]=\"date\"\n [showActive]=\"showActive\"\n (itemSelection)=\"selectDate($event)\"\n (mousedown)=\"onMouseDown()\"\n >\n <span class=\"igx-calendar-view__item-inner\" aria-hidden=\"true\">\n {{ formattedYear(year).formatted }}\n </span>\n </span>\n }\n</div>\n", dependencies: [{ kind: "directive", type: IgxCalendarYearDirective, selector: "[igxCalendarYear]", exportAs: ["igxCalendarYear"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxYearsViewComponent, decorators: [{
type: Component,
args: [{ providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: IgxYearsViewComponent,
multi: true,
},
{
provide: DAY_INTERVAL_TOKEN,
useValue: "year",
},
], selector: "igx-years-view", imports: [IgxCalendarYearDirective], template: "<div class=\"igx-calendar-view__items\" role=\"row\">\n @for (year of range; track yearTracker($index, year)) {\n <span\n igxCalendarYear\n #item=\"igxCalendarYear\"\n class=\"igx-calendar-view__item\"\n role=\"gridcell\"\n [attr.id]=\"year.getTime()\"\n [attr.aria-label]=\"formattedYear(year).long\"\n [attr.aria-selected]=\"item.isSelected\"\n [attr.aria-current]=\"item.isCurrent\"\n [value]=\"year\"\n [date]=\"date\"\n [showActive]=\"showActive\"\n (itemSelection)=\"selectDate($event)\"\n (mousedown)=\"onMouseDown()\"\n >\n <span class=\"igx-calendar-view__item-inner\" aria-hidden=\"true\">\n {{ formattedYear(year).formatted }}\n </span>\n </span>\n }\n</div>\n" }]
}], propDecorators: { viewClass: [{
type: HostBinding,
args: ["class.igx-calendar-view"]
}], standalone: [{
type: Input
}, {
type: HostBinding,
args: ['class.igx-calendar-view--standalone']
}], yearFormat: [{
type: Input
}] } });
/**
* @hidden
*/
class IgxDayItemComponent {
constructor() {
this.elementRef = inject(ElementRef);
this.hideOutsideDays = false;
this.isLastInRange = false;
this.isFirstInRange = false;
this.isWithinRange = false;
this.isWithinPreviewRange = false;
this.hideLeadingDays = false;
this.hideTrailingDays = false;
this.dateSelection = new EventEmitter();
this.mouseEnter = new EventEmitter();
this.mouseLeave = new EventEmitter();
this.mouseDown = new EventEmitter();
this.isActive = false;
this._selected = false;
}
/**
* Returns boolean indicating if the day is selected
*
*/
get selected() {
return this._selected;
}
/**
* Selects the day
*/
set selected(value) {
this._selected = value;
}
get hideLeading() {
return this.hideLeadingDays && this.isPreviousMonth;
}
get hideTrailing() {
return this.hideTrailingDays && this.isNextMonth;
}
get isCurrentMonth() {
return areSameMonth(this.date, this.viewDate);
}
get isPreviousMonth() {
return isPreviousMonth(this.date, this.viewDate);
}
get isNextMonth() {
return isNextMonth(this.date, this.viewDate);
}
get nativeElement() {
return this.elementRef.nativeElement;
}
get isSelectedCSS() {
const selectable = !this.isInactive || this.isWithinPreviewRange ||
(this.isWithinRange && this.selection === "range");
return !this.isDisabled && selectable && this.selected;
}
get isInactive() {
return !this.isCurrentMonth;
}
get isHidden() {
return (this.hideLeading || this.hideTrailing) && this.isInactive;
}
get isToday() {
return !this.isInactive && this.date.equalTo(CalendarDay.today);
}
get isWeekend() {
return this.date.weekend;
}
get isDisabled() {
if (!this.disabledDates) {
return false;
}
return isDateInRanges(this.date, this.disabledDates);
}
get isFocusable() {
return this.isCurrentMonth && !this.isHidden && !this.isDisabled;
}
onMouseEnter() {
this.mouseEnter.emit();
}
onMouseLeave() {
this.mouseLeave.emit();
}
onMouseDown(event) {
event.preventDefault();
this.mouseDown.emit();
}
get isWithinRangeCSS() {
return !this.isSingleSelection && this.isWithinRange;
}
get isWithinPreviewRangeCSS() {
return !this.isSingleSelection && this.isWithinPreviewRange;
}
get isSpecial() {
if (!this.specialDates) {
return false;
}
return !this.isInactive && isDateInRanges(this.date, this.specialDates);
}
get isDisabledCSS() {
return this.isHidden || this.isDisabled;
}
get isSingleSelection() {
return this.selection !== CalendarSelection.RANGE;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxDayItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "21.0.2", type: IgxDayItemComponent, isStandalone: true, selector: "igx-day-item", inputs: { date: "date", viewDate: "viewDate", selection: "selection", selected: "selected", disabledDates: "disabledDates", specialDates: "specialDates", hideOutsideDays: ["hideOutsideDays", "hideOutsideDays", booleanAttribute], isLastInRange: ["isLastInRange", "isLastInRange", booleanAttribute], isFirstInRange: ["isFirstInRange", "isFirstInRange", booleanAttribute], isWithinRange: ["isWithinRange", "isWithinRange", booleanAttribute], isWithinPreviewRange: ["isWithinPreviewRange", "isWithinPreviewRange", booleanAttribute], hideLeadingDays: ["hideLeadingDays", "hideLeadingDays", booleanAttribute], hideTrailingDays: ["hideTrailingDays", "hideTrailingDays", booleanAttribute], isActive: ["isActive", "isActive", booleanAttribute] }, outputs: { dateSelection: "dateSelection", mouseEnter: "mouseEnter", mouseLeave: "mouseLeave", mouseDown: "mouseDown" }, host: { properties: { "class.igx-days-view__date--last": "this.isLastInRange", "class.igx-days-view__date--first": "this.isFirstInRange", "class.igx-days-view__date--active": "this.isActive", "class.igx-days-view__date--selected": "this.isSelectedCSS", "class.igx-days-view__date--inactive": "this.isInactive", "class.igx-days-view__date--hidden": "this.isHidden", "class.igx-days-view__date--current": "this.isToday", "class.igx-days-view__date--weekend": "this.isWeekend", "class.igx-days-view__date--range": "this.isWithinRangeCSS", "class.igx-days-view__date--range-preview": "this.isWithinPreviewRangeCSS", "class.igx-days-view__date--special": "this.isSpecial", "class.igx-days-view__date--disabled": "this.isDisabledCSS", "class.igx-days-view__date--single": "this.isSingleSelection" } }, ngImport: i0, template: "<span\n aria-hidden=\"true\"\n class=\"igx-days-view__date-inner\"\n (mouseenter)=\"onMouseEnter()\"\n (mouseleave)=\"onMouseLeave()\"\n (mousedown)=\"onMouseDown($event)\"\n>\n <ng-content></ng-content>\n</span>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxDayItemComponent, decorators: [{
type: Component,
args: [{ selector: 'igx-day-item', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, template: "<span\n aria-hidden=\"true\"\n class=\"igx-days-view__date-inner\"\n (mouseenter)=\"onMouseEnter()\"\n (mouseleave)=\"onMouseLeave()\"\n (mousedown)=\"onMouseDown($event)\"\n>\n <ng-content></ng-content>\n</span>\n" }]
}], propDecorators: { date: [{
type: Input
}], viewDate: [{
type: Input
}], selection: [{
type: Input
}], selected: [{
type: Input
}], disabledDates: [{
type: Input
}], specialDates: [{
type: Input
}], hideOutsideDays: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], isLastInRange: [{
type: Input,
args: [{ transform: booleanAttribute }]
}, {
type: HostBinding,
args: ['class.igx-days-view__date--last']
}], isFirstInRange: [{
type: Input,
args: [{ transform: booleanAttribute }]
}, {
type: HostBinding,
args: ['class.igx-days-view__date--first']
}], isWithinRange: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], isWithinPreviewRange: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], hideLeadingDays: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], hideTrailingDays: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], dateSelection: [{
type: Output
}], mouseEnter: [{
type: Output
}], mouseLeave: [{
type: Output
}], mouseDown: [{
type: Output
}], isActive: [{
type: Input,
args: [{ transform: booleanAttribute }]
}, {
type: HostBinding,
args: ['class.igx-days-view__date--active']
}], isSelectedCSS: [{
type: HostBinding,
args: ['class.igx-days-view__date--selected']
}], isInactive: [{
type: HostBinding,
args: ['class.igx-days-view__date--inactive']
}], isHidden: [{
type: HostBinding,
args: ['class.igx-days-view__date--hidden']
}], isToday: [{
type: HostBinding,
args: ['class.igx-days-view__date--current']
}], isWeekend: [{
type: HostBinding,
args: ['class.igx-days-view__date--weekend']
}], isWithinRangeCSS: [{
type: HostBinding,
args: ['class.igx-days-view__date--range']
}], isWithinPreviewRangeCSS: [{
type: HostBinding,
args: ['class.igx-days-view__date--range-preview']
}], isSpecial: [{
type: HostBinding,
args: ['class.igx-days-view__date--special']
}], isDisabledCSS: [{
type: HostBinding,
args: ['class.igx-days-view__date--disabled']
}], isSingleSelection: [{
type: HostBinding,
args: ['class.igx-days-view__date--single']
}] } });
class KeyboardNavigationService {
constructor() {
this.eventManager = inject(EventManager);
this.ngZone = inject(NgZone);
this.keyHandlers = new Map();
this.eventUnsubscribeFn = null;
this.platform = inject(PlatformUtil);
}
attachKeyboardHandlers(elementRef, context) {
if (!this.platform.isBrowser) {
return this;
}
this.detachKeyboardHandlers(); // Clean up any existing listeners
this.ngZone.runOutsideAngular(() => {
this.eventUnsubscribeFn = this.eventManager.addEventListener(elementRef.nativeElement, 'keydown', (event) => {
const handler = this.keyHandlers.get(event.key);
if (handler) {
this.ngZone.run(handler.bind(context, event));
}
});
});
return this;
}
detachKeyboardHandlers() {
if (this.eventUnsubscribeFn) {
this.eventUnsubscribeFn();
this.eventUnsubscribeFn = null;
}
this.keyHandlers.clear();
}
set(key, handler) {
this.keyHandlers.set(key, handler);
return this;
}
unset(key) {
this.keyHandlers.delete(key);
return this;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: KeyboardNavigationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: KeyboardNavigationService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: KeyboardNavigationService, decorators: [{
type: Injectable
}] });
/** @hidden @internal */
class IgxCalendarBaseDirective {
/**
* An accessor that sets the resource strings.
* By default it uses EN resources.
*/
set resourceStrings(value) {
this._resourceStrings = Object.assign({}, this._resourceStrings, value);
}
/**
* An accessor that returns the resource strings.
*/
g