ngx-material-date-fns-adapter
Version:
date-fns adapter for Angular-Material applications. (Support jalali)
364 lines (357 loc) • 13 kB
JavaScript
import * as i0 from '@angular/core';
import { inject, Injectable, NgModule } from '@angular/core';
import { DateAdapter, MAT_DATE_LOCALE, MAT_DATE_FORMATS } from '@angular/material/core';
import * as gregorian from 'date-fns';
import * as jalali from 'date-fns-jalali';
import { enUS } from 'date-fns/locale';
import { faIR } from 'date-fns-jalali/locale';
/** Creates an array and fills it with values. */
function range(length, valueFunction) {
const valuesArray = Array(length);
for (let i = 0; i < length; i++) {
valuesArray[i] = valueFunction(i);
}
return valuesArray;
}
const dateFns = {
gregorian: {
setMonth: gregorian.setMonth,
setDate: gregorian.setDate,
getMonth: gregorian.getMonth,
getYear: gregorian.getYear,
getDate: gregorian.getDate,
getDay: gregorian.getDay,
getHours: gregorian.getHours,
getMinutes: gregorian.getMinutes,
getSeconds: gregorian.getSeconds,
getDaysInMonth: gregorian.getDaysInMonth,
formatISO: gregorian.formatISO,
addYears: gregorian.addYears,
addMonths: gregorian.addMonths,
addDays: gregorian.addDays,
addSeconds: gregorian.addSeconds,
isValid: gregorian.isValid,
isDate: gregorian.isDate,
format: gregorian.format,
parseISO: gregorian.parseISO,
parse: gregorian.parse,
set: gregorian.set,
},
jalali: {
setMonth: jalali.setMonth,
setDate: jalali.setDate,
getMonth: jalali.getMonth,
getYear: jalali.getYear,
getDate: jalali.getDate,
getDay: jalali.getDay,
getHours: jalali.getHours,
getMinutes: jalali.getMinutes,
getSeconds: jalali.getSeconds,
getDaysInMonth: jalali.getDaysInMonth,
formatISO: jalali.formatISO,
addYears: jalali.addYears,
addMonths: jalali.addMonths,
addDays: jalali.addDays,
addSeconds: jalali.addSeconds,
isValid: jalali.isValid,
isDate: jalali.isDate,
format: jalali.format,
parseISO: jalali.parseISO,
parse: jalali.parse,
set: jalali.set,
},
};
// date-fns doesn't have a way to read/print month names or days of the week directly,
// so we get them by formatting a date with a format that produces the desired month/day.
const MONTH_FORMATS = {
long: 'LLLL',
short: 'LLL',
narrow: 'LLLLL',
};
const DAY_OF_WEEK_FORMATS = {
long: 'EEEE',
short: 'EEE',
narrow: 'EEEEE',
};
class DateFnsAdapter extends DateAdapter {
constructor() {
super();
/** Calendar type. */
this._calendarType = 'gregorian';
const matDateLocale = inject(MAT_DATE_LOCALE, { optional: true });
this.setLocale(matDateLocale);
}
/**
* Sets the locale used for all dates.
*
* @param locale The new locale
*/
setLocale(locale = enUS) {
if (locale.code === 'fa-IR') {
locale = faIR;
this._calendarType = 'jalali';
}
else {
this._calendarType = 'gregorian';
}
super.setLocale(locale);
}
getYear(date) {
return dateFns[this._calendarType].getYear(date);
}
getMonth(date) {
return dateFns[this._calendarType].getMonth(date);
}
getDate(date) {
return dateFns[this._calendarType].getDate(date);
}
getDayOfWeek(date) {
return dateFns[this._calendarType].getDay(date);
}
getMonthNames(style) {
const pattern = MONTH_FORMATS[style];
return range(12, (i) => this.format(dateFns[this._calendarType].setMonth(this.today(), i), pattern));
}
getDateNames() {
const dtf = typeof Intl !== 'undefined'
? new Intl.DateTimeFormat(this.locale.code, {
day: 'numeric',
})
: null;
return range(31, (i) => {
let date = this.createDate(2017, 0, i + 1);
if (dtf) {
return dtf.format(date).replace(/[\u200e\u200f]/g, '');
}
return this.format(date, 'd');
});
}
getDayOfWeekNames(style) {
const pattern = DAY_OF_WEEK_FORMATS[style];
return range(7, (i) => this.format(new Date(2017, 0, i + 1), pattern));
}
getYearName(date) {
return this.format(date, 'y');
}
getFirstDayOfWeek() {
return this.locale.options?.weekStartsOn ?? 0;
}
getNumDaysInMonth(date) {
return dateFns[this._calendarType].getDaysInMonth(date);
}
clone(date) {
return new Date(date.getTime());
}
createDate(year, month, date) {
// Check for invalid month and date (except upper bound on date which we have to check after
// creating the Date).
if (month < 0 || month > 11) {
throw Error(`Invalid month index "${month}". Month index has to be between 0 and 11.`);
}
if (date < 1) {
throw Error(`Invalid date "${date}". Date has to be greater than 0.`);
}
const result = dateFns[this._calendarType].set(new Date(), {
year,
month,
date,
hours: 0,
minutes: 0,
seconds: 0,
milliseconds: 0,
});
// Check that the date wasn't above the upper bound for the month, causing the month to overflow
if (this.getMonth(result) != month) {
throw Error(`Invalid date "${date}" for month with index "${month}".`);
}
return result;
}
today() {
return new Date();
}
parse(value, parseFormat) {
if (typeof value == 'string' && value.length > 0) {
const iso8601Date = dateFns[this._calendarType].parseISO(value);
if (this.isValid(iso8601Date)) {
return iso8601Date;
}
const formats = Array.isArray(parseFormat) ? parseFormat : [parseFormat];
if (!parseFormat.length) {
throw Error('Formats array must not be empty.');
}
for (const currentFormat of formats) {
const fromFormat = dateFns[this._calendarType].parse(value, currentFormat, new Date(), {
locale: this.locale,
});
if (this.isValid(fromFormat)) {
return fromFormat;
}
}
return this.invalid();
}
else if (typeof value === 'number') {
return new Date(value);
}
else if (value instanceof Date) {
return this.clone(value);
}
return null;
}
format(date, displayFormat) {
if (!this.isValid(date)) {
throw Error('DateFnsAdapter: Cannot format invalid date.');
}
// fix persian Month short name
if (this.locale.code == 'fa-IR' && displayFormat === 'LLL')
displayFormat = 'LLLL';
// fix persian monthYearLabel
if (this.locale.code == 'fa-IR' && displayFormat === 'LLL uuuu')
displayFormat = 'LLLL uuuu';
return dateFns[this._calendarType].format(date, displayFormat, {
locale: this.locale,
});
}
addCalendarYears(date, years) {
return dateFns[this._calendarType].addYears(date, years);
}
addCalendarMonths(date, months) {
return dateFns[this._calendarType].addMonths(date, months);
}
addCalendarDays(date, days) {
return dateFns[this._calendarType].addDays(date, days);
}
toIso8601(date) {
return dateFns[this._calendarType].formatISO(date, {
representation: 'date',
});
}
/**
* Returns the given value if given a valid Date or null. Deserializes valid ISO 8601 strings
* (https://www.ietf.org/rfc/rfc3339.txt) into valid Dates and empty string into null. Returns an
* invalid date for all other values.
*/
deserialize(value) {
if (typeof value === 'string') {
if (!value) {
return null;
}
const date = dateFns[this._calendarType].parseISO(value);
if (this.isValid(date)) {
return date;
}
}
return super.deserialize(value);
}
isDateInstance(obj) {
return dateFns[this._calendarType].isDate(obj);
}
isValid(date) {
return dateFns[this._calendarType].isValid(date);
}
invalid() {
return new Date(NaN);
}
setTime(target, hours, minutes, seconds) {
if (hours < 0 || hours > 23) {
throw Error(`Invalid hours "${hours}". Hours value must be between 0 and 23.`);
}
if (minutes < 0 || minutes > 59) {
throw Error(`Invalid minutes "${minutes}". Minutes value must be between 0 and 59.`);
}
if (seconds < 0 || seconds > 59) {
throw Error(`Invalid seconds "${seconds}". Seconds value must be between 0 and 59.`);
}
return dateFns[this._calendarType].set(this.clone(target), {
hours,
minutes,
seconds,
milliseconds: 0,
});
}
getHours(date) {
return dateFns[this._calendarType].getHours(date);
}
getMinutes(date) {
return dateFns[this._calendarType].getMinutes(date);
}
getSeconds(date) {
return dateFns[this._calendarType].getSeconds(date);
}
parseTime(value, parseFormat) {
return this.parse(value, parseFormat);
}
addSeconds(date, amount) {
return dateFns[this._calendarType].addSeconds(date, amount);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.2", ngImport: i0, type: DateFnsAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.2", ngImport: i0, type: DateFnsAdapter }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.2", ngImport: i0, type: DateFnsAdapter, decorators: [{
type: Injectable
}], ctorParameters: () => [] });
const MAT_DATE_FNS_FORMATS = {
parse: {
dateInput: 'P',
timeInput: 'p',
},
display: {
dateInput: 'P',
timeInput: 'p',
monthYearLabel: 'LLL uuuu',
dateA11yLabel: 'PP',
monthYearA11yLabel: 'LLLL uuuu',
timeOptionLabel: 'p',
},
};
class DateFnsModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.2", ngImport: i0, type: DateFnsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.2", ngImport: i0, type: DateFnsModule }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.2", ngImport: i0, type: DateFnsModule, providers: [
{
provide: DateAdapter,
useClass: DateFnsAdapter,
deps: [MAT_DATE_LOCALE],
},
] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.2", ngImport: i0, type: DateFnsModule, decorators: [{
type: NgModule,
args: [{
providers: [
{
provide: DateAdapter,
useClass: DateFnsAdapter,
deps: [MAT_DATE_LOCALE],
},
],
}]
}] });
class NgxMatDateFnsModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.2", ngImport: i0, type: NgxMatDateFnsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.2", ngImport: i0, type: NgxMatDateFnsModule }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.2", ngImport: i0, type: NgxMatDateFnsModule, providers: [provideDateFnsAdapter()] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.2", ngImport: i0, type: NgxMatDateFnsModule, decorators: [{
type: NgModule,
args: [{
providers: [provideDateFnsAdapter()],
}]
}] });
function provideDateFnsAdapter(formats = MAT_DATE_FNS_FORMATS) {
return [
{
provide: DateAdapter,
useClass: DateFnsAdapter,
deps: [MAT_DATE_LOCALE],
},
{ provide: MAT_DATE_FORMATS, useValue: formats },
];
}
/*
* Public API Surface of ngx-material-date-fns-adapter
*/
/**
* Generated bundle index. Do not edit.
*/
export { DateFnsAdapter, DateFnsModule, MAT_DATE_FNS_FORMATS, NgxMatDateFnsModule, provideDateFnsAdapter };
//# sourceMappingURL=ngx-material-date-fns-adapter.mjs.map