UNPKG

primeng

Version:

PrimeNG is an open source UI library for Angular featuring a rich set of 80+ components, a theme designer, various theme alternatives such as Material, Bootstrap, Tailwind, premium templates and professional support. In addition, it integrates with PrimeB

1,561 lines (1,500 loc) 198 kB
import { trigger, state, transition, style, animate } from '@angular/animations'; import * as i2 from '@angular/common'; import { CommonModule } from '@angular/common'; import * as i0 from '@angular/core'; import { Injectable, forwardRef, EventEmitter, inject, numberAttribute, booleanAttribute, ContentChildren, ViewChild, ContentChild, Output, Input, ViewEncapsulation, ChangeDetectionStrategy, Component, NgModule } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { uuid, getOuterWidth, isDate, findSingle, getFocusableElements, hasClass, getIndex, find, isNotEmpty, addStyle, appendChild, absolutePosition, relativePosition, addClass, blockBodyScroll, unblockBodyScroll, setAttribute, isTouchDevice } from '@primeuix/utils'; import * as i1 from 'primeng/api'; import { TranslationKeys, SharedModule, PrimeTemplate } from 'primeng/api'; import { AutoFocus } from 'primeng/autofocus'; import { BaseComponent } from 'primeng/basecomponent'; import { Button } from 'primeng/button'; import { ConnectedOverlayScrollHandler } from 'primeng/dom'; import { ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, ChevronDownIcon, TimesIcon, CalendarIcon } from 'primeng/icons'; import { InputText } from 'primeng/inputtext'; import { Ripple } from 'primeng/ripple'; import { ZIndexUtils } from 'primeng/utils'; import { BaseStyle } from 'primeng/base'; const theme = ({ dt }) => ` .p-datepicker { position: relative; display: inline-flex; max-width: 100%; } .p-datepicker-input { flex: 1 1 auto; width: 1%; } .p-datepicker:has(.p-datepicker-dropdown) .p-datepicker-input { border-start-end-radius: 0; border-end-end-radius: 0; } .p-datepicker-dropdown { cursor: pointer; display: inline-flex; cursor: pointer; user-select: none; align-items: center; justify-content: center; overflow: hidden; position: relative; width: ${dt('datepicker.dropdown.width')}; border-start-end-radius: ${dt('datepicker.dropdown.border.radius')}; border-end-end-radius: ${dt('datepicker.dropdown.border.radius')}; background: ${dt('datepicker.dropdown.background')}; border: 1px solid ${dt('datepicker.dropdown.border.color')}; border-left: 0 none; color: ${dt('datepicker.dropdown.color')}; transition: background ${dt('datepicker.transition.duration')}, color ${dt('datepicker.transition.duration')}, border-color ${dt('datepicker.transition.duration')}, outline-color ${dt('datepicker.transition.duration')}; outline-color: transparent; } .p-datepicker-dropdown:not(:disabled):hover { background: ${dt('datepicker.dropdown.hover.background')}; border-color: ${dt('datepicker.dropdown.hover.border.color')}; color: ${dt('datepicker.dropdown.hover.color')}; } .p-datepicker-dropdown:not(:disabled):active { background: ${dt('datepicker.dropdown.active.background')}; border-color: ${dt('datepicker.dropdown.active.border.color')}; color: ${dt('datepicker.dropdown.active.color')}; } .p-datepicker-dropdown:focus-visible { box-shadow: ${dt('datepicker.dropdown.focus.ring.shadow')}; outline: ${dt('datepicker.dropdown.focus.ring.width')} ${dt('datepicker.dropdown.focus.ring.style')} ${dt('datepicker.dropdown.focus.ring.color')}; outline-offset: ${dt('datepicker.dropdown.focus.ring.offset')}; } .p-datepicker:has(.p-datepicker-input-icon-container) { position: relative; } .p-datepicker:has(.p-datepicker-input-icon-container) .p-datepicker-input { padding-right: calc((${dt('form.field.padding.x')} * 2) + ${dt('icon.size')}); } .p-datepicker-input-icon-container { cursor: pointer; position: absolute; top: 50%; right: ${dt('form.field.padding.x')}; margin-top: calc(-1 * (${dt('icon.size')} / 2)); color: ${dt('datepicker.input.icon.color')}; } .p-datepicker-fluid { display: flex; } .p-datepicker-fluid .p-datepicker-input { width: 1%; } .p-datepicker .p-datepicker-panel { min-width: 100%; } .p-datepicker-panel { position: absolute; width: auto; padding: ${dt('datepicker.panel.padding')}; background: ${dt('datepicker.panel.background')}; color: ${dt('datepicker.panel.color')}; border: 1px solid ${dt('datepicker.panel.border.color')}; border-radius: ${dt('datepicker.panel.border.radius')}; box-shadow: ${dt('datepicker.panel.shadow')}; } .p-datepicker-panel-inline { display: inline-block; overflow-x: auto; box-shadow: none; } .p-datepicker-header { display: flex; align-items: center; justify-content: space-between; padding: ${dt('datepicker.header.padding')}; font-weight: ${dt('datepicker.header.font.weight')}; background: ${dt('datepicker.header.background')}; color: ${dt('datepicker.header.color')}; border-bottom: 1px solid ${dt('datepicker.header.border.color')}; } .p-datepicker-title { display: flex; align-items: center; justify-content: space-between; gap: ${dt('datepicker.title.gap')}; font-weight: ${dt('datepicker.title.font.weight')}; } .p-datepicker-select-year, .p-datepicker-select-month { border: none; background: transparent; margin: 0; cursor: pointer; font-weight: inherit; transition: background ${dt('datepicker.transition.duration')}, color ${dt('datepicker.transition.duration')}, border-color ${dt('datepicker.transition.duration')}, outline-color ${dt('datepicker.transition.duration')}, box-shadow ${dt('datepicker.transition.duration')}; } .p-datepicker-select-month { padding: ${dt('datepicker.select.month.padding')}; color: ${dt('datepicker.select.month.color')}; border-radius: ${dt('datepicker.select.month.border.radius')}; } .p-datepicker-select-year { padding: ${dt('datepicker.select.year.padding')}; color: ${dt('datepicker.select.year.color')}; border-radius: ${dt('datepicker.select.year.border.radius')}; } .p-datepicker-select-month:enabled:hover { background: ${dt('datepicker.select.month.hover.background')}; color: ${dt('datepicker.select.month.hover.color')}; } .p-datepicker-select-year:enabled:hover { background: ${dt('datepicker.select.year.hover.background')}; color: ${dt('datepicker.select.year.hover.color')}; } .p-datepicker-calendar-container { display: flex; } .p-datepicker-calendar-container .p-datepicker-calendar { flex: 1 1 auto; border-left: 1px solid ${dt('datepicker.group.border.color')}; padding-right: ${dt('datepicker.group.gap')}; padding-left: ${dt('datepicker.group.gap')}; } .p-datepicker-calendar-container .p-datepicker-calendar:first-child { padding-left: 0; border-left: 0 none; } .p-datepicker-calendar-container .p-datepicker-calendar:last-child { padding-right: 0; } .p-datepicker-day-view { width: 100%; border-collapse: collapse; font-size: 1rem; margin: ${dt('datepicker.day.view.margin')}; } .p-datepicker-weekday-cell { padding: ${dt('datepicker.week.day.padding')}; } .p-datepicker-weekday { font-weight: ${dt('datepicker.week.day.font.weight')}; color: ${dt('datepicker.week.day.color')}; } .p-datepicker-day-cell { padding: ${dt('datepicker.date.padding')}; } .p-datepicker-day { display: flex; justify-content: center; align-items: center; cursor: pointer; margin: 0 auto; overflow: hidden; position: relative; width: ${dt('datepicker.date.width')}; height: ${dt('datepicker.date.height')}; border-radius: ${dt('datepicker.date.border.radius')}; transition: background ${dt('datepicker.transition.duration')}, color ${dt('datepicker.transition.duration')}, border-color ${dt('datepicker.transition.duration')}, box-shadow ${dt('datepicker.transition.duration')}, outline-color ${dt('datepicker.transition.duration')}; border: 1px solid transparent; outline-color: transparent; color: ${dt('datepicker.date.color')}; } .p-datepicker-day:not(.p-datepicker-day-selected):not(.p-disabled):hover { background: ${dt('datepicker.date.hover.background')}; color: ${dt('datepicker.date.hover.color')}; } .p-datepicker-day:focus-visible { box-shadow: ${dt('datepicker.date.focus.ring.shadow')}; outline: ${dt('datepicker.date.focus.ring.width')} ${dt('datepicker.date.focus.ring.style')} ${dt('datepicker.date.focus.ring.color')}; outline-offset: ${dt('datepicker.date.focus.ring.offset')}; } .p-datepicker-day-selected { background: ${dt('datepicker.date.selected.background')}; color: ${dt('datepicker.date.selected.color')}; } .p-datepicker-day-selected-range { background: ${dt('datepicker.date.range.selected.background')}; color: ${dt('datepicker.date.range.selected.color')}; } .p-datepicker-today > .p-datepicker-day { background: ${dt('datepicker.today.background')}; color: ${dt('datepicker.today.color')}; } .p-datepicker-today > .p-datepicker-day-selected { background: ${dt('datepicker.date.selected.background')}; color: ${dt('datepicker.date.selected.color')}; } .p-datepicker-today > .p-datepicker-day-selected-range { background: ${dt('datepicker.date.range.selected.background')}; color: ${dt('datepicker.date.range.selected.color')}; } .p-datepicker-weeknumber { text-align: center } .p-datepicker-month-view { margin: ${dt('datepicker.month.view.margin')}; } .p-datepicker-month { width: 33.3%; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; overflow: hidden; position: relative; padding: ${dt('datepicker.month.padding')}; transition: background ${dt('datepicker.transition.duration')}, color ${dt('datepicker.transition.duration')}, border-color ${dt('datepicker.transition.duration')}, box-shadow ${dt('datepicker.transition.duration')}, outline-color ${dt('datepicker.transition.duration')}; border-radius: ${dt('datepicker.month.border.radius')}; outline-color: transparent; color: ${dt('datepicker.date.color')}; } .p-datepicker-month:not(.p-disabled):not(.p-datepicker-month-selected):hover { color: ${dt('datepicker.date.hover.color')}; background: ${dt('datepicker.date.hover.background')}; } .p-datepicker-month-selected { color: ${dt('datepicker.date.selected.color')}; background: ${dt('datepicker.date.selected.background')}; } .p-datepicker-month:not(.p-disabled):focus-visible { box-shadow: ${dt('datepicker.date.focus.ring.shadow')}; outline: ${dt('datepicker.date.focus.ring.width')} ${dt('datepicker.date.focus.ring.style')} ${dt('datepicker.date.focus.ring.color')}; outline-offset: ${dt('datepicker.date.focus.ring.offset')}; } .p-datepicker-year-view { margin: ${dt('datepicker.year.view.margin')}; } .p-datepicker-year { width: 50%; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; overflow: hidden; position: relative; padding: ${dt('datepicker.year.padding')}; transition: background ${dt('datepicker.transition.duration')}, color ${dt('datepicker.transition.duration')}, border-color ${dt('datepicker.transition.duration')}, box-shadow ${dt('datepicker.transition.duration')}, outline-color ${dt('datepicker.transition.duration')}; border-radius: ${dt('datepicker.year.border.radius')}; outline-color: transparent; color: ${dt('datepicker.date.color')}; } .p-datepicker-year:not(.p-disabled):not(.p-datepicker-year-selected):hover { color: ${dt('datepicker.date.hover.color')}; background: ${dt('datepicker.date.hover.background')}; } .p-datepicker-year-selected { color: ${dt('datepicker.date.selected.color')}; background: ${dt('datepicker.date.selected.background')}; } .p-datepicker-year:not(.p-disabled):focus-visible { box-shadow: ${dt('datepicker.date.focus.ring.shadow')}; outline: ${dt('datepicker.date.focus.ring.width')} ${dt('datepicker.date.focus.ring.style')} ${dt('datepicker.date.focus.ring.color')}; outline-offset: ${dt('datepicker.date.focus.ring.offset')}; } .p-datepicker-buttonbar { display: flex; justify-content: space-between; align-items: center; padding: ${dt('datepicker.buttonbar.padding')}; border-top: 1px solid ${dt('datepicker.buttonbar.border.color')}; } .p-datepicker-buttonbar .p-button { width: auto; } .p-datepicker-time-picker { display: flex; justify-content: center; align-items: center; border-top: 1px solid ${dt('datepicker.time.picker.border.color')}; padding: 0; gap: ${dt('datepicker.time.picker.gap')}; } .p-datepicker-calendar-container + .p-datepicker-time-picker { padding: ${dt('datepicker.time.picker.padding')}; } .p-datepicker-time-picker > div { display: flex; align-items: center; flex-direction: column; gap: ${dt('datepicker.time.picker.button.gap')}; } .p-datepicker-time-picker span { font-size: 1rem; } .p-datepicker-timeonly .p-datepicker-time-picker { border-top: 0 none; } .p-datepicker-calendar:not(:first-child):not(:last-child) .p-datepicker-header { justify-content: center; } /* For PrimeNG */ p-calendar.ng-invalid.ng-dirty .p-datepicker.p-inputwrapper .p-inputtext{ border-color: ${dt('inputtext.invalid.border.color')}; } p-datePicker.ng-invalid.ng-dirty .p-datepicker.p-inputwrapper .p-inputtext, p-date-picker.ng-invalid.ng-dirty .p-datepicker.p-inputwrapper .p-inputtext, p-datepicker.ng-invalid.ng-dirty .p-datepicker.p-inputwrapper .p-inputtext { border-color: ${dt('inputtext.invalid.border.color')}; } `; const inlineStyles = { root: ({ props }) => ({ position: props.appendTo === 'self' ? 'relative' : undefined }) }; const classes = { root: ({ instance }) => ({ 'p-datepicker p-component p-inputwrapper': true, 'p-datepicker-fluid': instance.hasFluid, 'p-inputwrapper-filled': instance.filled, 'p-inputwrapper-focus': instance.focus, 'p-focus': instance.focus || instance.overlayVisible }), pcInput: 'p-datepicker-input', dropdown: 'p-datepicker-dropdown', inputIconContainer: 'p-datepicker-input-icon-container', inputIcon: 'p-datepicker-input-icon', panel: ({ instance }) => ({ 'p-datepicker-panel p-component': true, 'p-datepicker-panel-inline': instance.inline, 'p-disabled': instance.disabled, 'p-datepicker-timeonly': instance.timeOnly }), calendarContainer: 'p-datepicker-calendar-container', calendar: 'p-datepicker-calendar', header: 'p-datepicker-header', pcPrevButton: 'p-datepicker-prev-button', title: 'p-datepicker-title', selectMonth: 'p-datepicker-select-month', selectYear: 'p-datepicker-select-year', decade: 'p-datepicker-decade', pcNextButton: 'p-datepicker-next-button', dayView: 'p-datepicker-day-view', weekHeader: 'p-datepicker-weekheader p-disabled', weekNumber: 'p-datepicker-weeknumber', weekLabelContainer: 'p-datepicker-weeklabel-container p-disabled', weekDayCell: 'p-datepicker-weekday-cell', weekDay: 'p-datepicker-weekday', dayCell: ({ date }) => [ 'p-datepicker-day-cell', { 'p-datepicker-other-month': date.otherMonth, 'p-datepicker-today': date.today } ], day: ({ instance, date }) => { let selectedDayClass = ''; if (instance.isRangeSelection() && instance.isSelected(date) && date.selectable) { selectedDayClass = date.day === instance.value[0].getDate() || date.day === instance.value[1].getDate() ? 'p-datepicker-day-selected' : 'p-datepicker-day-selected-range'; } return { 'p-datepicker-day': true, 'p-datepicker-day-selected': !instance.isRangeSelection() && instance.isSelected(date) && date.selectable, 'p-disabled': instance.disabled || !date.selectable, [selectedDayClass]: true }; }, monthView: 'p-datepicker-month-view', month: ({ instance, props, month, index }) => [ 'p-datepicker-month', { 'p-datepicker-month-selected': instance.isMonthSelected(index), 'p-disabled': props.disabled || !month.selectable } ], yearView: 'p-datepicker-year-view', year: ({ instance, props, year }) => [ 'p-datepicker-year', { 'p-datepicker-year-selected': instance.isYearSelected(year.value), 'p-disabled': props.disabled || !year.selectable } ], timePicker: 'p-datepicker-time-picker', hourPicker: 'p-datepicker-hour-picker', pcIncrementButton: 'p-datepicker-increment-button', pcDecrementButton: 'p-datepicker-decrement-button', separator: 'p-datepicker-separator', minutePicker: 'p-datepicker-minute-picker', secondPicker: 'p-datepicker-second-picker', ampmPicker: 'p-datepicker-ampm-picker', buttonbar: 'p-datepicker-buttonbar', pcTodayButton: 'p-datepicker-today-button', pcClearButton: 'p-datepicker-clear-button' }; class CalendarStyle extends BaseStyle { name = 'datepicker'; theme = theme; classes = classes; inlineStyles = inlineStyles; static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: CalendarStyle, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: CalendarStyle }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: CalendarStyle, decorators: [{ type: Injectable }] }); const CALENDAR_VALUE_ACCESSOR = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => Calendar), multi: true }; /** * Calendar also known as DatePicker, is a form component to work with dates. * @group Components */ class Calendar extends BaseComponent { zone; overlayService; iconDisplay = 'button'; /** * Inline style of the component. * @group Props */ style; /** * Style class of the component. * @group Props */ styleClass; /** * Inline style of the input field. * @group Props */ inputStyle; /** * Identifier of the focus input to match a label defined for the component. * @group Props */ inputId; /** * Name of the input element. * @group Props */ name; /** * Style class of the input field. * @group Props */ inputStyleClass; /** * Placeholder text for the input. * @group Props */ placeholder; /** * Establishes relationships between the component and label(s) where its value should be one or more element IDs. * @group Props */ ariaLabelledBy; /** * Defines a string that labels the input for accessibility. * @group Props */ ariaLabel; /** * Defines a string that labels the icon button for accessibility. * @group Props */ iconAriaLabel; /** * When specified, disables the component. * @group Props */ disabled; /** * Format of the date which can also be defined at locale settings. * @group Props */ dateFormat; /** * Separator for multiple selection mode. * @group Props */ multipleSeparator = ','; /** * Separator for joining start and end dates on range selection mode. * @group Props */ rangeSeparator = '-'; /** * When enabled, displays the calendar as inline. Default is false for popup mode. * @group Props */ inline = false; /** * Whether to display dates in other months (non-selectable) at the start or end of the current month. To make these days selectable use the selectOtherMonths option. * @group Props */ showOtherMonths = true; /** * Whether days in other months shown before or after the current month are selectable. This only applies if the showOtherMonths option is set to true. * @group Props */ selectOtherMonths; /** * When enabled, displays a button with icon next to input. * @group Props */ showIcon; /** * Whether the component should span the full width of its parent. * @group Props */ fluid; /** * Icon of the calendar button. * @group Props */ icon; /** * Target element to attach the overlay, valid values are "body" or a local ng-template variable of another element (note: use binding with brackets for template variables, e.g. [appendTo]="mydiv" for a div element having#mydiv as variable name). * @group Props */ appendTo; /** * When specified, prevents entering the date manually with keyboard. * @group Props */ readonlyInput; /** * The cutoff year for determining the century for a date. * @group Props */ shortYearCutoff = '+10'; /** * Whether the month should be rendered as a dropdown instead of text. * @group Props * @deprecated Navigator is always on. */ monthNavigator; /** * Whether the year should be rendered as a dropdown instead of text. * @group Props * @deprecated Navigator is always on. */ yearNavigator; /** * Specifies 12 or 24 hour format. * @group Props */ hourFormat = '24'; /** * Whether to display timepicker only. * @group Props */ timeOnly; /** * Hours to change per step. * @group Props */ stepHour = 1; /** * Minutes to change per step. * @group Props */ stepMinute = 1; /** * Seconds to change per step. * @group Props */ stepSecond = 1; /** * Whether to show the seconds in time picker. * @group Props */ showSeconds = false; /** * When present, it specifies that an input field must be filled out before submitting the form. * @group Props */ required; /** * When disabled, datepicker will not be visible with input focus. * @group Props */ showOnFocus = true; /** * When enabled, calendar will show week numbers. * @group Props */ showWeek = false; /** * When enabled, calendar will start week numbers from first day of the year. * @group Props */ startWeekFromFirstDayOfYear = false; /** * When enabled, a clear icon is displayed to clear the value. * @group Props */ showClear = false; /** * Type of the value to write back to ngModel, default is date and alternative is string. * @group Props */ dataType = 'date'; /** * Defines the quantity of the selection, valid values are "single", "multiple" and "range". * @group Props */ selectionMode = 'single'; /** * Maximum number of selectable dates in multiple mode. * @group Props */ maxDateCount; /** * Whether to display today and clear buttons at the footer * @group Props */ showButtonBar; /** * Style class of the today button. * @group Props */ todayButtonStyleClass; /** * Style class of the clear button. * @group Props */ clearButtonStyleClass; /** * When present, it specifies that the component should automatically get focus on load. * @group Props */ autofocus; /** * Whether to automatically manage layering. * @group Props */ autoZIndex = true; /** * Base zIndex value to use in layering. * @group Props */ baseZIndex = 0; /** * Style class of the datetimepicker container element. * @group Props */ panelStyleClass; /** * Inline style of the datetimepicker container element. * @group Props */ panelStyle; /** * Keep invalid value when input blur. * @group Props */ keepInvalid = false; /** * Whether to hide the overlay on date selection. * @group Props */ hideOnDateTimeSelect = true; /** * When enabled, calendar overlay is displayed as optimized for touch devices. * @group Props */ touchUI; /** * Separator of time selector. * @group Props */ timeSeparator = ':'; /** * When enabled, can only focus on elements inside the calendar. * @group Props */ focusTrap = true; /** * Transition options of the show animation. * @group Props */ showTransitionOptions = '.12s cubic-bezier(0, 0, 0.2, 1)'; /** * Transition options of the hide animation. * @group Props */ hideTransitionOptions = '.1s linear'; /** * Index of the element in tabbing order. * @group Props */ tabindex; /** * Specifies the input variant of the component. * @group Props */ variant; /** * The minimum selectable date. * @group Props */ get minDate() { return this._minDate; } set minDate(date) { this._minDate = date; if (this.currentMonth != undefined && this.currentMonth != null && this.currentYear) { this.createMonths(this.currentMonth, this.currentYear); } } /** * The maximum selectable date. * @group Props */ get maxDate() { return this._maxDate; } set maxDate(date) { this._maxDate = date; if (this.currentMonth != undefined && this.currentMonth != null && this.currentYear) { this.createMonths(this.currentMonth, this.currentYear); } } /** * Array with dates that should be disabled (not selectable). * @group Props */ get disabledDates() { return this._disabledDates; } set disabledDates(disabledDates) { this._disabledDates = disabledDates; if (this.currentMonth != undefined && this.currentMonth != null && this.currentYear) { this.createMonths(this.currentMonth, this.currentYear); } } /** * Array with weekday numbers that should be disabled (not selectable). * @group Props */ get disabledDays() { return this._disabledDays; } set disabledDays(disabledDays) { this._disabledDays = disabledDays; if (this.currentMonth != undefined && this.currentMonth != null && this.currentYear) { this.createMonths(this.currentMonth, this.currentYear); } } /** * The range of years displayed in the year drop-down in (nnnn:nnnn) format such as (2000:2020). * @group Props * @deprecated Years are based on decades by default. */ get yearRange() { return this._yearRange; } set yearRange(yearRange) { this._yearRange = yearRange; if (yearRange) { const years = yearRange.split(':'); const yearStart = parseInt(years[0]); const yearEnd = parseInt(years[1]); this.populateYearOptions(yearStart, yearEnd); } } /** * Whether to display timepicker. * @group Props */ get showTime() { return this._showTime; } set showTime(showTime) { this._showTime = showTime; if (this.currentHour === undefined) { this.initTime(this.value || new Date()); } this.updateInputfield(); } /** * An array of options for responsive design. * @group Props */ get responsiveOptions() { return this._responsiveOptions; } set responsiveOptions(responsiveOptions) { this._responsiveOptions = responsiveOptions; this.destroyResponsiveStyleElement(); this.createResponsiveStyle(); } /** * Number of months to display. * @group Props */ get numberOfMonths() { return this._numberOfMonths; } set numberOfMonths(numberOfMonths) { this._numberOfMonths = numberOfMonths; this.destroyResponsiveStyleElement(); this.createResponsiveStyle(); } /** * Defines the first of the week for various date calculations. * @group Props */ get firstDayOfWeek() { return this._firstDayOfWeek; } set firstDayOfWeek(firstDayOfWeek) { this._firstDayOfWeek = firstDayOfWeek; this.createWeekDays(); } /** * Option to set calendar locale. * @group Props * @deprecated Locale property has no effect, use new i18n API instead. */ set locale(newLocale) { console.log('Locale property has no effect, use new i18n API instead.'); } /** * Type of view to display, valid values are "date" for datepicker and "month" for month picker. * @group Props */ get view() { return this._view; } set view(view) { this._view = view; this.currentView = this._view; } /** * Set the date to highlight on first opening if the field is blank. * @group Props */ get defaultDate() { return this._defaultDate; } set defaultDate(defaultDate) { this._defaultDate = defaultDate; if (this.initialized) { const date = defaultDate || new Date(); this.currentMonth = date.getMonth(); this.currentYear = date.getFullYear(); this.initTime(date); this.createMonths(this.currentMonth, this.currentYear); } } /** * Callback to invoke on focus of input field. * @param {Event} event - browser event. * @group Emits */ onFocus = new EventEmitter(); /** * Callback to invoke on blur of input field. * @param {Event} event - browser event. * @group Emits */ onBlur = new EventEmitter(); /** * Callback to invoke when date panel closed. * @param {Event} event - Mouse event * @group Emits */ onClose = new EventEmitter(); /** * Callback to invoke on date select. * @param {Date} date - date value. * @group Emits */ onSelect = new EventEmitter(); /** * Callback to invoke when input field cleared. * @group Emits */ onClear = new EventEmitter(); /** * Callback to invoke when input field is being typed. * @param {Event} event - browser event * @group Emits */ onInput = new EventEmitter(); /** * Callback to invoke when today button is clicked. * @param {Date} date - today as a date instance. * @group Emits */ onTodayClick = new EventEmitter(); /** * Callback to invoke when clear button is clicked. * @param {Event} event - browser event. * @group Emits */ onClearClick = new EventEmitter(); /** * Callback to invoke when a month is changed using the navigators. * @param {CalendarMonthChangeEvent} event - custom month change event. * @group Emits */ onMonthChange = new EventEmitter(); /** * Callback to invoke when a year is changed using the navigators. * @param {CalendarYearChangeEvent} event - custom year change event. * @group Emits */ onYearChange = new EventEmitter(); /** * Callback to invoke when clicked outside of the date panel. * @group Emits */ onClickOutside = new EventEmitter(); /** * Callback to invoke when datepicker panel is shown. * @group Emits */ onShow = new EventEmitter(); /** * Custom template for date cells. * @group Templates */ dateTemplate; /** * Custom template for header section. * @group Templates */ headerTemplate; /** * Custom template for footer section. * @group Templates */ footerTemplate; /** * Custom template for disabled date cells. * @group Templates */ disabledDateTemplate; /** * Custom template for decade view. * @group Templates */ decadeTemplate; /** * Custom template for previous month icon. * @group Templates */ previousIconTemplate; /** * Custom template for next month icon. * @group Templates */ nextIconTemplate; /** * Custom template for trigger icon. * @group Templates */ triggerIconTemplate; /** * Custom template for clear icon. * @group Templates */ clearIconTemplate; /** * Custom template for decrement icon. * @group Templates */ decrementIconTemplate; /** * Custom template for increment icon. * @group Templates */ incrementIconTemplate; /** * Custom template for input icon. * @group Templates */ inputIconTemplate; containerViewChild; inputfieldViewChild; set content(content) { this.contentViewChild = content; if (this.contentViewChild) { if (this.isMonthNavigate) { Promise.resolve(null).then(() => this.updateFocus()); this.isMonthNavigate = false; } else { if (!this.focus && !this.inline) { this.initFocusableCell(); } } } } _dateTemplate; _headerTemplate; _footerTemplate; _disabledDateTemplate; _decadeTemplate; _previousIconTemplate; _nextIconTemplate; _triggerIconTemplate; _clearIconTemplate; _decrementIconTemplate; _incrementIconTemplate; _inputIconTemplate; _componentStyle = inject(CalendarStyle); contentViewChild; value; dates; months; weekDays; currentMonth; currentYear; currentHour; currentMinute; currentSecond; pm; mask; maskClickListener; overlay; responsiveStyleElement; overlayVisible; onModelChange = () => { }; onModelTouched = () => { }; calendarElement; timePickerTimer; documentClickListener; animationEndListener; ticksTo1970; yearOptions; focus; isKeydown; filled; inputFieldValue = null; _minDate; _maxDate; _showTime; _yearRange; preventDocumentListener; dayClass(date) { return this._componentStyle.classes.day({ instance: this, date: date }); } _disabledDates; _disabledDays; selectElement; todayElement; focusElement; scrollHandler; documentResizeListener; navigationState = null; isMonthNavigate; initialized; translationSubscription; _locale; _responsiveOptions; currentView; attributeSelector; panelId; _numberOfMonths = 1; _firstDayOfWeek; _view = 'date'; preventFocus; _defaultDate; _focusKey = null; window; get locale() { return this._locale; } get iconButtonAriaLabel() { return this.iconAriaLabel ? this.iconAriaLabel : this.getTranslation('chooseDate'); } get prevIconAriaLabel() { return this.currentView === 'year' ? this.getTranslation('prevDecade') : this.currentView === 'month' ? this.getTranslation('prevYear') : this.getTranslation('prevMonth'); } get nextIconAriaLabel() { return this.currentView === 'year' ? this.getTranslation('nextDecade') : this.currentView === 'month' ? this.getTranslation('nextYear') : this.getTranslation('nextMonth'); } get rootClass() { return this._componentStyle.classes.root({ instance: this }); } get panelClass() { return this._componentStyle.classes.panel({ instance: this }); } get hasFluid() { const nativeElement = this.el.nativeElement; const fluidComponent = nativeElement.closest('p-fluid'); return this.fluid || !!fluidComponent; } constructor(zone, overlayService) { super(); this.zone = zone; this.overlayService = overlayService; } ngOnInit() { console.log('Calendar component is deprecated as of v18, use DatePicker component instead.'); super.ngOnInit(); this.attributeSelector = uuid('pn_id_'); this.panelId = this.attributeSelector + '_panel'; const date = this.defaultDate || new Date(); this.createResponsiveStyle(); this.currentMonth = date.getMonth(); this.currentYear = date.getFullYear(); this.yearOptions = []; this.currentView = this.view; if (this.view === 'date') { this.createWeekDays(); this.initTime(date); this.createMonths(this.currentMonth, this.currentYear); this.ticksTo1970 = ((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000; } this.translationSubscription = this.config.translationObserver.subscribe(() => { this.createWeekDays(); this.cd.markForCheck(); }); this.initialized = true; } ngAfterViewInit() { super.ngAfterViewInit(); if (this.inline) { this.contentViewChild && this.contentViewChild.nativeElement.setAttribute(this.attributeSelector, ''); if (!this.disabled && !this.inline) { this.initFocusableCell(); if (this.numberOfMonths === 1) { if (this.contentViewChild && this.contentViewChild.nativeElement) { this.contentViewChild.nativeElement.style.width = getOuterWidth(this.containerViewChild?.nativeElement) + 'px'; } } } } } templates; ngAfterContentInit() { this.templates.forEach((item) => { switch (item.getType()) { case 'date': this._dateTemplate = item.template; break; case 'decade': this._decadeTemplate = item.template; break; case 'disabledDate': this._disabledDateTemplate = item.template; break; case 'header': this._headerTemplate = item.template; break; case 'inputicon': this._inputIconTemplate = item.template; break; case 'previousicon': this._previousIconTemplate = item.template; break; case 'nexticon': this._nextIconTemplate = item.template; break; case 'triggericon': this._triggerIconTemplate = item.template; break; case 'clearicon': this._clearIconTemplate = item.template; break; case 'decrementicon': this._decrementIconTemplate = item.template; break; case 'incrementicon': this._incrementIconTemplate = item.template; break; case 'footer': this._footerTemplate = item.template; break; default: this._dateTemplate = item.template; break; } }); } getTranslation(option) { return this.config.getTranslation(option); } populateYearOptions(start, end) { this.yearOptions = []; for (let i = start; i <= end; i++) { this.yearOptions.push(i); } } createWeekDays() { this.weekDays = []; let dayIndex = this.getFirstDateOfWeek(); let dayLabels = this.getTranslation(TranslationKeys.DAY_NAMES_MIN); for (let i = 0; i < 7; i++) { this.weekDays.push(dayLabels[dayIndex]); dayIndex = dayIndex == 6 ? 0 : ++dayIndex; } } monthPickerValues() { let monthPickerValues = []; for (let i = 0; i <= 11; i++) { monthPickerValues.push(this.config.getTranslation('monthNamesShort')[i]); } return monthPickerValues; } yearPickerValues() { let yearPickerValues = []; let base = this.currentYear - (this.currentYear % 10); for (let i = 0; i < 10; i++) { yearPickerValues.push(base + i); } return yearPickerValues; } createMonths(month, year) { this.months = this.months = []; for (let i = 0; i < this.numberOfMonths; i++) { let m = month + i; let y = year; if (m > 11) { m = (m % 11) - 1; y = year + 1; } this.months.push(this.createMonth(m, y)); } } getWeekNumber(date) { let checkDate = new Date(date.getTime()); if (this.startWeekFromFirstDayOfYear) { let firstDayOfWeek = +this.getFirstDateOfWeek(); checkDate.setDate(checkDate.getDate() + 6 + firstDayOfWeek - checkDate.getDay()); } else { checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); } let time = checkDate.getTime(); checkDate.setMonth(0); checkDate.setDate(1); return Math.floor(Math.round((time - checkDate.getTime()) / 86400000) / 7) + 1; } createMonth(month, year) { let dates = []; let firstDay = this.getFirstDayOfMonthIndex(month, year); let daysLength = this.getDaysCountInMonth(month, year); let prevMonthDaysLength = this.getDaysCountInPrevMonth(month, year); let dayNo = 1; let today = new Date(); let weekNumbers = []; let monthRows = Math.ceil((daysLength + firstDay) / 7); for (let i = 0; i < monthRows; i++) { let week = []; if (i == 0) { for (let j = prevMonthDaysLength - firstDay + 1; j <= prevMonthDaysLength; j++) { let prev = this.getPreviousMonthAndYear(month, year); week.push({ day: j, month: prev.month, year: prev.year, otherMonth: true, today: this.isToday(today, j, prev.month, prev.year), selectable: this.isSelectable(j, prev.month, prev.year, true) }); } let remainingDaysLength = 7 - week.length; for (let j = 0; j < remainingDaysLength; j++) { week.push({ day: dayNo, month: month, year: year, today: this.isToday(today, dayNo, month, year), selectable: this.isSelectable(dayNo, month, year, false) }); dayNo++; } } else { for (let j = 0; j < 7; j++) { if (dayNo > daysLength) { let next = this.getNextMonthAndYear(month, year); week.push({ day: dayNo - daysLength, month: next.month, year: next.year, otherMonth: true, today: this.isToday(today, dayNo - daysLength, next.month, next.year), selectable: this.isSelectable(dayNo - daysLength, next.month, next.year, true) }); } else { week.push({ day: dayNo, month: month, year: year, today: this.isToday(today, dayNo, month, year), selectable: this.isSelectable(dayNo, month, year, false) }); } dayNo++; } } if (this.showWeek) { weekNumbers.push(this.getWeekNumber(new Date(week[0].year, week[0].month, week[0].day))); } dates.push(week); } return { month: month, year: year, dates: dates, weekNumbers: weekNumbers }; } initTime(date) { this.pm = date.getHours() > 11; if (this.showTime) { this.currentMinute = date.getMinutes(); this.currentSecond = date.getSeconds(); this.setCurrentHourPM(date.getHours()); } else if (this.timeOnly) { this.currentMinute = 0; this.currentHour = 0; this.currentSecond = 0; } } navBackward(event) { if (this.disabled) { event.preventDefault(); return; } this.isMonthNavigate = true; if (this.currentView === 'month') { this.decrementYear(); setTimeout(() => { this.updateFocus(); }, 1); } else if (this.currentView === 'year') { this.decrementDecade(); setTimeout(() => { this.updateFocus(); }, 1); } else { if (this.currentMonth === 0) { this.currentMonth = 11; this.decrementYear(); } else { this.currentMonth--; } this.onMonthChange.emit({ month: this.currentMonth + 1, year: this.currentYear }); this.createMonths(this.currentMonth, this.currentYear); } } navForward(event) { if (this.disabled) { event.preventDefault(); return; } this.isMonthNavigate = true; if (this.currentView === 'month') { this.incrementYear(); setTimeout(() => { this.updateFocus(); }, 1); } else if (this.currentView === 'year') { this.incrementDecade(); setTimeout(() => { this.updateFocus(); }, 1); } else { if (this.currentMonth === 11) { this.currentMonth = 0; this.incrementYear(); } else { this.currentMonth++; } this.onMonthChange.emit({ month: this.currentMonth + 1, year: this.currentYear }); this.createMonths(this.currentMonth, this.currentYear); } } decrementYear() { this.currentYear--; let _yearOptions = this.yearOptions; if (this.yearNavigator && this.currentYear < _yearOptions[0]) { let difference = _yearOptions[_yearOptions.length - 1] - _yearOptions[0]; this.populateYearOptions(_yearOptions[0] - difference, _yearOptions[_yearOptions.length - 1] - difference); } } decrementDecade() { this.currentYear = this.currentYear - 10; } incrementDecade() { this.currentYear = this.currentYear + 10; } incrementYear() { this.currentYear++; let _yearOptions = this.yearOptions; if (this.yearNavigator && this.currentYear > _yearOptions[_yearOptions.length - 1]) { let difference = _yearOptions[_yearOptions.length - 1] - _yearOptions[0]; this.populateYearOptions(_yearOptions[0] + difference, _yearOptions[_yearOptions.length - 1] + difference); } } switchToMonthView(event) { this.setCurrentView('month'); event.preventDefault(); } switchToYearView(event) { this.setCurrentView('year'); event.preventDefault(); } onDateSelect(event, dateMeta) { if (this.disabled || !dateMeta.selectable) { event.preventDefault(); return; } if (this.isMultipleSelection() && this.isSelected(dateMeta)) { this.value = this.value.filter((date, i) => { return !this.isDateEquals(date, dateMeta); }); if (this.value.length === 0) { this.value = null; } this.updateModel(this.value); } else { if (this.shouldSelectDate(dateMeta)) { this.selectDate(dateMeta); } } if ((this.isSingleSelection() && this.hideOnDateTimeSelect) || (this.isRangeSelection() && this.value[1])) { setTimeout(() => { event.preventDefault(); this.hideOverlay(); if (this.mask) { this.disableModality(); } this.cd.markForCheck(); }, 150); } this.updateInputfield(); event.preventDefault(); } shouldSelectDate(dateMeta) { if (this.isMultipleSelection()) return this.maxDateCount != null ? this.maxDateCount > (this.value ? this.value.length : 0) : true; else return true; } onMonthSelect(event, index) { if (this.view === 'month') { this.onDateSelect(event, { year: this.currentYear, month: index, day: 1, selectable: true }); } else { this.currentMonth = index; this.createMonths(this.currentMonth, this.currentYear); this.setCurrentView('date'); this.onMonthChange.emit({ month: this.currentMonth + 1, year: this.currentYear }); } } onYearSelect(event, year) { if (this.view === 'year') { this.onDateSelect(event, { year: year, month: 0, day: 1, selectable: true }); } else { this.currentYear = year; this.setCurrentView('month'); this.onYearChange.emit({ month: this.currentMonth + 1, year: this.currentYear }); } } updateInputfie