@updevs/components 1.0.0-alpha.48 → 1.0.0-alpha.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -13
- package/calendar/calendar.component.d.ts +58 -122
- package/calendar/models/calendar-date.model.d.ts +10 -0
- package/calendar/models/calendar-month.model.d.ts +7 -0
- package/calendar/models/calendar-selected.model.d.ts +5 -0
- package/calendar/models/calendar-year.model.d.ts +6 -0
- package/calendar/models/date-range.model.d.ts +0 -4
- package/calendar/models/enums/calendar-view.enum.d.ts +5 -0
- package/calendar/models/public-api.d.ts +5 -0
- package/calendar/upd-calendar.module.d.ts +6 -11
- package/card/public-api.d.ts +1 -0
- package/card/types/public-api.d.ts +5 -0
- package/dropdown/dropdown.component.d.ts +3 -0
- package/esm2022/calendar/calendar.component.mjs +288 -217
- package/esm2022/calendar/models/calendar-date.model.mjs +2 -0
- package/esm2022/calendar/models/calendar-month.model.mjs +2 -0
- package/esm2022/calendar/models/calendar-selected.model.mjs +2 -0
- package/esm2022/calendar/models/calendar-year.model.mjs +2 -0
- package/esm2022/calendar/models/date-range.model.mjs +1 -1
- package/esm2022/calendar/models/enums/calendar-view.enum.mjs +7 -0
- package/esm2022/calendar/models/public-api.mjs +6 -1
- package/esm2022/calendar/upd-calendar.module.mjs +2 -20
- package/esm2022/card/public-api.mjs +2 -1
- package/esm2022/card/types/public-api.mjs +6 -0
- package/esm2022/dropdown/dropdown.component.mjs +23 -7
- package/esm2022/form-controls/date-picker/date-picker.component.mjs +45 -60
- package/esm2022/form-controls/input/input.component.mjs +3 -3
- package/esm2022/popover/popover.directive.mjs +10 -26
- package/esm2022/pricing-cards/index.mjs +2 -0
- package/esm2022/pricing-cards/models/price-item-feature.model.mjs +2 -0
- package/esm2022/pricing-cards/models/price-item-features-group.model.mjs +2 -0
- package/esm2022/pricing-cards/models/price-item.model.mjs +2 -0
- package/esm2022/pricing-cards/models/public-api.mjs +4 -0
- package/esm2022/pricing-cards/pricing-cards.component.mjs +24 -0
- package/esm2022/pricing-cards/public-api.mjs +4 -0
- package/esm2022/pricing-cards/upd-pricing-cards.module.mjs +36 -0
- package/esm2022/pricing-cards/updevs-components-pricing-cards.mjs +5 -0
- package/esm2022/table/abstractions/base.column.mjs +30 -44
- package/esm2022/table/table.component.mjs +9 -12
- package/fesm2022/updevs-components-calendar.mjs +319 -1449
- package/fesm2022/updevs-components-calendar.mjs.map +1 -1
- package/fesm2022/updevs-components-dropdown.mjs +22 -6
- package/fesm2022/updevs-components-dropdown.mjs.map +1 -1
- package/fesm2022/updevs-components-form-controls-date-picker.mjs +44 -59
- package/fesm2022/updevs-components-form-controls-date-picker.mjs.map +1 -1
- package/fesm2022/updevs-components-form-controls-input.mjs +2 -2
- package/fesm2022/updevs-components-form-controls-input.mjs.map +1 -1
- package/fesm2022/updevs-components-popover.mjs +9 -25
- package/fesm2022/updevs-components-popover.mjs.map +1 -1
- package/fesm2022/updevs-components-pricing-cards.mjs +64 -0
- package/fesm2022/updevs-components-pricing-cards.mjs.map +1 -0
- package/fesm2022/updevs-components-table.mjs +38 -55
- package/fesm2022/updevs-components-table.mjs.map +1 -1
- package/form-controls/date-picker/date-picker.component.d.ts +10 -31
- package/package.json +37 -31
- package/pricing-cards/index.d.ts +1 -0
- package/pricing-cards/models/price-item-feature.model.d.ts +5 -0
- package/pricing-cards/models/price-item-features-group.model.d.ts +5 -0
- package/pricing-cards/models/price-item.model.d.ts +19 -0
- package/pricing-cards/models/public-api.d.ts +3 -0
- package/pricing-cards/pricing-cards.component.d.ts +11 -0
- package/pricing-cards/public-api.d.ts +3 -0
- package/pricing-cards/upd-pricing-cards.module.d.ts +11 -0
- package/table/abstractions/base.column.d.ts +4 -0
- package/calendar/components/calendar-body/calendar-body.component.d.ts +0 -263
- package/calendar/components/calendar-header/calendar-header.component.d.ts +0 -57
- package/calendar/components/calendar-month-view/calendar-month-view.component.d.ts +0 -151
- package/calendar/components/calendar-multi-year-view/calendar-multi-year-view.component.d.ts +0 -10
- package/calendar/components/calendar-year-view/calendar-year-view.component.d.ts +0 -9
- package/calendar/models/calendar-cell.model.d.ts +0 -16
- package/calendar/services/calendar.service.d.ts +0 -15
- package/calendar/tools/events-options.d.ts +0 -12
- package/calendar/tools/keyboard-tools.d.ts +0 -9
- package/calendar/tools/passive-listeners.d.ts +0 -16
- package/calendar/types/calendar-cell-class-function.type.d.ts +0 -3
- package/calendar/types/calendar-cell-css-classes.type.d.ts +0 -3
- package/calendar/types/modifier-key.type.d.ts +0 -1
- package/esm2022/calendar/components/calendar-body/calendar-body.component.mjs +0 -515
- package/esm2022/calendar/components/calendar-header/calendar-header.component.mjs +0 -144
- package/esm2022/calendar/components/calendar-month-view/calendar-month-view.component.mjs +0 -423
- package/esm2022/calendar/components/calendar-multi-year-view/calendar-multi-year-view.component.mjs +0 -18
- package/esm2022/calendar/components/calendar-year-view/calendar-year-view.component.mjs +0 -17
- package/esm2022/calendar/models/calendar-cell.model.mjs +0 -18
- package/esm2022/calendar/services/calendar.service.mjs +0 -40
- package/esm2022/calendar/tools/events-options.mjs +0 -14
- package/esm2022/calendar/tools/keyboard-tools.mjs +0 -14
- package/esm2022/calendar/tools/passive-listeners.mjs +0 -29
- package/esm2022/calendar/types/calendar-cell-class-function.type.mjs +0 -2
- package/esm2022/calendar/types/calendar-cell-css-classes.type.mjs +0 -2
- package/esm2022/calendar/types/modifier-key.type.mjs +0 -2
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, Injectable,
|
|
2
|
+
import { inject, Injectable, input, output, signal, computed, Component, NgModule } from '@angular/core';
|
|
3
3
|
import { DateService } from '@updevs/sdk/core';
|
|
4
|
-
import { BaseComponent } from '@updevs/sdk/layout';
|
|
5
|
-
import * as i1$2 from '@jsverse/transloco';
|
|
6
|
-
import { TranslocoService, TranslocoDirective } from '@jsverse/transloco';
|
|
7
|
-
import { startWith } from 'rxjs';
|
|
8
|
-
import * as i1 from '@angular/common';
|
|
9
4
|
import { CommonModule } from '@angular/common';
|
|
10
|
-
import * as i1$1 from '@updevs/components/button';
|
|
11
5
|
import { UpdButtonModule } from '@updevs/components/button';
|
|
12
|
-
import * as i3 from '@updevs/icons';
|
|
13
6
|
import { UpdIconsModule } from '@updevs/icons';
|
|
7
|
+
import * as i1 from '@jsverse/transloco';
|
|
8
|
+
import { TranslocoDirective } from '@jsverse/transloco';
|
|
14
9
|
|
|
15
10
|
/**
|
|
16
11
|
* A class representing a range of dates.
|
|
@@ -30,6 +25,13 @@ class DateRangeModel {
|
|
|
30
25
|
}
|
|
31
26
|
}
|
|
32
27
|
|
|
28
|
+
var CalendarViewEnum;
|
|
29
|
+
(function (CalendarViewEnum) {
|
|
30
|
+
CalendarViewEnum["Days"] = "days";
|
|
31
|
+
CalendarViewEnum["Months"] = "months";
|
|
32
|
+
CalendarViewEnum["Years"] = "years";
|
|
33
|
+
})(CalendarViewEnum || (CalendarViewEnum = {}));
|
|
34
|
+
|
|
33
35
|
/**
|
|
34
36
|
* Provides the default date range selection behavior.
|
|
35
37
|
*/
|
|
@@ -125,1484 +127,319 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImpor
|
|
|
125
127
|
type: Injectable
|
|
126
128
|
}] });
|
|
127
129
|
|
|
128
|
-
class
|
|
129
|
-
/**
|
|
130
|
-
* Checks whether the user's browser supports passive event listeners.
|
|
131
|
-
* See: https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md
|
|
132
|
-
*/
|
|
133
|
-
static supportsPassiveEventListeners() {
|
|
134
|
-
if (this.supportsPassiveEvents === undefined && typeof window !== 'undefined') {
|
|
135
|
-
try {
|
|
136
|
-
window.addEventListener('test', undefined, Object.defineProperty({}, 'passive', {
|
|
137
|
-
get: () => (this.supportsPassiveEvents = true)
|
|
138
|
-
}));
|
|
139
|
-
}
|
|
140
|
-
finally {
|
|
141
|
-
this.supportsPassiveEvents = this.supportsPassiveEvents || false;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
return this.supportsPassiveEvents;
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Normalizes an `AddEventListener` object to something that can be passed
|
|
148
|
-
* to `addEventListener` on any browser, no matter whether it supports the
|
|
149
|
-
* `options` parameter.
|
|
150
|
-
* @param options Object to be normalized.
|
|
151
|
-
*/
|
|
152
|
-
static normalizePassiveListenerOptions(options) {
|
|
153
|
-
return this.supportsPassiveEventListeners() ? options : !!options.capture;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Event options that can be used to bind an active, capturing event.
|
|
159
|
-
*/
|
|
160
|
-
const activeCapturingEventOptions = PassiveListeners.normalizePassiveListenerOptions({ passive: false, capture: true });
|
|
161
|
-
/**
|
|
162
|
-
* Event options that can be used to bind a passive, capturing event.
|
|
163
|
-
*/
|
|
164
|
-
const passiveCapturingEventOptions = PassiveListeners.normalizePassiveListenerOptions({ passive: true, capture: true });
|
|
165
|
-
/**
|
|
166
|
-
* Event options that can be used to bind a passive, non-capturing event.
|
|
167
|
-
*/
|
|
168
|
-
const passiveEventOptions = PassiveListeners.normalizePassiveListenerOptions({ passive: true });
|
|
169
|
-
|
|
170
|
-
class CalendarSignalsService {
|
|
171
|
-
constructor() {
|
|
172
|
-
this.minDateSignal = signal(undefined);
|
|
173
|
-
this.maxDateSignal = signal(undefined);
|
|
174
|
-
this.activeDateSignal = signal(new Date());
|
|
175
|
-
this.selectedDateSignal = signal(undefined);
|
|
176
|
-
this.currentViewSignal = signal('month');
|
|
177
|
-
}
|
|
178
|
-
get minDate() {
|
|
179
|
-
return this.minDateSignal.asReadonly();
|
|
180
|
-
}
|
|
181
|
-
set minDate(value) {
|
|
182
|
-
this.minDateSignal.set(value);
|
|
183
|
-
}
|
|
184
|
-
get maxDate() {
|
|
185
|
-
return this.maxDateSignal.asReadonly();
|
|
186
|
-
}
|
|
187
|
-
set maxDate(value) {
|
|
188
|
-
this.maxDateSignal.set(value);
|
|
189
|
-
}
|
|
190
|
-
get activeDate() {
|
|
191
|
-
return this.activeDateSignal.asReadonly();
|
|
192
|
-
}
|
|
193
|
-
set activeDate(value) {
|
|
194
|
-
this.activeDateSignal.set(value);
|
|
195
|
-
}
|
|
196
|
-
get selectedDate() {
|
|
197
|
-
return this.selectedDateSignal.asReadonly();
|
|
198
|
-
}
|
|
199
|
-
set selectedDate(value) {
|
|
200
|
-
this.selectedDateSignal.set(value);
|
|
201
|
-
}
|
|
202
|
-
get currentView() {
|
|
203
|
-
return this.currentViewSignal.asReadonly();
|
|
204
|
-
}
|
|
205
|
-
set currentView(value) {
|
|
206
|
-
this.currentViewSignal.set(value);
|
|
207
|
-
}
|
|
208
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: CalendarSignalsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
209
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: CalendarSignalsService }); }
|
|
210
|
-
}
|
|
211
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: CalendarSignalsService, decorators: [{
|
|
212
|
-
type: Injectable
|
|
213
|
-
}] });
|
|
214
|
-
|
|
215
|
-
let calendarBodyId = 1;
|
|
216
|
-
class CalendarBodyComponent {
|
|
217
|
-
get startDateLabelId() {
|
|
218
|
-
return `${this.id}-start-date`;
|
|
219
|
-
}
|
|
220
|
-
get endDateLabelId() {
|
|
221
|
-
return `${this.id}-end-date`;
|
|
222
|
-
}
|
|
223
|
-
get colspanClass() {
|
|
224
|
-
return `col-${this.firstRowOffset}`;
|
|
225
|
-
}
|
|
226
|
-
constructor() {
|
|
227
|
-
/**
|
|
228
|
-
* The number of columns in the table.
|
|
229
|
-
*/
|
|
230
|
-
this.numCols = 7;
|
|
231
|
-
/**
|
|
232
|
-
* The cell number of the active cell in the table.
|
|
233
|
-
*/
|
|
234
|
-
this.activeCell = 0;
|
|
235
|
-
/**
|
|
236
|
-
* Whether a range is being selected.
|
|
237
|
-
*/
|
|
238
|
-
this.isRange = false;
|
|
239
|
-
/**
|
|
240
|
-
* The aspect ratio (width / height) to use for the cells in the table. This aspect ratio will be
|
|
241
|
-
* maintained even as the table resizes.
|
|
242
|
-
*/
|
|
243
|
-
this.cellAspectRatio = 1;
|
|
244
|
-
/**
|
|
245
|
-
* Emits when a new value is selected.
|
|
246
|
-
*/
|
|
247
|
-
this.selectedValueChange = new EventEmitter();
|
|
248
|
-
/**
|
|
249
|
-
* Emits when the preview has changed as a result of a user action.
|
|
250
|
-
*/
|
|
251
|
-
this.previewChange = new EventEmitter();
|
|
252
|
-
/**
|
|
253
|
-
* Emits the date at the possible start of a drag event.
|
|
254
|
-
*/
|
|
255
|
-
this.dragStarted = new EventEmitter();
|
|
256
|
-
/**
|
|
257
|
-
* Emits the date at the conclusion of a drag, or null if mouse was not released on a date.
|
|
258
|
-
*/
|
|
259
|
-
this.dragEnded = new EventEmitter();
|
|
260
|
-
this.didDragSinceMouseDown = false;
|
|
261
|
-
this.id = `upd-calendar-body-${calendarBodyId++}`;
|
|
262
|
-
/**
|
|
263
|
-
* Used to focus the active cell after change detection has run.
|
|
264
|
-
*/
|
|
265
|
-
this.focusActiveCellAfterViewChecked = false;
|
|
266
|
-
this.injector = inject(Injector);
|
|
267
|
-
this.elementRef = inject((ElementRef));
|
|
268
|
-
this.ngZone = inject(NgZone);
|
|
269
|
-
this.calendarSignalsService = inject(CalendarSignalsService);
|
|
270
|
-
this.dateService = inject(DateService);
|
|
271
|
-
/**
|
|
272
|
-
* Tracking function for rows based on their identity. Ideally we would use some sort of
|
|
273
|
-
* key on the row, but that would require a breaking change for the `rows` input. We don't
|
|
274
|
-
* use the built-in identity tracking, because it logs warnings.
|
|
275
|
-
*/
|
|
276
|
-
this.trackRow = (row) => row;
|
|
277
|
-
/**
|
|
278
|
-
* Event handler for when the user enters an element
|
|
279
|
-
* inside the calendar body (e.g. by hovering in or focus).
|
|
280
|
-
*/
|
|
281
|
-
this.enterHandler = (event) => {
|
|
282
|
-
if (this.skipNextFocus && event.type === 'focus') {
|
|
283
|
-
this.skipNextFocus = false;
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
// We only need to hit the zone when we're selecting a range.
|
|
287
|
-
if (!!event.target && this.isRange) {
|
|
288
|
-
const cell = this.getCellFromElement(event.target);
|
|
289
|
-
if (cell) {
|
|
290
|
-
this.ngZone.run(() => this.previewChange.emit({ value: cell.isEnabled ? cell : undefined, event }));
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
};
|
|
294
|
-
this.touchmoveHandler = (event) => {
|
|
295
|
-
if (!this.isRange) {
|
|
296
|
-
return;
|
|
297
|
-
}
|
|
298
|
-
const target = this.getActualTouchTarget(event);
|
|
299
|
-
const cell = target ? this.getCellFromElement(target) : undefined;
|
|
300
|
-
if (target !== event.target) {
|
|
301
|
-
this.didDragSinceMouseDown = true;
|
|
302
|
-
}
|
|
303
|
-
// If the initial target of the touch is a date cell, prevent default so
|
|
304
|
-
// that the move is not handled as a scroll.
|
|
305
|
-
if (this.getCellElement(event.target)) {
|
|
306
|
-
event.preventDefault();
|
|
307
|
-
}
|
|
308
|
-
this.ngZone.run(() => this.previewChange.emit({ value: cell?.isEnabled ? cell : undefined, event }));
|
|
309
|
-
};
|
|
310
|
-
/**
|
|
311
|
-
* Event handler for when the user's pointer leaves an element
|
|
312
|
-
* inside the calendar body (e.g. by hovering out or blurring).
|
|
313
|
-
*/
|
|
314
|
-
this.leaveHandler = (event) => {
|
|
315
|
-
// We only need to hit the zone when we're selecting a range.
|
|
316
|
-
if (this.previewEnd !== undefined && this.isRange) {
|
|
317
|
-
if (event.type !== 'blur') {
|
|
318
|
-
this.didDragSinceMouseDown = true;
|
|
319
|
-
}
|
|
320
|
-
// Only reset the preview end value when leaving cells. This looks better, because
|
|
321
|
-
// we have a gap between the cells and the rows and we don't want to remove the
|
|
322
|
-
// range just for it to show up again when the user moves a few pixels to the side.
|
|
323
|
-
if (event.target &&
|
|
324
|
-
this.getCellFromElement(event.target) &&
|
|
325
|
-
!(event.relatedTarget &&
|
|
326
|
-
this.getCellFromElement(event.relatedTarget))) {
|
|
327
|
-
this.ngZone.run(() => this.previewChange.emit({ value: undefined, event }));
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
};
|
|
331
|
-
/**
|
|
332
|
-
* Triggered on mousedown or touchstart on a date cell.
|
|
333
|
-
* Responsible for starting a drag sequence.
|
|
334
|
-
*/
|
|
335
|
-
this.mousedownHandler = (event) => {
|
|
336
|
-
if (!this.isRange) {
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
|
-
this.didDragSinceMouseDown = false;
|
|
340
|
-
// Begin a drag if a cell within the current range was targeted.
|
|
341
|
-
const cell = event.target && this.getCellFromElement(event.target);
|
|
342
|
-
if (!cell || !this.isInRange(cell.compareValue)) {
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
|
-
this.ngZone.run(() => {
|
|
346
|
-
this.dragStarted.emit({
|
|
347
|
-
value: cell.rawValue,
|
|
348
|
-
event
|
|
349
|
-
});
|
|
350
|
-
});
|
|
351
|
-
};
|
|
352
|
-
/** Triggered on mouseup anywhere. Responsible for ending a drag sequence. */
|
|
353
|
-
this.mouseupHandler = (event) => {
|
|
354
|
-
if (!this.isRange) {
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
const cellElement = this.getCellElement(event.target);
|
|
358
|
-
if (!cellElement) {
|
|
359
|
-
// Mouseup happened outside of datepicker. Cancel drag.
|
|
360
|
-
this.ngZone.run(() => {
|
|
361
|
-
this.dragEnded.emit({ value: undefined, event });
|
|
362
|
-
});
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
if (cellElement.closest('.upd-calendar-body') !== this.elementRef.nativeElement) {
|
|
366
|
-
// Mouseup happened inside a different month instance.
|
|
367
|
-
// Allow it to handle the event.
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
this.ngZone.run(() => {
|
|
371
|
-
const cell = this.getCellFromElement(cellElement);
|
|
372
|
-
this.dragEnded.emit({ value: cell?.rawValue ?? undefined, event });
|
|
373
|
-
});
|
|
374
|
-
};
|
|
375
|
-
/** Triggered on touchend anywhere. Respsonsible for ending a drag sequence. */
|
|
376
|
-
this.touchendHandler = (event) => {
|
|
377
|
-
const target = this.getActualTouchTarget(event);
|
|
378
|
-
if (target) {
|
|
379
|
-
this.mouseupHandler({ target });
|
|
380
|
-
}
|
|
381
|
-
};
|
|
382
|
-
this.ngZone.runOutsideAngular(() => {
|
|
383
|
-
const element = this.elementRef.nativeElement;
|
|
384
|
-
// `touchmove` is active since we need to call `preventDefault`.
|
|
385
|
-
element.addEventListener('touchmove', this.touchmoveHandler, activeCapturingEventOptions);
|
|
386
|
-
element.addEventListener('mouseenter', this.enterHandler, passiveCapturingEventOptions);
|
|
387
|
-
element.addEventListener('focus', this.enterHandler, passiveCapturingEventOptions);
|
|
388
|
-
element.addEventListener('mouseleave', this.leaveHandler, passiveCapturingEventOptions);
|
|
389
|
-
element.addEventListener('blur', this.leaveHandler, passiveCapturingEventOptions);
|
|
390
|
-
element.addEventListener('mousedown', this.mousedownHandler, passiveEventOptions);
|
|
391
|
-
element.addEventListener('touchstart', this.mousedownHandler, passiveEventOptions);
|
|
392
|
-
window.addEventListener('mouseup', this.mouseupHandler);
|
|
393
|
-
window.addEventListener('touchend', this.touchendHandler);
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
ngAfterViewChecked() {
|
|
397
|
-
if (this.focusActiveCellAfterViewChecked) {
|
|
398
|
-
this.focusActiveCell();
|
|
399
|
-
this.focusActiveCellAfterViewChecked = false;
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
ngOnChanges(changes) {
|
|
403
|
-
const columnChanges = changes['numCols'];
|
|
404
|
-
const { rows, numCols } = this;
|
|
405
|
-
if (changes['rows'] || columnChanges) {
|
|
406
|
-
this.firstRowOffset = rows && rows.length && rows[0].length ? numCols - rows[0].length : 0;
|
|
407
|
-
}
|
|
408
|
-
if (changes['cellAspectRatio'] || columnChanges || !this.cellPadding) {
|
|
409
|
-
this.cellPadding = `${(50 * this.cellAspectRatio) / numCols}%`;
|
|
410
|
-
}
|
|
411
|
-
if (columnChanges || !this.cellWidth) {
|
|
412
|
-
this.cellWidth = `${100 / numCols}%`;
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
ngOnDestroy() {
|
|
416
|
-
const element = this.elementRef.nativeElement;
|
|
417
|
-
element.removeEventListener('touchmove', this.touchmoveHandler, activeCapturingEventOptions);
|
|
418
|
-
element.removeEventListener('mouseenter', this.enterHandler, passiveCapturingEventOptions);
|
|
419
|
-
element.removeEventListener('focus', this.enterHandler, passiveCapturingEventOptions);
|
|
420
|
-
element.removeEventListener('mouseleave', this.leaveHandler, passiveCapturingEventOptions);
|
|
421
|
-
element.removeEventListener('blur', this.leaveHandler, passiveCapturingEventOptions);
|
|
422
|
-
element.removeEventListener('mousedown', this.mousedownHandler, passiveEventOptions);
|
|
423
|
-
element.removeEventListener('touchstart', this.mousedownHandler, passiveEventOptions);
|
|
424
|
-
window.removeEventListener('mouseup', this.mouseupHandler);
|
|
425
|
-
window.removeEventListener('touchend', this.touchendHandler);
|
|
426
|
-
}
|
|
427
|
-
getIndex(colIndex, rowIndex) {
|
|
428
|
-
return `${colIndex}${rowIndex}`;
|
|
429
|
-
}
|
|
430
|
-
onDateEnter(index) {
|
|
431
|
-
this.hoveredDate = index;
|
|
432
|
-
}
|
|
433
|
-
onDateLeave() {
|
|
434
|
-
this.hoveredDate = undefined;
|
|
435
|
-
}
|
|
436
|
-
/**
|
|
437
|
-
* Called when a cell is clicked.
|
|
438
|
-
* @param cell
|
|
439
|
-
* @param event
|
|
440
|
-
*/
|
|
441
|
-
cellClicked(cell, event) {
|
|
442
|
-
// Ignore "clicks" that are actually canceled drags (eg the user dragged off and then went back to this cell to undo).
|
|
443
|
-
if (this.didDragSinceMouseDown) {
|
|
444
|
-
return;
|
|
445
|
-
}
|
|
446
|
-
if (cell.isEnabled) {
|
|
447
|
-
this.selectedValueChange.emit({ value: cell.value, event });
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
emitActiveDateChange(cell) {
|
|
451
|
-
if (cell.isEnabled) {
|
|
452
|
-
const month = cell.value;
|
|
453
|
-
const oldActiveDate = this.calendarSignalsService.activeDate();
|
|
454
|
-
const tempDate = this.getDateFromDayOfMonth(oldActiveDate, month);
|
|
455
|
-
if (this.dateService.compare(oldActiveDate, tempDate)) {
|
|
456
|
-
this.calendarSignalsService.activeDate = tempDate;
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
/**
|
|
461
|
-
* Returns whether a cell should be marked as selected.
|
|
462
|
-
* @param value
|
|
463
|
-
*/
|
|
464
|
-
isSelected(value) {
|
|
465
|
-
return this.startValue === value || this.endValue === value;
|
|
466
|
-
}
|
|
467
|
-
/**
|
|
468
|
-
* Returns whether a cell is active.
|
|
469
|
-
* @param rowIndex
|
|
470
|
-
* @param colIndex
|
|
471
|
-
*/
|
|
472
|
-
isActiveCell(rowIndex, colIndex) {
|
|
473
|
-
let cellNumber = rowIndex * this.numCols + colIndex;
|
|
474
|
-
// Account for the fact that the first row may not have as many cells.
|
|
475
|
-
if (rowIndex) {
|
|
476
|
-
cellNumber -= this.firstRowOffset;
|
|
477
|
-
}
|
|
478
|
-
return cellNumber === this.activeCell;
|
|
479
|
-
}
|
|
480
|
-
/**
|
|
481
|
-
* Focuses the active cell after the microtask queue is empty.
|
|
482
|
-
*
|
|
483
|
-
* Adding a 0ms setTimeout seems to fix Voiceover losing focus when pressing PageUp/PageDown
|
|
484
|
-
* (issue #24330).
|
|
485
|
-
*
|
|
486
|
-
* Determined a 0ms by gradually increasing duration from 0 and testing two use cases with screen
|
|
487
|
-
* reader enabled:
|
|
488
|
-
*
|
|
489
|
-
* 1. Pressing PageUp/PageDown repeatedly with pausing between each key press.
|
|
490
|
-
* 2. Pressing and holding the PageDown key with repeated keys enabled.
|
|
491
|
-
*
|
|
492
|
-
* Test 1 worked roughly 95-99% of the time with 0ms and got a little bit better as the duration
|
|
493
|
-
* increased. Test 2 got slightly better until the duration was long enough to interfere with
|
|
494
|
-
* repeated keys. If the repeated key speed was faster than the timeout duration, then pressing
|
|
495
|
-
* and holding pagedown caused the entire page to scroll.
|
|
496
|
-
*
|
|
497
|
-
* Since repeated key speed can verify across machines, determined that any duration could
|
|
498
|
-
* potentially interfere with repeated keys. 0ms would be best because it almost entirely
|
|
499
|
-
* eliminates the focus being lost in Voiceover (#24330) without causing unintended side effects.
|
|
500
|
-
* Adding delay also complicates writing tests.
|
|
501
|
-
*/
|
|
502
|
-
focusActiveCell(movePreview = true) {
|
|
503
|
-
afterNextRender(() => {
|
|
504
|
-
setTimeout(() => {
|
|
505
|
-
const activeCell = this.elementRef.nativeElement.querySelector('.upd-calendar-body-active');
|
|
506
|
-
if (!!activeCell) {
|
|
507
|
-
if (!movePreview) {
|
|
508
|
-
this.skipNextFocus = true;
|
|
509
|
-
}
|
|
510
|
-
activeCell.focus();
|
|
511
|
-
}
|
|
512
|
-
});
|
|
513
|
-
}, { injector: this.injector });
|
|
514
|
-
}
|
|
515
|
-
/**
|
|
516
|
-
* Focuses the active cell after change detection has run and the microtask queue is empty.
|
|
517
|
-
*/
|
|
518
|
-
scheduleFocusActiveCellAfterViewChecked() {
|
|
519
|
-
this.focusActiveCellAfterViewChecked = true;
|
|
520
|
-
}
|
|
521
|
-
/**
|
|
522
|
-
* Gets whether a value is the start of the main range.
|
|
523
|
-
* @param value
|
|
524
|
-
*/
|
|
525
|
-
isRangeStart(value) {
|
|
526
|
-
return this.isStart(value, this.startValue, this.endValue);
|
|
527
|
-
}
|
|
528
|
-
/** Gets whether a value is the end of the main range. */
|
|
529
|
-
isRangeEnd(value) {
|
|
530
|
-
return this.isEnd(value, this.startValue, this.endValue);
|
|
531
|
-
}
|
|
532
|
-
/** Gets whether a value is within the currently-selected range. */
|
|
533
|
-
isInRange(value) {
|
|
534
|
-
return this.isInsideRange(value, this.startValue, this.endValue, this.isRange);
|
|
535
|
-
}
|
|
536
|
-
/** Gets whether a value is the start of the comparison range. */
|
|
537
|
-
isComparisonStart(value) {
|
|
538
|
-
return this.isStart(value, this.comparisonStart, this.comparisonEnd);
|
|
539
|
-
}
|
|
540
|
-
/** Whether the cell is a start bridge cell between the main and comparison ranges. */
|
|
541
|
-
isComparisonBridgeStart(value, rowIndex, colIndex) {
|
|
542
|
-
if (!this.isComparisonStart(value) || this.isRangeStart(value) || !this.isInRange(value)) {
|
|
543
|
-
return false;
|
|
544
|
-
}
|
|
545
|
-
let previousCell = this.rows[rowIndex][colIndex - 1];
|
|
546
|
-
if (!previousCell) {
|
|
547
|
-
const previousRow = this.rows[rowIndex - 1];
|
|
548
|
-
previousCell = previousRow && previousRow[previousRow.length - 1];
|
|
549
|
-
}
|
|
550
|
-
return previousCell && !this.isRangeEnd(previousCell.compareValue);
|
|
551
|
-
}
|
|
552
|
-
/** Whether the cell is an end bridge cell between the main and comparison ranges. */
|
|
553
|
-
isComparisonBridgeEnd(value, rowIndex, colIndex) {
|
|
554
|
-
if (!this.isComparisonEnd(value) || this.isRangeEnd(value) || !this.isInRange(value)) {
|
|
555
|
-
return false;
|
|
556
|
-
}
|
|
557
|
-
let nextCell = this.rows[rowIndex][colIndex + 1];
|
|
558
|
-
if (!nextCell) {
|
|
559
|
-
const nextRow = this.rows[rowIndex + 1];
|
|
560
|
-
nextCell = nextRow && nextRow[0];
|
|
561
|
-
}
|
|
562
|
-
return nextCell && !this.isRangeStart(nextCell.compareValue);
|
|
563
|
-
}
|
|
564
|
-
/** Gets whether a value is the end of the comparison range. */
|
|
565
|
-
isComparisonEnd(value) {
|
|
566
|
-
return this.isEnd(value, this.comparisonStart, this.comparisonEnd);
|
|
567
|
-
}
|
|
568
|
-
/** Gets whether a value is within the current comparison range. */
|
|
569
|
-
isInComparisonRange(value) {
|
|
570
|
-
return this.isInsideRange(value, this.comparisonStart, this.comparisonEnd, this.isRange);
|
|
571
|
-
}
|
|
572
|
-
/**
|
|
573
|
-
* Gets whether a value is the same as the start and end of the comparison range.
|
|
574
|
-
* For context, the functions that we use to determine whether something is the start/end of
|
|
575
|
-
* a range don't allow for the start and end to be on the same day, because we'd have to use
|
|
576
|
-
* much more specific CSS selectors to style them correctly in all scenarios. This is fine for
|
|
577
|
-
* the regular range, because when it happens, the selected styles take over and still show where
|
|
578
|
-
* the range would've been, however we don't have these selected styles for a comparison range.
|
|
579
|
-
* This function is used to apply a class that serves the same purpose as the one for selected
|
|
580
|
-
* dates, but it only applies in the context of a comparison range.
|
|
581
|
-
*/
|
|
582
|
-
isComparisonIdentical(value) {
|
|
583
|
-
// Note that we don't need to null check the start/end
|
|
584
|
-
// here, because the `value` will always be defined.
|
|
585
|
-
return this.comparisonStart === this.comparisonEnd && value === this.comparisonStart;
|
|
586
|
-
}
|
|
587
|
-
/** Gets whether a value is the start of the preview range. */
|
|
588
|
-
isPreviewStart(value) {
|
|
589
|
-
return this.isStart(value, this.previewStart, this.previewEnd);
|
|
590
|
-
}
|
|
591
|
-
/** Gets whether a value is the end of the preview range. */
|
|
592
|
-
isPreviewEnd(value) {
|
|
593
|
-
return this.isEnd(value, this.previewStart, this.previewEnd);
|
|
594
|
-
}
|
|
595
|
-
/** Gets whether a value is inside the preview range. */
|
|
596
|
-
isInPreview(value) {
|
|
597
|
-
// console.log('is in range', this.isInsideRange(value, this.previewStart, this.previewEnd, this.isRange));
|
|
598
|
-
return this.isInsideRange(value, this.previewStart, this.previewEnd, this.isRange);
|
|
599
|
-
}
|
|
600
|
-
/** Gets ids of aria descriptions for the start and end of a date range. */
|
|
601
|
-
getDescribedby(value) {
|
|
602
|
-
if (!this.isRange) {
|
|
603
|
-
return undefined;
|
|
604
|
-
}
|
|
605
|
-
if (this.startValue === value && this.endValue === value) {
|
|
606
|
-
return `${this.startDateLabelId} ${this.endDateLabelId}`;
|
|
607
|
-
}
|
|
608
|
-
else if (this.startValue === value) {
|
|
609
|
-
return this.startDateLabelId;
|
|
610
|
-
}
|
|
611
|
-
else if (this.endValue === value) {
|
|
612
|
-
return this.endDateLabelId;
|
|
613
|
-
}
|
|
614
|
-
return undefined;
|
|
615
|
-
}
|
|
616
|
-
/** Finds the CalendarCell that corresponds to a DOM node. */
|
|
617
|
-
getCellFromElement(element) {
|
|
618
|
-
const cell = this.getCellElement(element);
|
|
619
|
-
if (!!cell) {
|
|
620
|
-
const row = cell.getAttribute('data-upd-row');
|
|
621
|
-
const col = cell.getAttribute('data-upd-col');
|
|
622
|
-
if (row && col) {
|
|
623
|
-
return this.rows[parseInt(row, 10)][parseInt(col, 10)];
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
return undefined;
|
|
627
|
-
}
|
|
628
|
-
/** Checks whether a node is a table cell element. */
|
|
629
|
-
isTableCell(node) {
|
|
630
|
-
return node?.nodeName === 'DIV';
|
|
631
|
-
}
|
|
632
|
-
/**
|
|
633
|
-
* Gets the date table cell element that is or contains the specified element.
|
|
634
|
-
* Or returns null if element is not part of a date cell.
|
|
635
|
-
*/
|
|
636
|
-
getCellElement(element) {
|
|
637
|
-
let cell;
|
|
638
|
-
if (this.isTableCell(element)) {
|
|
639
|
-
cell = element;
|
|
640
|
-
}
|
|
641
|
-
else if (this.isTableCell(element.parentNode || undefined)) {
|
|
642
|
-
cell = element.parentNode;
|
|
643
|
-
}
|
|
644
|
-
else if (this.isTableCell(element.parentNode?.parentNode || undefined)) {
|
|
645
|
-
cell = element.parentNode.parentNode;
|
|
646
|
-
}
|
|
647
|
-
return cell?.getAttribute('data-upd-row') !== undefined ? cell : undefined;
|
|
648
|
-
}
|
|
649
|
-
/** Checks whether a value is the start of a range. */
|
|
650
|
-
isStart(value, start, end) {
|
|
651
|
-
return end !== undefined && start !== end && value < end && value === start;
|
|
652
|
-
}
|
|
653
|
-
/** Checks whether a value is the end of a range. */
|
|
654
|
-
isEnd(value, start, end) {
|
|
655
|
-
return start !== undefined && start !== end && value >= start && value === end;
|
|
656
|
-
}
|
|
657
|
-
/** Checks whether a value is inside of a range. */
|
|
658
|
-
isInsideRange(value, start, end, rangeEnabled) {
|
|
659
|
-
return (rangeEnabled && start !== undefined && end !== undefined && start !== end && value >= start && value <= end);
|
|
660
|
-
}
|
|
661
|
-
/**
|
|
662
|
-
* Extracts the element that actually corresponds to a touch event's location
|
|
663
|
-
* (rather than the element that initiated the sequence of touch events).
|
|
664
|
-
*/
|
|
665
|
-
getActualTouchTarget(event) {
|
|
666
|
-
const touchLocation = event.changedTouches[0];
|
|
667
|
-
return document.elementFromPoint(touchLocation.clientX, touchLocation.clientY);
|
|
668
|
-
}
|
|
669
|
-
/**
|
|
670
|
-
* Takes a day of the month and returns a new date in the same month and year as the currently
|
|
671
|
-
* active date. The returned date will have the same day of the month as the argument date.
|
|
672
|
-
*/
|
|
673
|
-
getDateFromDayOfMonth(activeDate, dayOfMonth) {
|
|
674
|
-
return this.dateService.create(activeDate.getFullYear(), activeDate.getMonth(), dayOfMonth);
|
|
675
|
-
}
|
|
676
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: CalendarBodyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
677
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.1.0", type: CalendarBodyComponent, selector: "upd-calendar-body", inputs: { label: "label", rows: "rows", todayValue: "todayValue", startValue: "startValue", endValue: "endValue", labelMinRequiredCells: "labelMinRequiredCells", numCols: "numCols", activeCell: "activeCell", isRange: "isRange", cellAspectRatio: "cellAspectRatio", comparisonStart: "comparisonStart", comparisonEnd: "comparisonEnd", previewStart: "previewStart", previewEnd: "previewEnd", startDateAccessibleName: "startDateAccessibleName", endDateAccessibleName: "endDateAccessibleName" }, outputs: { selectedValueChange: "selectedValueChange", previewChange: "previewChange", dragStarted: "dragStarted", dragEnded: "dragEnded" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"container\">\n <!--\n If there's not enough space in the first row, create a separate label row. We mark this row as\n aria-hidden because we don't want it to be read out as one of the weeks in the month.\n -->\n @if (firstRowOffset < labelMinRequiredCells) {\n <div class=\"row seven-cols\" aria-hidden=\"true\">\n <div class=\"col-7 p-1 d-flex align-items-center\" [style.min-height.px]=\"40\">\n {{ label }}\n </div>\n </div>\n }\n\n <!-- Create the first row separately so we can include a special spacer cell. -->\n @for (row of rows; track trackRow(row); let rowIndex = $index) {\n <div class=\"row seven-cols\">\n <!--\n This cell is purely decorative, but we can't put `aria-hidden` or `role=\"presentation\"` on it,\n because it throws off the week days for the rest of the row on NVDA. The aspect ratio of the\n table cells is maintained by setting the top and bottom padding as a percentage of the width\n (a variant of the trick described here: https://www.w3schools.com/howto/howto_css_aspect_ratio.asp).\n -->\n @if (rowIndex === 0 && firstRowOffset) {\n <div [ngClass]=\"colspanClass\" class=\"p-1 d-flex align-items-center\" [style.min-height.px]=\"40\">\n {{ firstRowOffset >= labelMinRequiredCells ? label : '' }}\n </div>\n }\n\n <!--\n Each gridcell in the calendar contains a button, which signals to assistive technology that the\n cell is interactable, as well as the selection state via `aria-pressed`. See #23476 for\n background.\n -->\n @for (item of row; track item.id; let colIndex = $index) {\n <div class=\"col-1 justify-content-center p-1 d-flex align-items-center cursor-pointer\" [attr.data-upd-row]=\"rowIndex\"\n [attr.data-upd-col]=\"colIndex\" [style.min-height.px]=\"40\"\n [class.bg-secondary-lt]=\"hoveredDate === getIndex(rowIndex, colIndex)\" [class.border]=\"isActiveCell(rowIndex, colIndex)\"\n [class.border-secondary]=\"isActiveCell(rowIndex, colIndex)\" [class.bg-azure]=\"isSelected(item.compareValue)\"\n [class.text-azure-fg]=\"isSelected(item.compareValue)\" [tabindex]=\"isActiveCell(rowIndex, colIndex) ? 0 : -1\"\n [class.upd-calendar-body-disabled]=\"!item.isEnabled\" [class.bg-danger]=\"isRangeStart(item.compareValue)\"\n [class.text-danger-fg]=\"isRangeStart(item.compareValue)\" [class.bg-muted]=\"isRangeEnd(item.compareValue)\"\n [class.text-muted-fg]=\"isRangeEnd(item.compareValue)\"\n [class.upd-calendar-body-range-end]=\"isRangeEnd(item.compareValue)\"\n [class.upd-calendar-body-in-range]=\"isInRange(item.compareValue)\"\n [class.upd-calendar-body-comparison-bridge-start]=\"isComparisonBridgeStart(item.compareValue, rowIndex, colIndex)\"\n [class.upd-calendar-body-comparison-bridge-end]=\"isComparisonBridgeEnd(item.compareValue, rowIndex, colIndex)\"\n [class.upd-calendar-body-comparison-start]=\"isComparisonStart(item.compareValue)\"\n [class.upd-calendar-body-comparison-end]=\"isComparisonEnd(item.compareValue)\"\n [class.upd-calendar-body-in-comparison-range]=\"isInComparisonRange(item.compareValue)\"\n [class.rounded-start]=\"isPreviewStart(item.compareValue)\" [class.rounded-end]=\"isPreviewEnd(item.compareValue)\"\n [class.border-top]=\"isInPreview(item.compareValue)\" [class.fw-bold]=\"isInPreview(item.compareValue)\"\n [class.border-bottom]=\"isInPreview(item.compareValue)\" [class.border-secondary-lt]=\"isInPreview(item.compareValue)\"\n [attr.aria-label]=\"item.ariaLabel\" [attr.aria-disabled]=\"!item.isEnabled || undefined\"\n [attr.aria-pressed]=\"isSelected(item.compareValue)\"\n [attr.aria-current]=\"todayValue === item.compareValue ? 'date' : undefined\"\n [attr.aria-describedby]=\"getDescribedby(item.compareValue)\" (click)=\"cellClicked(item, $event)\"\n (focus)=\"emitActiveDateChange(item)\" (mouseenter)=\"onDateEnter(getIndex(rowIndex, colIndex))\"\n (mouseleave)=\"onDateLeave()\">\n <span [class.upd-calendar-body-selected]=\"isSelected(item.compareValue)\"\n [class.upd-calendar-body-comparison-identical]=\"isComparisonIdentical(item.compareValue)\"\n [class.upd-calendar-body-today]=\"todayValue === item.compareValue\">\n {{ item.displayValue }}\n </span>\n </div>\n }\n </div>\n }\n\n <label [id]=\"startDateLabelId\" class=\"upd-calendar-body-hidden-label\">\n {{ startDateAccessibleName }}\n </label>\n <label [id]=\"endDateLabelId\" class=\"upd-calendar-body-hidden-label\">\n {{ endDateAccessibleName }}\n </label>\n</div>\n", styles: ["@media (min-width: 768px){.seven-cols .col-1{width:100%}.seven-cols .col-6{width:85.7142857143%}}@media (min-width: 992px){.seven-cols .col-1{width:14.2857142857%}.seven-cols .col-2{width:28.5714285714%}.seven-cols .col-3{width:42.8571428571%}.seven-cols .col-4{width:57.1428571429%}.seven-cols .col-5{width:71.4285714286%}.seven-cols .col-6{width:85.7142857143%}.seven-cols .col-7{width:100%}}@media (min-width: 1200px){.seven-cols .col-1{width:14.2857142857%}.seven-cols .col-2{width:28.5714285714%}.seven-cols .col-3{width:42.8571428571%}.seven-cols .col-4{width:57.1428571429%}.seven-cols .col-5{width:71.4285714286%}.seven-cols .col-6{width:85.7142857143%}.seven-cols .col-7{width:100%}}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
|
|
678
|
-
}
|
|
679
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: CalendarBodyComponent, decorators: [{
|
|
680
|
-
type: Component,
|
|
681
|
-
args: [{ selector: 'upd-calendar-body', template: "<div class=\"container\">\n <!--\n If there's not enough space in the first row, create a separate label row. We mark this row as\n aria-hidden because we don't want it to be read out as one of the weeks in the month.\n -->\n @if (firstRowOffset < labelMinRequiredCells) {\n <div class=\"row seven-cols\" aria-hidden=\"true\">\n <div class=\"col-7 p-1 d-flex align-items-center\" [style.min-height.px]=\"40\">\n {{ label }}\n </div>\n </div>\n }\n\n <!-- Create the first row separately so we can include a special spacer cell. -->\n @for (row of rows; track trackRow(row); let rowIndex = $index) {\n <div class=\"row seven-cols\">\n <!--\n This cell is purely decorative, but we can't put `aria-hidden` or `role=\"presentation\"` on it,\n because it throws off the week days for the rest of the row on NVDA. The aspect ratio of the\n table cells is maintained by setting the top and bottom padding as a percentage of the width\n (a variant of the trick described here: https://www.w3schools.com/howto/howto_css_aspect_ratio.asp).\n -->\n @if (rowIndex === 0 && firstRowOffset) {\n <div [ngClass]=\"colspanClass\" class=\"p-1 d-flex align-items-center\" [style.min-height.px]=\"40\">\n {{ firstRowOffset >= labelMinRequiredCells ? label : '' }}\n </div>\n }\n\n <!--\n Each gridcell in the calendar contains a button, which signals to assistive technology that the\n cell is interactable, as well as the selection state via `aria-pressed`. See #23476 for\n background.\n -->\n @for (item of row; track item.id; let colIndex = $index) {\n <div class=\"col-1 justify-content-center p-1 d-flex align-items-center cursor-pointer\" [attr.data-upd-row]=\"rowIndex\"\n [attr.data-upd-col]=\"colIndex\" [style.min-height.px]=\"40\"\n [class.bg-secondary-lt]=\"hoveredDate === getIndex(rowIndex, colIndex)\" [class.border]=\"isActiveCell(rowIndex, colIndex)\"\n [class.border-secondary]=\"isActiveCell(rowIndex, colIndex)\" [class.bg-azure]=\"isSelected(item.compareValue)\"\n [class.text-azure-fg]=\"isSelected(item.compareValue)\" [tabindex]=\"isActiveCell(rowIndex, colIndex) ? 0 : -1\"\n [class.upd-calendar-body-disabled]=\"!item.isEnabled\" [class.bg-danger]=\"isRangeStart(item.compareValue)\"\n [class.text-danger-fg]=\"isRangeStart(item.compareValue)\" [class.bg-muted]=\"isRangeEnd(item.compareValue)\"\n [class.text-muted-fg]=\"isRangeEnd(item.compareValue)\"\n [class.upd-calendar-body-range-end]=\"isRangeEnd(item.compareValue)\"\n [class.upd-calendar-body-in-range]=\"isInRange(item.compareValue)\"\n [class.upd-calendar-body-comparison-bridge-start]=\"isComparisonBridgeStart(item.compareValue, rowIndex, colIndex)\"\n [class.upd-calendar-body-comparison-bridge-end]=\"isComparisonBridgeEnd(item.compareValue, rowIndex, colIndex)\"\n [class.upd-calendar-body-comparison-start]=\"isComparisonStart(item.compareValue)\"\n [class.upd-calendar-body-comparison-end]=\"isComparisonEnd(item.compareValue)\"\n [class.upd-calendar-body-in-comparison-range]=\"isInComparisonRange(item.compareValue)\"\n [class.rounded-start]=\"isPreviewStart(item.compareValue)\" [class.rounded-end]=\"isPreviewEnd(item.compareValue)\"\n [class.border-top]=\"isInPreview(item.compareValue)\" [class.fw-bold]=\"isInPreview(item.compareValue)\"\n [class.border-bottom]=\"isInPreview(item.compareValue)\" [class.border-secondary-lt]=\"isInPreview(item.compareValue)\"\n [attr.aria-label]=\"item.ariaLabel\" [attr.aria-disabled]=\"!item.isEnabled || undefined\"\n [attr.aria-pressed]=\"isSelected(item.compareValue)\"\n [attr.aria-current]=\"todayValue === item.compareValue ? 'date' : undefined\"\n [attr.aria-describedby]=\"getDescribedby(item.compareValue)\" (click)=\"cellClicked(item, $event)\"\n (focus)=\"emitActiveDateChange(item)\" (mouseenter)=\"onDateEnter(getIndex(rowIndex, colIndex))\"\n (mouseleave)=\"onDateLeave()\">\n <span [class.upd-calendar-body-selected]=\"isSelected(item.compareValue)\"\n [class.upd-calendar-body-comparison-identical]=\"isComparisonIdentical(item.compareValue)\"\n [class.upd-calendar-body-today]=\"todayValue === item.compareValue\">\n {{ item.displayValue }}\n </span>\n </div>\n }\n </div>\n }\n\n <label [id]=\"startDateLabelId\" class=\"upd-calendar-body-hidden-label\">\n {{ startDateAccessibleName }}\n </label>\n <label [id]=\"endDateLabelId\" class=\"upd-calendar-body-hidden-label\">\n {{ endDateAccessibleName }}\n </label>\n</div>\n", styles: ["@media (min-width: 768px){.seven-cols .col-1{width:100%}.seven-cols .col-6{width:85.7142857143%}}@media (min-width: 992px){.seven-cols .col-1{width:14.2857142857%}.seven-cols .col-2{width:28.5714285714%}.seven-cols .col-3{width:42.8571428571%}.seven-cols .col-4{width:57.1428571429%}.seven-cols .col-5{width:71.4285714286%}.seven-cols .col-6{width:85.7142857143%}.seven-cols .col-7{width:100%}}@media (min-width: 1200px){.seven-cols .col-1{width:14.2857142857%}.seven-cols .col-2{width:28.5714285714%}.seven-cols .col-3{width:42.8571428571%}.seven-cols .col-4{width:57.1428571429%}.seven-cols .col-5{width:71.4285714286%}.seven-cols .col-6{width:85.7142857143%}.seven-cols .col-7{width:100%}}\n"] }]
|
|
682
|
-
}], ctorParameters: () => [], propDecorators: { label: [{
|
|
683
|
-
type: Input
|
|
684
|
-
}], rows: [{
|
|
685
|
-
type: Input
|
|
686
|
-
}], todayValue: [{
|
|
687
|
-
type: Input
|
|
688
|
-
}], startValue: [{
|
|
689
|
-
type: Input
|
|
690
|
-
}], endValue: [{
|
|
691
|
-
type: Input
|
|
692
|
-
}], labelMinRequiredCells: [{
|
|
693
|
-
type: Input
|
|
694
|
-
}], numCols: [{
|
|
695
|
-
type: Input
|
|
696
|
-
}], activeCell: [{
|
|
697
|
-
type: Input
|
|
698
|
-
}], isRange: [{
|
|
699
|
-
type: Input
|
|
700
|
-
}], cellAspectRatio: [{
|
|
701
|
-
type: Input
|
|
702
|
-
}], comparisonStart: [{
|
|
703
|
-
type: Input
|
|
704
|
-
}], comparisonEnd: [{
|
|
705
|
-
type: Input
|
|
706
|
-
}], previewStart: [{
|
|
707
|
-
type: Input
|
|
708
|
-
}], previewEnd: [{
|
|
709
|
-
type: Input
|
|
710
|
-
}], startDateAccessibleName: [{
|
|
711
|
-
type: Input
|
|
712
|
-
}], endDateAccessibleName: [{
|
|
713
|
-
type: Input
|
|
714
|
-
}], selectedValueChange: [{
|
|
715
|
-
type: Output
|
|
716
|
-
}], previewChange: [{
|
|
717
|
-
type: Output
|
|
718
|
-
}], dragStarted: [{
|
|
719
|
-
type: Output
|
|
720
|
-
}], dragEnded: [{
|
|
721
|
-
type: Output
|
|
722
|
-
}] } });
|
|
723
|
-
|
|
724
|
-
let uniqueIdCounter$1 = 0;
|
|
725
|
-
/**
|
|
726
|
-
* An internal class that represents the data corresponding to a single calendar cell.
|
|
727
|
-
* @docs-private
|
|
728
|
-
*/
|
|
729
|
-
class CalendarCellModel {
|
|
730
|
-
constructor(value, displayValue, ariaLabel, isEnabled, cssClasses = {}, compareValue = value, rawValue) {
|
|
731
|
-
this.value = value;
|
|
732
|
-
this.displayValue = displayValue;
|
|
733
|
-
this.ariaLabel = ariaLabel;
|
|
734
|
-
this.isEnabled = isEnabled;
|
|
735
|
-
this.cssClasses = cssClasses;
|
|
736
|
-
this.compareValue = compareValue;
|
|
737
|
-
this.rawValue = rawValue;
|
|
738
|
-
this.id = uniqueIdCounter$1++;
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
class KeyboardTools {
|
|
743
|
-
/**
|
|
744
|
-
* Checks whether a modifier key is pressed.
|
|
745
|
-
* @param event Event to be checked.
|
|
746
|
-
* @param modifiers
|
|
747
|
-
*/
|
|
748
|
-
static hasModifierKey(event, ...modifiers) {
|
|
749
|
-
if (modifiers.length) {
|
|
750
|
-
return modifiers.some(modifier => event[modifier]);
|
|
751
|
-
}
|
|
752
|
-
return event.altKey || event.shiftKey || event.ctrlKey || event.metaKey;
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
const yearsPerPage = 24;
|
|
757
|
-
class CalendarMultiYearViewComponent {
|
|
758
|
-
/** Initializes this month view. */
|
|
759
|
-
init() {
|
|
760
|
-
}
|
|
761
|
-
/** Focuses the active cell after the microtask queue is empty. */
|
|
762
|
-
focusActiveCell(movePreview) {
|
|
763
|
-
}
|
|
764
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: CalendarMultiYearViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
765
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.1.0", type: CalendarMultiYearViewComponent, selector: "upd-calendar-multi-year-view", ngImport: i0, template: "<p>calendar-multi-year-view works!</p>\n", styles: [""] }); }
|
|
766
|
-
}
|
|
767
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: CalendarMultiYearViewComponent, decorators: [{
|
|
768
|
-
type: Component,
|
|
769
|
-
args: [{ selector: 'upd-calendar-multi-year-view', template: "<p>calendar-multi-year-view works!</p>\n" }]
|
|
770
|
-
}] });
|
|
771
|
-
|
|
772
|
-
class CalendarService {
|
|
773
|
-
/**
|
|
774
|
-
* When the multi-year view is first opened, the active year will be in view.
|
|
775
|
-
* So we compute how many years are between the active year and the *slot* where our
|
|
776
|
-
* "startingYear" will render when paged into view.
|
|
777
|
-
*/
|
|
778
|
-
getMultiYearActiveOffset(activeDate, minDate, maxDate) {
|
|
779
|
-
const activeYear = activeDate.getFullYear();
|
|
780
|
-
return this.euclideanModulo(activeYear - this.getStartingYear(minDate, maxDate), yearsPerPage);
|
|
781
|
-
}
|
|
782
|
-
isSameMultiYearView(date1, date2, minDate, maxDate) {
|
|
783
|
-
const year1 = date1.getFullYear();
|
|
784
|
-
const year2 = date2.getFullYear();
|
|
785
|
-
const startingYear = this.getStartingYear(minDate, maxDate);
|
|
786
|
-
return Math.floor((year1 - startingYear) / yearsPerPage) === Math.floor((year2 - startingYear) / yearsPerPage);
|
|
787
|
-
}
|
|
788
|
-
getStartingYear(minDate, maxDate) {
|
|
789
|
-
let startingYear = 0;
|
|
790
|
-
if (maxDate) {
|
|
791
|
-
const maxYear = maxDate.getFullYear();
|
|
792
|
-
startingYear = maxYear - yearsPerPage + 1;
|
|
793
|
-
}
|
|
794
|
-
else if (minDate) {
|
|
795
|
-
startingYear = minDate.getFullYear();
|
|
796
|
-
}
|
|
797
|
-
return startingYear;
|
|
798
|
-
}
|
|
799
|
-
euclideanModulo(a, b) {
|
|
800
|
-
return ((a % b) + b) % b;
|
|
801
|
-
}
|
|
802
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: CalendarService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
803
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: CalendarService }); }
|
|
804
|
-
}
|
|
805
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: CalendarService, decorators: [{
|
|
806
|
-
type: Injectable
|
|
807
|
-
}] });
|
|
808
|
-
|
|
809
|
-
let calendarHeaderId = 1;
|
|
810
|
-
class CalendarHeaderComponent {
|
|
811
|
-
constructor() {
|
|
812
|
-
this.id = `upd-calendar-header-${calendarHeaderId++}`;
|
|
813
|
-
this.calendarService = inject(CalendarService);
|
|
814
|
-
this.calendarSignalsService = inject(CalendarSignalsService);
|
|
815
|
-
this.dateService = inject(DateService);
|
|
816
|
-
}
|
|
817
|
-
/**
|
|
818
|
-
* The `aria-label` for changing the calendar view.
|
|
819
|
-
*/
|
|
820
|
-
get periodButtonLabel() {
|
|
821
|
-
return this.calendarSignalsService.currentView() === 'month' ? 'SwitchToMultiYearView' : 'SwitchToMonthView';
|
|
822
|
-
}
|
|
823
|
-
/**
|
|
824
|
-
* The label for the previous button.
|
|
825
|
-
*/
|
|
826
|
-
get prevButtonLabel() {
|
|
827
|
-
return {
|
|
828
|
-
'month': 'PreviousMonth',
|
|
829
|
-
'year': 'PreviousYear',
|
|
830
|
-
'multi-year': 'PreviousMultiYear'
|
|
831
|
-
}[this.calendarSignalsService.currentView()];
|
|
832
|
-
}
|
|
833
|
-
/**
|
|
834
|
-
* The label for the next button.
|
|
835
|
-
*/
|
|
836
|
-
get nextButtonLabel() {
|
|
837
|
-
return {
|
|
838
|
-
'month': 'NextMonth',
|
|
839
|
-
'year': 'NextYear',
|
|
840
|
-
'multi-year': 'NextMultiYear'
|
|
841
|
-
}[this.calendarSignalsService.currentView()];
|
|
842
|
-
}
|
|
843
|
-
/**
|
|
844
|
-
* Whether the selected view is not a month.
|
|
845
|
-
*/
|
|
846
|
-
get isNotMonth() {
|
|
847
|
-
return this.calendarSignalsService.currentView() !== 'month';
|
|
848
|
-
}
|
|
849
|
-
/**
|
|
850
|
-
* ID of the label of the period button.
|
|
851
|
-
*/
|
|
852
|
-
get periodButtonLabelId() {
|
|
853
|
-
return `${this.id}-period-label`;
|
|
854
|
-
}
|
|
855
|
-
get minYearOfPageLabel() {
|
|
856
|
-
return this.dateService.getYearName(this.dateService.create(this.minYearOfPage, 0, 1));
|
|
857
|
-
}
|
|
858
|
-
get maxYearOfPageLabel() {
|
|
859
|
-
const maxYearOfPage = this.minYearOfPage + yearsPerPage - 1;
|
|
860
|
-
return this.dateService.getYearName(this.dateService.create(maxYearOfPage, 0, 1));
|
|
861
|
-
}
|
|
862
|
-
get periodText() {
|
|
863
|
-
if (this.calendarSignalsService.currentView() === 'month') {
|
|
864
|
-
return this.dateService
|
|
865
|
-
.format(this.calendarSignalsService.activeDate(), { year: 'numeric', month: 'short' })
|
|
866
|
-
.toLocaleUpperCase();
|
|
867
|
-
}
|
|
868
|
-
if (this.calendarSignalsService.currentView() === 'year') {
|
|
869
|
-
return this.dateService.getYearName(this.calendarSignalsService.activeDate());
|
|
870
|
-
}
|
|
871
|
-
return '';
|
|
872
|
-
}
|
|
873
|
-
get minYearOfPage() {
|
|
874
|
-
// The offset from the active year to the "slot" for the starting year is the
|
|
875
|
-
// *actual* first rendered year in the multi-year view, and the last year is
|
|
876
|
-
// just yearsPerPage - 1 away.
|
|
877
|
-
const activeDate = this.calendarSignalsService.activeDate();
|
|
878
|
-
const activeYear = activeDate.getFullYear();
|
|
879
|
-
const offset = this.calendarService.getMultiYearActiveOffset(activeDate, this.calendarSignalsService.minDate(), this.calendarSignalsService.maxDate());
|
|
880
|
-
return activeYear - offset;
|
|
881
|
-
}
|
|
882
|
-
/**
|
|
883
|
-
* Handles user clicks on the period label.
|
|
884
|
-
*/
|
|
885
|
-
currentPeriodClicked() {
|
|
886
|
-
this.calendarSignalsService.currentView = this.calendarSignalsService.currentView() === 'month' ? 'multi-year' : 'month';
|
|
887
|
-
}
|
|
888
|
-
/**
|
|
889
|
-
* Handles user clicks on the previous button.
|
|
890
|
-
*/
|
|
891
|
-
previousClicked() {
|
|
892
|
-
this.calendarSignalsService.activeDate =
|
|
893
|
-
this.calendarSignalsService.currentView() === 'month'
|
|
894
|
-
? this.dateService.addMonths(this.calendarSignalsService.activeDate(), -1)
|
|
895
|
-
: this.dateService.addYears(this.calendarSignalsService.activeDate(), this.calendarSignalsService.currentView() === 'year' ? -1 : -yearsPerPage);
|
|
896
|
-
}
|
|
897
|
-
/**
|
|
898
|
-
* Handles user clicks on the next button.
|
|
899
|
-
*/
|
|
900
|
-
nextClicked() {
|
|
901
|
-
this.calendarSignalsService.activeDate =
|
|
902
|
-
this.calendarSignalsService.currentView() === 'month'
|
|
903
|
-
? this.dateService.addMonths(this.calendarSignalsService.activeDate(), 1)
|
|
904
|
-
: this.dateService.addYears(this.calendarSignalsService.activeDate(), this.calendarSignalsService.currentView() === 'year' ? 1 : yearsPerPage);
|
|
905
|
-
}
|
|
906
|
-
/**
|
|
907
|
-
* Whether the previous period button is enabled.
|
|
908
|
-
*/
|
|
909
|
-
previousEnabled() {
|
|
910
|
-
if (!this.calendarSignalsService.minDate()) {
|
|
911
|
-
return true;
|
|
912
|
-
}
|
|
913
|
-
return !this.calendarSignalsService.minDate()
|
|
914
|
-
|| !this.isSameView(this.calendarSignalsService.activeDate(), this.calendarSignalsService.minDate());
|
|
915
|
-
}
|
|
916
|
-
/**
|
|
917
|
-
* Whether the next period button is enabled.
|
|
918
|
-
*/
|
|
919
|
-
nextEnabled() {
|
|
920
|
-
return !this.calendarSignalsService.maxDate()
|
|
921
|
-
|| !this.isSameView(this.calendarSignalsService.activeDate(), this.calendarSignalsService.maxDate());
|
|
922
|
-
}
|
|
923
|
-
/**
|
|
924
|
-
* Whether the two dates represent the same view in the current view mode (month or year).
|
|
925
|
-
*/
|
|
926
|
-
isSameView(date1, date2) {
|
|
927
|
-
if (this.calendarSignalsService.currentView() === 'month') {
|
|
928
|
-
return date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth();
|
|
929
|
-
}
|
|
930
|
-
if (this.calendarSignalsService.currentView() === 'year') {
|
|
931
|
-
return date1.getFullYear() === date2.getFullYear();
|
|
932
|
-
}
|
|
933
|
-
// Otherwise we are in 'multi-year' view.
|
|
934
|
-
return this.calendarService.isSameMultiYearView(date1, date2, this.calendarSignalsService.minDate(), this.calendarSignalsService.maxDate());
|
|
935
|
-
}
|
|
936
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: CalendarHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
937
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.1.0", type: CalendarHeaderComponent, selector: "upd-calendar-header", ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'UpDevs.Calendar'\">\n <div class=\"container\">\n <div class=\"row\">\n <div class=\"col d-flex\">\n <label [id]=\"periodButtonLabelId\" class=\"visually-hidden\" aria-live=\"polite\">\n {{ periodText || t('YearRangeLabel', { start: minYearOfPageLabel, end: maxYearOfPageLabel }) }}\n </label>\n\n <upd-button [isIcon]=\"true\" [iconModel]=\"{tablerIcon:'chevron-left'}\" [isDisabled]=\"!previousEnabled()\"\n (clicked)=\"previousClicked()\" [attr.aria-label]=\"t(prevButtonLabel)\">\n </upd-button>\n\n <upd-button (click)=\"currentPeriodClicked()\" [attr.aria-label]=\"t(periodButtonLabel)\"\n [attr.aria-describedby]=\"periodButtonLabelId\" customClasses=\"mx-1 flex-grow-1\">\n <span aria-hidden=\"true\">\n {{ periodText || t('YearRange', { start: minYearOfPageLabel, end: maxYearOfPageLabel }) }}\n </span>\n <upd-icon [tablerIcon]=\"!isNotMonth ? 'chevron-down' : 'chevron-up'\"></upd-icon>\n </upd-button>\n\n <upd-button [isIcon]=\"true\" [iconModel]=\"{tablerIcon:'chevron-right'}\" [isDisabled]=\"!nextEnabled()\"\n (clicked)=\"nextClicked()\" [attr.aria-label]=\"t(nextButtonLabel)\">\n </upd-button>\n </div>\n </div>\n </div>\n</ng-container>\n", styles: [""], dependencies: [{ kind: "component", type: i1$1.ButtonComponent, selector: "upd-button", inputs: ["model", "text", "brandColorStyle", "customClasses", "isOutline", "isGhost", "isSquare", "isPill", "isIcon", "isLoading", "isList", "isFloating", "isAction", "isNavigationLink", "isLink", "shouldIgnoreBtnClass", "iconModel", "iconPosition", "isDisabled", "isActive", "badgeConfig", "colorStyle", "size", "title"], outputs: ["clicked"] }, { kind: "directive", type: i1$2.TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: i3.IconComponent, selector: "upd-icon", inputs: ["model", "wrapperClasses", "color", "colorClass", "removeDefaultClasses", "customClasses", "tablerIcon", "tablerIconWeight", "tablerIconType", "tablerIconSize", "heroIcon", "heroIconSize", "heroIconType"] }] }); }
|
|
938
|
-
}
|
|
939
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: CalendarHeaderComponent, decorators: [{
|
|
940
|
-
type: Component,
|
|
941
|
-
args: [{ selector: 'upd-calendar-header', template: "<ng-container *transloco=\"let t; prefix: 'UpDevs.Calendar'\">\n <div class=\"container\">\n <div class=\"row\">\n <div class=\"col d-flex\">\n <label [id]=\"periodButtonLabelId\" class=\"visually-hidden\" aria-live=\"polite\">\n {{ periodText || t('YearRangeLabel', { start: minYearOfPageLabel, end: maxYearOfPageLabel }) }}\n </label>\n\n <upd-button [isIcon]=\"true\" [iconModel]=\"{tablerIcon:'chevron-left'}\" [isDisabled]=\"!previousEnabled()\"\n (clicked)=\"previousClicked()\" [attr.aria-label]=\"t(prevButtonLabel)\">\n </upd-button>\n\n <upd-button (click)=\"currentPeriodClicked()\" [attr.aria-label]=\"t(periodButtonLabel)\"\n [attr.aria-describedby]=\"periodButtonLabelId\" customClasses=\"mx-1 flex-grow-1\">\n <span aria-hidden=\"true\">\n {{ periodText || t('YearRange', { start: minYearOfPageLabel, end: maxYearOfPageLabel }) }}\n </span>\n <upd-icon [tablerIcon]=\"!isNotMonth ? 'chevron-down' : 'chevron-up'\"></upd-icon>\n </upd-button>\n\n <upd-button [isIcon]=\"true\" [iconModel]=\"{tablerIcon:'chevron-right'}\" [isDisabled]=\"!nextEnabled()\"\n (clicked)=\"nextClicked()\" [attr.aria-label]=\"t(nextButtonLabel)\">\n </upd-button>\n </div>\n </div>\n </div>\n</ng-container>\n" }]
|
|
942
|
-
}] });
|
|
943
|
-
|
|
944
|
-
const daysPerWeek = 7;
|
|
945
|
-
let uniqueIdCounter = 0;
|
|
946
|
-
class CalendarMonthViewComponent extends BaseComponent {
|
|
947
|
-
/**
|
|
948
|
-
* The date to display in this month view (everything other than the month and year is ignored).
|
|
949
|
-
*/
|
|
950
|
-
get activeDate() {
|
|
951
|
-
return this.calendarSignalsService.activeDate();
|
|
952
|
-
}
|
|
953
|
-
set activeDate(value) {
|
|
954
|
-
this.updateActiveDate(value);
|
|
955
|
-
}
|
|
956
|
-
/** The currently selected date. */
|
|
957
|
-
get selected() {
|
|
958
|
-
return this.calendarSignalsService.selectedDate();
|
|
959
|
-
}
|
|
960
|
-
set selected(value) {
|
|
961
|
-
let currValue;
|
|
962
|
-
if (value instanceof DateRangeModel) {
|
|
963
|
-
currValue = value;
|
|
964
|
-
}
|
|
965
|
-
else {
|
|
966
|
-
currValue = this.dateService.getValidOrUndefined(this.dateService.deserialize(value));
|
|
967
|
-
}
|
|
968
|
-
this.calendarSignalsService.selectedDate = currValue;
|
|
969
|
-
this.setRanges(currValue);
|
|
970
|
-
}
|
|
971
|
-
/** The minimum selectable date. */
|
|
972
|
-
get minDate() {
|
|
973
|
-
return this._minDate;
|
|
974
|
-
}
|
|
975
|
-
set minDate(value) {
|
|
976
|
-
this._minDate = this.dateService.getValidOrUndefined(this.dateService.deserialize(value));
|
|
977
|
-
}
|
|
978
|
-
/** The maximum selectable date. */
|
|
979
|
-
get maxDate() {
|
|
980
|
-
return this._maxDate;
|
|
981
|
-
}
|
|
982
|
-
set maxDate(value) {
|
|
983
|
-
this._maxDate = this.dateService.getValidOrUndefined(this.dateService.deserialize(value));
|
|
984
|
-
}
|
|
130
|
+
class CalendarComponent {
|
|
985
131
|
constructor() {
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
this.
|
|
993
|
-
|
|
994
|
-
this.
|
|
995
|
-
|
|
996
|
-
this.
|
|
997
|
-
|
|
998
|
-
this.
|
|
999
|
-
|
|
1000
|
-
this.
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
this.
|
|
1006
|
-
|
|
1007
|
-
this.
|
|
1008
|
-
|
|
1009
|
-
this.
|
|
1010
|
-
/** The number of blank cells in the first row before the 1st of the month. */
|
|
1011
|
-
this.firstWeekOffset = 0;
|
|
1012
|
-
/** The names of the weekdays. */
|
|
1013
|
-
this.weekdays = [];
|
|
1014
|
-
/** Flag used to filter out space/enter keyup events that originated outside of the view. */
|
|
1015
|
-
this._selectionKeyPressed = false;
|
|
1016
|
-
this.translocoService = inject(TranslocoService);
|
|
1017
|
-
this.changeDetectorRef = inject(ChangeDetectorRef);
|
|
132
|
+
this.selectedDate = input();
|
|
133
|
+
this.selectedStartDate = input();
|
|
134
|
+
this.selectedEndDate = input();
|
|
135
|
+
this.minDate = input();
|
|
136
|
+
this.maxDate = input();
|
|
137
|
+
this.disabledDatesFilter = input();
|
|
138
|
+
this.isRange = input(false);
|
|
139
|
+
this.shouldRemoveExternalBorder = input(false);
|
|
140
|
+
this.selected = output();
|
|
141
|
+
this.monthChanged = output();
|
|
142
|
+
this.CalendarViewEnum = CalendarViewEnum;
|
|
143
|
+
this.currentView = signal(CalendarViewEnum.Days);
|
|
144
|
+
this.currentDate = signal(new Date());
|
|
145
|
+
this.yearRange = signal({ start: 2020, end: 2030 });
|
|
146
|
+
this.currentYear = computed(() => this.currentDate().getFullYear());
|
|
147
|
+
this.currentMonth = computed(() => this.currentDate().getMonth());
|
|
148
|
+
this.currentMonthName = computed(() => this.dateService.format(this.currentDate(), { month: 'short', year: 'numeric' }).toUpperCase());
|
|
149
|
+
this.calendarDays = computed(() => this.generateCalendarDays());
|
|
150
|
+
this.calendarMonths = computed(() => this.generateCalendarMonths());
|
|
151
|
+
this.calendarYears = computed(() => this.generateCalendarYears());
|
|
152
|
+
this.weekDayNames = computed(() => this.dateService.getDayOfWeekNames('narrow'));
|
|
153
|
+
this.internalSelectedDate = signal(undefined);
|
|
154
|
+
this.internalSelectedStartDate = signal(undefined);
|
|
155
|
+
this.internalSelectedEndDate = signal(undefined);
|
|
1018
156
|
this.dateService = inject(DateService);
|
|
1019
|
-
this.
|
|
1020
|
-
this.calendarRangeStrategy = inject(CalendarRangeStrategyService);
|
|
1021
|
-
effect(() => this.updateActiveDate(this.calendarSignalsService.activeDate(), true));
|
|
1022
|
-
}
|
|
1023
|
-
ngAfterContentInit() {
|
|
1024
|
-
const langSub = this.translocoService.langChanges$
|
|
1025
|
-
.pipe(startWith(undefined))
|
|
1026
|
-
.subscribe(() => this.init());
|
|
1027
|
-
this.addSubscriptions(langSub);
|
|
1028
|
-
}
|
|
1029
|
-
ngOnChanges(changes) {
|
|
1030
|
-
const comparisonChange = changes['comparisonStart'] || changes['comparisonEnd'];
|
|
1031
|
-
if (comparisonChange && !comparisonChange.firstChange) {
|
|
1032
|
-
this.setRanges(this.selected);
|
|
1033
|
-
}
|
|
1034
|
-
if (changes['activeDrag'] && !this.activeDrag) {
|
|
1035
|
-
this.clearPreview();
|
|
1036
|
-
}
|
|
157
|
+
this.rangeSelectionState = 'start';
|
|
1037
158
|
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
const currSelection = this.calendarSignalsService.selectedDate();
|
|
1043
|
-
let rangeStartDate;
|
|
1044
|
-
let rangeEndDate;
|
|
1045
|
-
if (currSelection instanceof DateRangeModel) {
|
|
1046
|
-
rangeStartDate = this.getDateInCurrentMonth(currSelection.start);
|
|
1047
|
-
rangeEndDate = this.getDateInCurrentMonth(currSelection.end);
|
|
1048
|
-
}
|
|
1049
|
-
else {
|
|
1050
|
-
rangeStartDate = rangeEndDate = this.getDateInCurrentMonth(currSelection);
|
|
159
|
+
ngOnInit() {
|
|
160
|
+
this.syncInternalState();
|
|
161
|
+
if (this.selectedDate()) {
|
|
162
|
+
this.currentDate.set(new Date(this.selectedDate()));
|
|
1051
163
|
}
|
|
1052
|
-
if (
|
|
1053
|
-
this.
|
|
164
|
+
else if (this.selectedStartDate()) {
|
|
165
|
+
this.currentDate.set(new Date(this.selectedStartDate()));
|
|
1054
166
|
}
|
|
1055
|
-
this.
|
|
1056
|
-
this.clearPreview();
|
|
1057
|
-
this.changeDetectorRef.markForCheck();
|
|
167
|
+
this.updateYearRange();
|
|
1058
168
|
}
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
// navigation should skip over disabled dates, and if so, how to implement that efficiently.
|
|
1064
|
-
const oldActiveDate = this.activeDate;
|
|
1065
|
-
let tempActiveDate;
|
|
1066
|
-
switch (event.key) {
|
|
1067
|
-
case 'LEFT_ARROW':
|
|
1068
|
-
tempActiveDate = this.dateService.addDays(this.activeDate, -1);
|
|
169
|
+
onHeaderClick() {
|
|
170
|
+
switch (this.currentView()) {
|
|
171
|
+
case CalendarViewEnum.Days:
|
|
172
|
+
this.currentView.set(CalendarViewEnum.Months);
|
|
1069
173
|
break;
|
|
1070
|
-
case
|
|
1071
|
-
|
|
174
|
+
case CalendarViewEnum.Months:
|
|
175
|
+
this.currentView.set(CalendarViewEnum.Years);
|
|
1072
176
|
break;
|
|
1073
|
-
|
|
1074
|
-
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
onPreviousClick() {
|
|
180
|
+
const current = this.currentDate();
|
|
181
|
+
switch (this.currentView()) {
|
|
182
|
+
case CalendarViewEnum.Days:
|
|
183
|
+
this.currentDate.set(this.dateService.addMonths(current, -1));
|
|
184
|
+
this.monthChanged.emit(this.currentDate());
|
|
1075
185
|
break;
|
|
1076
|
-
case
|
|
1077
|
-
|
|
186
|
+
case CalendarViewEnum.Months:
|
|
187
|
+
this.currentDate.set(this.dateService.addYears(current, -1));
|
|
1078
188
|
break;
|
|
1079
|
-
case
|
|
1080
|
-
|
|
189
|
+
case CalendarViewEnum.Years:
|
|
190
|
+
this.moveYearRange(-12);
|
|
1081
191
|
break;
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
onNextClick() {
|
|
195
|
+
const current = this.currentDate();
|
|
196
|
+
switch (this.currentView()) {
|
|
197
|
+
case CalendarViewEnum.Days:
|
|
198
|
+
this.currentDate.set(this.dateService.addMonths(current, 1));
|
|
199
|
+
this.monthChanged.emit(this.currentDate());
|
|
1085
200
|
break;
|
|
1086
|
-
case
|
|
1087
|
-
|
|
1088
|
-
? this.dateService.addYears(this.activeDate, -1)
|
|
1089
|
-
: this.dateService.addMonths(this.activeDate, -1);
|
|
201
|
+
case CalendarViewEnum.Months:
|
|
202
|
+
this.currentDate.set(this.dateService.addYears(current, 1));
|
|
1090
203
|
break;
|
|
1091
|
-
case
|
|
1092
|
-
|
|
1093
|
-
? this.dateService.addYears(this.activeDate, 1)
|
|
1094
|
-
: this.dateService.addMonths(this.activeDate, 1);
|
|
204
|
+
case CalendarViewEnum.Years:
|
|
205
|
+
this.moveYearRange(12);
|
|
1095
206
|
break;
|
|
1096
|
-
case 'ENTER':
|
|
1097
|
-
case 'SPACE':
|
|
1098
|
-
this._selectionKeyPressed = true;
|
|
1099
|
-
if (this.canSelect(this.activeDate)) {
|
|
1100
|
-
// Prevent unexpected default actions such as form submission.
|
|
1101
|
-
// Note that we only prevent the default action here while the selection happens in
|
|
1102
|
-
// `keyup` below. We can't do the selection here, because it can cause the calendar to
|
|
1103
|
-
// reopen if focus is restored immediately. We also can't call `preventDefault` on `keyup`
|
|
1104
|
-
// because it's too late (see #23305).
|
|
1105
|
-
event.preventDefault();
|
|
1106
|
-
}
|
|
1107
|
-
return;
|
|
1108
|
-
case 'ESCAPE':
|
|
1109
|
-
// Abort the current range selection if the user presses escape mid-selection.
|
|
1110
|
-
if (this.previewEnd !== undefined && !KeyboardTools.hasModifierKey(event)) {
|
|
1111
|
-
this.clearPreview();
|
|
1112
|
-
// If a drag is in progress, cancel the drag without changing the
|
|
1113
|
-
// current selection.
|
|
1114
|
-
if (this.activeDrag) {
|
|
1115
|
-
this.dragEnded.emit({ value: undefined, event });
|
|
1116
|
-
}
|
|
1117
|
-
else {
|
|
1118
|
-
this.selectedChange.emit(undefined);
|
|
1119
|
-
this.userSelection.emit({ value: undefined, event });
|
|
1120
|
-
}
|
|
1121
|
-
event.preventDefault();
|
|
1122
|
-
event.stopPropagation(); // Prevents the overlay from closing.
|
|
1123
|
-
}
|
|
1124
|
-
return;
|
|
1125
|
-
default:
|
|
1126
|
-
// Don't prevent default or focus active cell on keys that we don't explicitly handle.
|
|
1127
|
-
return;
|
|
1128
|
-
}
|
|
1129
|
-
if (this.dateService.compare(oldActiveDate, this.activeDate)) {
|
|
1130
|
-
this.calendarSignalsService.activeDate = tempActiveDate;
|
|
1131
|
-
this.focusActiveCellAfterViewChecked();
|
|
1132
207
|
}
|
|
1133
|
-
// Prevent unexpected default actions such as form submission.
|
|
1134
|
-
event.preventDefault();
|
|
1135
208
|
}
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
if (this._selectionKeyPressed && this.canSelect(this.activeDate)) {
|
|
1140
|
-
this.dateSelected({ value: this.activeDate.getDate(), event });
|
|
1141
|
-
}
|
|
1142
|
-
this._selectionKeyPressed = false;
|
|
209
|
+
onDateClick(dateModel) {
|
|
210
|
+
if (!dateModel.isCurrentMonth) {
|
|
211
|
+
return;
|
|
1143
212
|
}
|
|
1144
|
-
|
|
1145
|
-
/** Initializes this month view. */
|
|
1146
|
-
init() {
|
|
1147
|
-
this.setRanges(this.selected);
|
|
1148
|
-
this.todayDate = this.getCellCompareValue(new Date());
|
|
1149
|
-
this.monthLabel = this.dateService.getMonthNames('short')[this.activeDate.getMonth()].toLocaleUpperCase();
|
|
1150
|
-
const firstOfMonth = this.dateService.create(this.activeDate.getFullYear(), this.activeDate.getMonth(), 1);
|
|
1151
|
-
this.firstWeekOffset = (daysPerWeek + firstOfMonth.getDay() - this.firstDayOfWeek) % daysPerWeek;
|
|
1152
|
-
this.initWeekdays();
|
|
1153
|
-
this.createWeekCells();
|
|
1154
|
-
this.changeDetectorRef.markForCheck();
|
|
1155
|
-
}
|
|
1156
|
-
/** Focuses the active cell after the microtask queue is empty. */
|
|
1157
|
-
focusActiveCell(movePreview) {
|
|
1158
|
-
this._matCalendarBody.focusActiveCell(movePreview);
|
|
1159
|
-
}
|
|
1160
|
-
/** Focuses the active cell after change detection has run and the microtask queue is empty. */
|
|
1161
|
-
focusActiveCellAfterViewChecked() {
|
|
1162
|
-
this._matCalendarBody.scheduleFocusActiveCellAfterViewChecked();
|
|
1163
|
-
}
|
|
1164
|
-
/** Called when the user has activated a new cell and the preview needs to be updated. */
|
|
1165
|
-
previewChanged({ value: cell }) {
|
|
1166
|
-
if (!this.selected) {
|
|
213
|
+
if (dateModel.isDisabled) {
|
|
1167
214
|
return;
|
|
1168
215
|
}
|
|
1169
|
-
if (this.isRange
|
|
1170
|
-
this.
|
|
216
|
+
if (this.isRange()) {
|
|
217
|
+
this.handleRangeSelection(dateModel.date);
|
|
1171
218
|
}
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
const previewRange = this.calendarRangeStrategy.createPreview(value, this.selected);
|
|
1176
|
-
this.previewStart = this.getCellCompareValue(previewRange.start);
|
|
1177
|
-
this.previewEnd = this.getCellCompareValue(previewRange.end);
|
|
1178
|
-
if (!!this.activeDrag && !!value) {
|
|
1179
|
-
const dragRange = this.calendarRangeStrategy.createDrag?.(this.activeDrag.value, this.selected, value);
|
|
1180
|
-
if (!!dragRange) {
|
|
1181
|
-
this.previewStart = this.getCellCompareValue(dragRange.start);
|
|
1182
|
-
this.previewEnd = this.getCellCompareValue(dragRange.end);
|
|
1183
|
-
}
|
|
219
|
+
else {
|
|
220
|
+
this.internalSelectedDate.set(dateModel.date);
|
|
221
|
+
this.selected.emit({ selectedDate: dateModel.date });
|
|
1184
222
|
}
|
|
1185
|
-
// Note that here we need to use `detectChanges`, rather than `markForCheck`, because
|
|
1186
|
-
// the way `_focusActiveCell` is set up at the moment makes it fire at the wrong time
|
|
1187
|
-
// when navigating one month back using the keyboard which will cause this handler
|
|
1188
|
-
// to throw a "changed after checked" error when updating the preview state.
|
|
1189
|
-
this.changeDetectorRef.detectChanges();
|
|
1190
223
|
}
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
* computes and emits the new range selection.
|
|
1194
|
-
*/
|
|
1195
|
-
_dragEnded(event) {
|
|
1196
|
-
if (!this.activeDrag) {
|
|
224
|
+
onMonthClick(monthModel) {
|
|
225
|
+
if (monthModel.isDisabled) {
|
|
1197
226
|
return;
|
|
1198
227
|
}
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
}
|
|
1204
|
-
else {
|
|
1205
|
-
this.dragEnded.emit({ value: undefined, event: event.event });
|
|
1206
|
-
}
|
|
228
|
+
const newDate = new Date(this.currentYear(), monthModel.monthIndex, 1);
|
|
229
|
+
this.currentDate.set(newDate);
|
|
230
|
+
this.currentView.set(CalendarViewEnum.Days);
|
|
231
|
+
this.monthChanged.emit(newDate);
|
|
1207
232
|
}
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
if (!isFromEffect) {
|
|
1212
|
-
this.calendarSignalsService.activeDate = this.dateService.clamp(validDate, this.minDate, this.maxDate);
|
|
233
|
+
onYearClick(yearModel) {
|
|
234
|
+
if (yearModel.isDisabled) {
|
|
235
|
+
return;
|
|
1213
236
|
}
|
|
1214
|
-
|
|
1215
|
-
|
|
237
|
+
const newDate = new Date(yearModel.year, this.currentMonth(), 1);
|
|
238
|
+
this.currentDate.set(newDate);
|
|
239
|
+
this.currentView.set(CalendarViewEnum.Months);
|
|
240
|
+
}
|
|
241
|
+
clearSelection() {
|
|
242
|
+
this.internalSelectedDate.set(undefined);
|
|
243
|
+
this.internalSelectedStartDate.set(undefined);
|
|
244
|
+
this.internalSelectedEndDate.set(undefined);
|
|
245
|
+
this.rangeSelectionState = 'start';
|
|
246
|
+
this.selected.emit(undefined);
|
|
247
|
+
}
|
|
248
|
+
syncInternalState() {
|
|
249
|
+
this.internalSelectedDate.set(this.selectedDate());
|
|
250
|
+
this.internalSelectedStartDate.set(this.selectedStartDate());
|
|
251
|
+
this.internalSelectedEndDate.set(this.selectedEndDate());
|
|
252
|
+
}
|
|
253
|
+
handleRangeSelection(selectedDate) {
|
|
254
|
+
if (this.rangeSelectionState === 'start' || !this.internalSelectedStartDate()) {
|
|
255
|
+
this.internalSelectedStartDate.set(selectedDate);
|
|
256
|
+
this.internalSelectedEndDate.set(undefined);
|
|
257
|
+
this.rangeSelectionState = 'end';
|
|
258
|
+
this.selected.emit({ startDate: selectedDate });
|
|
1216
259
|
}
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
const
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
260
|
+
else {
|
|
261
|
+
const startDate = this.internalSelectedStartDate();
|
|
262
|
+
const endDate = selectedDate;
|
|
263
|
+
if (this.dateService.compare(selectedDate, startDate) < 0) {
|
|
264
|
+
this.internalSelectedStartDate.set(selectedDate);
|
|
265
|
+
this.internalSelectedEndDate.set(startDate);
|
|
266
|
+
this.selected.emit({
|
|
267
|
+
startDate: selectedDate,
|
|
268
|
+
endDate: startDate
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
this.internalSelectedEndDate.set(endDate);
|
|
273
|
+
this.selected.emit({
|
|
274
|
+
startDate: startDate,
|
|
275
|
+
endDate: endDate
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
this.rangeSelectionState = 'start';
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
generateCalendarDays() {
|
|
282
|
+
const current = this.currentDate();
|
|
283
|
+
const year = current.getFullYear();
|
|
284
|
+
const month = current.getMonth();
|
|
285
|
+
const firstDayOfMonth = new Date(year, month, 1);
|
|
286
|
+
const lastDayOfMonth = new Date(year, month + 1, 0);
|
|
287
|
+
const firstDayOfWeek = firstDayOfMonth.getDay();
|
|
288
|
+
const days = [];
|
|
289
|
+
const today = new Date();
|
|
290
|
+
if (firstDayOfWeek > 0) {
|
|
291
|
+
const prevMonthLastDay = new Date(year, month, 0);
|
|
292
|
+
const startDate = prevMonthLastDay.getDate() - firstDayOfWeek + 1;
|
|
293
|
+
for (let day = startDate; day <= prevMonthLastDay.getDate(); day++) {
|
|
294
|
+
const date = new Date(year, month - 1, day);
|
|
295
|
+
days.push({
|
|
296
|
+
date,
|
|
297
|
+
isCurrentMonth: false,
|
|
298
|
+
isToday: this.dateService.areEqual(date, today),
|
|
299
|
+
isSelected: false,
|
|
300
|
+
isDisabled: true,
|
|
301
|
+
isInRange: false,
|
|
302
|
+
isRangeStart: false,
|
|
303
|
+
isRangeEnd: false
|
|
304
|
+
});
|
|
1245
305
|
}
|
|
1246
|
-
const date = this.dateService.create(this.activeDate.getFullYear(), this.activeDate.getMonth(), i + 1);
|
|
1247
|
-
const isEnabled = this.shouldEnableDate(date);
|
|
1248
|
-
const ariaLabel = this.dateService.format(date, { year: 'numeric', month: 'long', day: 'numeric' });
|
|
1249
|
-
const cellClasses = this.dateClass ? this.dateClass(date, 'month') : undefined;
|
|
1250
|
-
this.weeks[this.weeks.length - 1].push(new CalendarCellModel(i + 1, dateNames[i], ariaLabel, isEnabled, cellClasses, this.getCellCompareValue(date), date));
|
|
1251
306
|
}
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
getDateInCurrentMonth(date) {
|
|
1265
|
-
return !!date && this.isSameMonthAndYearAsActiveDate(date, this.calendarSignalsService.activeDate())
|
|
1266
|
-
? date.getDate()
|
|
1267
|
-
: undefined;
|
|
1268
|
-
}
|
|
1269
|
-
/** Checks whether the 2 dates are non-null and fall within the same month of the same year. */
|
|
1270
|
-
isSameMonthAndYearAsActiveDate(d1, d2) {
|
|
1271
|
-
return (!!d1 && !!d2 && d1.getMonth() === d2.getMonth() && d1.getFullYear() === d2.getFullYear());
|
|
1272
|
-
}
|
|
1273
|
-
/** Gets the value that will be used to one cell to another. */
|
|
1274
|
-
getCellCompareValue(date) {
|
|
1275
|
-
if (!!date) {
|
|
1276
|
-
// We use the time since the Unix epoch to compare dates in this view, rather than the
|
|
1277
|
-
// cell values, because we need to support ranges that span across multiple months/years.
|
|
1278
|
-
const year = date.getFullYear();
|
|
1279
|
-
const month = date.getMonth();
|
|
1280
|
-
const day = date.getDate();
|
|
1281
|
-
return new Date(year, month, day).getTime();
|
|
307
|
+
for (let day = 1; day <= lastDayOfMonth.getDate(); day++) {
|
|
308
|
+
const date = new Date(year, month, day);
|
|
309
|
+
days.push({
|
|
310
|
+
date,
|
|
311
|
+
isCurrentMonth: true,
|
|
312
|
+
isToday: this.dateService.areEqual(date, today),
|
|
313
|
+
isSelected: this.isDateSelected(date),
|
|
314
|
+
isDisabled: this.isDateDisabled(date),
|
|
315
|
+
isInRange: this.isDateInRange(date),
|
|
316
|
+
isRangeStart: this.isDateRangeStart(date),
|
|
317
|
+
isRangeEnd: this.isDateRangeEnd(date)
|
|
318
|
+
});
|
|
1282
319
|
}
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
320
|
+
const totalCells = Math.ceil(days.length / 7) * 7;
|
|
321
|
+
const nextMonthDays = totalCells - days.length;
|
|
322
|
+
for (let day = 1; day <= nextMonthDays; day++) {
|
|
323
|
+
const date = new Date(year, month + 1, day);
|
|
324
|
+
days.push({
|
|
325
|
+
date,
|
|
326
|
+
isCurrentMonth: false,
|
|
327
|
+
isToday: this.dateService.areEqual(date, today),
|
|
328
|
+
isSelected: false,
|
|
329
|
+
isDisabled: true,
|
|
330
|
+
isInRange: false,
|
|
331
|
+
isRangeStart: false,
|
|
332
|
+
isRangeEnd: false
|
|
333
|
+
});
|
|
1291
334
|
}
|
|
1292
|
-
|
|
1293
|
-
|
|
335
|
+
return days;
|
|
336
|
+
}
|
|
337
|
+
generateCalendarMonths() {
|
|
338
|
+
const currentYear = this.currentYear();
|
|
339
|
+
const currentMonth = this.currentMonth();
|
|
340
|
+
const today = new Date();
|
|
341
|
+
const monthNames = this.dateService.getMonthNames('short');
|
|
342
|
+
return monthNames.map((name, index) => ({
|
|
343
|
+
monthIndex: index,
|
|
344
|
+
name: name.toUpperCase(),
|
|
345
|
+
isCurrentMonth: today.getFullYear() === currentYear && today.getMonth() === index,
|
|
346
|
+
isSelected: currentMonth === index,
|
|
347
|
+
isDisabled: this.isMonthDisabled(currentYear, index)
|
|
348
|
+
}));
|
|
349
|
+
}
|
|
350
|
+
generateCalendarYears() {
|
|
351
|
+
const range = this.yearRange();
|
|
352
|
+
const currentYear = this.currentYear();
|
|
353
|
+
const today = new Date();
|
|
354
|
+
const years = [];
|
|
355
|
+
for (let year = range.start; year <= range.end; year++) {
|
|
356
|
+
years.push({
|
|
357
|
+
year,
|
|
358
|
+
isCurrentYear: today.getFullYear() === year,
|
|
359
|
+
isSelected: currentYear === year,
|
|
360
|
+
isDisabled: this.isYearDisabled(year)
|
|
361
|
+
});
|
|
1294
362
|
}
|
|
1295
|
-
|
|
1296
|
-
this.comparisonRangeEnd = this.getCellCompareValue(this.comparisonEnd);
|
|
1297
|
-
}
|
|
1298
|
-
/** Gets whether a date can be selected in the month view. */
|
|
1299
|
-
canSelect(date) {
|
|
1300
|
-
return !this.dateFilter || this.dateFilter(date);
|
|
363
|
+
return years;
|
|
1301
364
|
}
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
}
|
|
1309
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: CalendarMonthViewComponent, decorators: [{
|
|
1310
|
-
type: Component,
|
|
1311
|
-
args: [{ selector: 'upd-calendar-month-view', template: "<upd-calendar-header></upd-calendar-header>\n<div class=\"container mt-2\">\n <div class=\"row seven-cols\">\n @for (day of weekdays; track day.id) {\n <div class=\"col-1 p-1 d-flex justify-content-center align-items-center\">\n <span class=\"visually-hidden\">{{ day.long }}</span>\n <span aria-hidden=\"true\">{{ day.narrow }}</span>\n </div>\n }\n </div>\n</div>\n<upd-calendar-body [label]=\"monthLabel\" [rows]=\"weeks\" [todayValue]=\"todayDate!\" [startValue]=\"rangeStart!\"\n [endValue]=\"rangeEnd!\" [comparisonStart]=\"comparisonRangeStart\" [comparisonEnd]=\"comparisonRangeEnd\"\n [previewStart]=\"previewStart\" [previewEnd]=\"previewEnd\" [isRange]=\"isRange\" [labelMinRequiredCells]=\"3\"\n [activeCell]=\"activeDate.getDate() - 1\" [startDateAccessibleName]=\"startDateAccessibleName\"\n [endDateAccessibleName]=\"endDateAccessibleName\" (selectedValueChange)=\"dateSelected($event)\"\n (previewChange)=\"previewChanged($event)\" (dragStarted)=\"dragStarted.emit($event)\" (dragEnded)=\"_dragEnded($event)\"\n (keyup)=\"handleCalendarBodyKeyup($event)\" (keydown)=\"handleCalendarBodyKeydown($event)\">\n</upd-calendar-body>\n", styles: ["@media (min-width: 768px){.seven-cols .col-1{width:100%}.seven-cols .col-6{width:85.7142857143%}}@media (min-width: 992px){.seven-cols .col-1{width:14.2857142857%}.seven-cols .col-2{width:28.5714285714%}.seven-cols .col-3{width:42.8571428571%}.seven-cols .col-4{width:57.1428571429%}.seven-cols .col-5{width:71.4285714286%}.seven-cols .col-6{width:85.7142857143%}.seven-cols .col-7{width:100%}}@media (min-width: 1200px){.seven-cols .col-1{width:14.2857142857%}.seven-cols .col-2{width:28.5714285714%}.seven-cols .col-3{width:42.8571428571%}.seven-cols .col-4{width:57.1428571429%}.seven-cols .col-5{width:71.4285714286%}.seven-cols .col-6{width:85.7142857143%}.seven-cols .col-7{width:100%}}\n"] }]
|
|
1312
|
-
}], ctorParameters: () => [], propDecorators: { _matCalendarBody: [{
|
|
1313
|
-
type: ViewChild,
|
|
1314
|
-
args: [CalendarBodyComponent]
|
|
1315
|
-
}], activeDate: [{
|
|
1316
|
-
type: Input
|
|
1317
|
-
}], selected: [{
|
|
1318
|
-
type: Input
|
|
1319
|
-
}], minDate: [{
|
|
1320
|
-
type: Input
|
|
1321
|
-
}], maxDate: [{
|
|
1322
|
-
type: Input
|
|
1323
|
-
}], dateFilter: [{
|
|
1324
|
-
type: Input
|
|
1325
|
-
}], dateClass: [{
|
|
1326
|
-
type: Input
|
|
1327
|
-
}], comparisonStart: [{
|
|
1328
|
-
type: Input
|
|
1329
|
-
}], comparisonEnd: [{
|
|
1330
|
-
type: Input
|
|
1331
|
-
}], startDateAccessibleName: [{
|
|
1332
|
-
type: Input
|
|
1333
|
-
}], endDateAccessibleName: [{
|
|
1334
|
-
type: Input
|
|
1335
|
-
}], firstDayOfWeek: [{
|
|
1336
|
-
type: Input
|
|
1337
|
-
}], activeDrag: [{
|
|
1338
|
-
type: Input
|
|
1339
|
-
}], isRange: [{
|
|
1340
|
-
type: Input
|
|
1341
|
-
}], selectedChange: [{
|
|
1342
|
-
type: Output
|
|
1343
|
-
}], userSelection: [{
|
|
1344
|
-
type: Output
|
|
1345
|
-
}], dragStarted: [{
|
|
1346
|
-
type: Output
|
|
1347
|
-
}], dragEnded: [{
|
|
1348
|
-
type: Output
|
|
1349
|
-
}], activeDateChange: [{
|
|
1350
|
-
type: Output
|
|
1351
|
-
}] } });
|
|
1352
|
-
|
|
1353
|
-
class CalendarYearViewComponent {
|
|
1354
|
-
/** Initializes this month view. */
|
|
1355
|
-
init() {
|
|
1356
|
-
}
|
|
1357
|
-
/** Focuses the active cell after the microtask queue is empty. */
|
|
1358
|
-
focusActiveCell(movePreview) {
|
|
1359
|
-
}
|
|
1360
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: CalendarYearViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1361
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.1.0", type: CalendarYearViewComponent, selector: "upd-calendar-year-view", ngImport: i0, template: "<p>calendar-year-view works!</p>\n", styles: [""] }); }
|
|
1362
|
-
}
|
|
1363
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: CalendarYearViewComponent, decorators: [{
|
|
1364
|
-
type: Component,
|
|
1365
|
-
args: [{ selector: 'upd-calendar-year-view', template: "<p>calendar-year-view works!</p>\n" }]
|
|
1366
|
-
}] });
|
|
1367
|
-
|
|
1368
|
-
class CalendarComponent {
|
|
1369
|
-
constructor() {
|
|
1370
|
-
/**
|
|
1371
|
-
* Whether the calendar should be started in month or year view.
|
|
1372
|
-
*/
|
|
1373
|
-
this.startView = 'month';
|
|
1374
|
-
/** Whether the user is currently selecting a range of dates. */
|
|
1375
|
-
this.isRange = false;
|
|
1376
|
-
/** Emits when the currently selected date changes. */
|
|
1377
|
-
this.selectedChange = new EventEmitter();
|
|
1378
|
-
/**
|
|
1379
|
-
* Emits the year chosen in multiyear view.
|
|
1380
|
-
* This doesn't imply a change on the selected date.
|
|
1381
|
-
*/
|
|
1382
|
-
this.yearSelected = new EventEmitter();
|
|
1383
|
-
/**
|
|
1384
|
-
* Emits the month chosen in year view.
|
|
1385
|
-
* This doesn't imply a change on the selected date.
|
|
1386
|
-
*/
|
|
1387
|
-
this.monthSelected = new EventEmitter();
|
|
1388
|
-
/**
|
|
1389
|
-
* Emits when the current view changes.
|
|
1390
|
-
*/
|
|
1391
|
-
this.viewChanged = new EventEmitter(true);
|
|
1392
|
-
/** Emits when any date is selected. */
|
|
1393
|
-
this.userSelection = new EventEmitter();
|
|
1394
|
-
/** Emits a new date range value when the user completes a drag drop operation. */
|
|
1395
|
-
this.userDragDrop = new EventEmitter();
|
|
1396
|
-
/**
|
|
1397
|
-
* Used for scheduling that focus should be moved to the active cell on the next tick.
|
|
1398
|
-
* We need to schedule it, rather than do it immediately, because we have to wait
|
|
1399
|
-
* for Angular to re-evaluate the view children.
|
|
1400
|
-
*/
|
|
1401
|
-
this._moveFocusOnNextTick = false;
|
|
1402
|
-
this.dateService = inject(DateService);
|
|
1403
|
-
this._changeDetectorRef = inject(ChangeDetectorRef);
|
|
1404
|
-
}
|
|
1405
|
-
/** A date representing the period (month or year) to start the calendar in. */
|
|
1406
|
-
get startAt() {
|
|
1407
|
-
return this._startAt;
|
|
1408
|
-
}
|
|
1409
|
-
set startAt(value) {
|
|
1410
|
-
this._startAt = this.dateService.getValidOrUndefined(this.dateService.deserialize(value));
|
|
1411
|
-
}
|
|
1412
|
-
/**
|
|
1413
|
-
* The currently selected date.
|
|
1414
|
-
*/
|
|
1415
|
-
get selected() {
|
|
1416
|
-
return this._selected;
|
|
1417
|
-
}
|
|
1418
|
-
set selected(value) {
|
|
1419
|
-
console.log('setting selected', value);
|
|
1420
|
-
if (value instanceof DateRangeModel) {
|
|
1421
|
-
this._selected = value;
|
|
365
|
+
isDateSelected(date) {
|
|
366
|
+
if (this.isRange()) {
|
|
367
|
+
if (this.internalSelectedStartDate() && this.dateService.areEqual(date, this.internalSelectedStartDate())) {
|
|
368
|
+
return true;
|
|
369
|
+
}
|
|
370
|
+
return !!(this.internalSelectedEndDate() && this.dateService.areEqual(date, this.internalSelectedEndDate()));
|
|
1422
371
|
}
|
|
1423
372
|
else {
|
|
1424
|
-
this.
|
|
373
|
+
return this.internalSelectedDate() ? this.dateService.areEqual(date, this.internalSelectedDate()) : false;
|
|
1425
374
|
}
|
|
1426
375
|
}
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
return this.
|
|
1432
|
-
|
|
1433
|
-
set minDate(value) {
|
|
1434
|
-
this._minDate = this.dateService.getValidOrUndefined(this.dateService.deserialize(value));
|
|
1435
|
-
}
|
|
1436
|
-
/**
|
|
1437
|
-
* The maximum selectable date.
|
|
1438
|
-
*/
|
|
1439
|
-
get maxDate() {
|
|
1440
|
-
return this._maxDate;
|
|
1441
|
-
}
|
|
1442
|
-
set maxDate(value) {
|
|
1443
|
-
this._maxDate = this.dateService.getValidOrUndefined(this.dateService.deserialize(value));
|
|
1444
|
-
}
|
|
1445
|
-
/**
|
|
1446
|
-
* The current active date. This determines which time period is shown and which date is
|
|
1447
|
-
* highlighted when using keyboard navigation.
|
|
1448
|
-
*/
|
|
1449
|
-
get activeDate() {
|
|
1450
|
-
return this._clampedActiveDate;
|
|
376
|
+
isDateInRange(date) {
|
|
377
|
+
if (!this.isRange() || !this.internalSelectedStartDate() || !this.internalSelectedEndDate()) {
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
return this.dateService.compare(date, this.internalSelectedStartDate()) > 0
|
|
381
|
+
&& this.dateService.compare(date, this.internalSelectedEndDate()) < 0;
|
|
1451
382
|
}
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
383
|
+
isDateRangeStart(date) {
|
|
384
|
+
return this.isRange() && this.internalSelectedStartDate()
|
|
385
|
+
? this.dateService.areEqual(date, this.internalSelectedStartDate())
|
|
386
|
+
: false;
|
|
1455
387
|
}
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
388
|
+
isDateRangeEnd(date) {
|
|
389
|
+
return this.isRange() && this.internalSelectedEndDate()
|
|
390
|
+
? this.dateService.areEqual(date, this.internalSelectedEndDate())
|
|
391
|
+
: false;
|
|
1459
392
|
}
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
this._moveFocusOnNextTick = true;
|
|
1464
|
-
this._changeDetectorRef.markForCheck();
|
|
1465
|
-
if (viewChangedResult) {
|
|
1466
|
-
this.viewChanged.emit(viewChangedResult);
|
|
393
|
+
isDateDisabled(date) {
|
|
394
|
+
if (this.minDate() && this.dateService.compare(date, this.minDate()) < 0) {
|
|
395
|
+
return true;
|
|
1467
396
|
}
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
this.activeDate = this.startAt || new Date();
|
|
1471
|
-
// Assign to the private property since we don't want to move focus on init.
|
|
1472
|
-
this._currentView = this.startView;
|
|
1473
|
-
}
|
|
1474
|
-
ngAfterViewChecked() {
|
|
1475
|
-
if (this._moveFocusOnNextTick) {
|
|
1476
|
-
this._moveFocusOnNextTick = false;
|
|
1477
|
-
this.focusActiveCell();
|
|
397
|
+
if (this.maxDate() && this.dateService.compare(date, this.maxDate()) > 0) {
|
|
398
|
+
return true;
|
|
1478
399
|
}
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
// the calendar re-renders when there is no meaningful change to [minDate] or [maxDate]
|
|
1483
|
-
// (#24435).
|
|
1484
|
-
const minDateChange = changes['minDate'] && !this.dateService.areEqual(changes['minDate'].previousValue, changes['minDate'].currentValue)
|
|
1485
|
-
? changes['minDate']
|
|
1486
|
-
: undefined;
|
|
1487
|
-
const maxDateChange = changes['maxDate'] && !this.dateService.areEqual(changes['maxDate'].previousValue, changes['maxDate'].currentValue)
|
|
1488
|
-
? changes['maxDate']
|
|
1489
|
-
: undefined;
|
|
1490
|
-
const change = minDateChange || maxDateChange || changes['dateFilter'];
|
|
1491
|
-
if (change && !change.firstChange) {
|
|
1492
|
-
const view = this._getCurrentViewComponent();
|
|
1493
|
-
if (view) {
|
|
1494
|
-
// We need to `detectChanges` manually here, because the `minDate`, `maxDate` etc. are
|
|
1495
|
-
// passed down to the view via data bindings which won't be up-to-date when we call `_init`.
|
|
1496
|
-
this._changeDetectorRef.detectChanges();
|
|
1497
|
-
view.init();
|
|
1498
|
-
}
|
|
400
|
+
const filterFn = this.disabledDatesFilter();
|
|
401
|
+
if (!!filterFn) {
|
|
402
|
+
return !filterFn(date);
|
|
1499
403
|
}
|
|
404
|
+
return false;
|
|
1500
405
|
}
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
updateTodaysDate() {
|
|
1507
|
-
this._getCurrentViewComponent().init();
|
|
1508
|
-
}
|
|
1509
|
-
/** Handles date selection in the month view. */
|
|
1510
|
-
_dateSelected(event) {
|
|
1511
|
-
const date = event.value;
|
|
1512
|
-
if (this.selected instanceof DateRangeModel || (date && !this.dateService.areEqual(date, this.selected))) {
|
|
1513
|
-
this.selectedChange.emit(date);
|
|
406
|
+
isMonthDisabled(year, month) {
|
|
407
|
+
const firstDayOfMonth = new Date(year, month, 1);
|
|
408
|
+
const lastDayOfMonth = new Date(year, month + 1, 0);
|
|
409
|
+
if (this.minDate() && this.dateService.compare(lastDayOfMonth, this.minDate()) < 0) {
|
|
410
|
+
return true;
|
|
1514
411
|
}
|
|
1515
|
-
this.
|
|
1516
|
-
}
|
|
1517
|
-
/** Handles year selection in the multiyear view. */
|
|
1518
|
-
_yearSelectedInMultiYearView(normalizedYear) {
|
|
1519
|
-
this.yearSelected.emit(normalizedYear);
|
|
1520
|
-
}
|
|
1521
|
-
/** Handles month selection in the year view. */
|
|
1522
|
-
_monthSelectedInYearView(normalizedMonth) {
|
|
1523
|
-
this.monthSelected.emit(normalizedMonth);
|
|
412
|
+
return !!(this.maxDate() && this.dateService.compare(firstDayOfMonth, this.maxDate()) > 0);
|
|
1524
413
|
}
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
this.
|
|
1529
|
-
|
|
1530
|
-
/** Called when the user starts dragging to change a date range. */
|
|
1531
|
-
_dragStarted(event) {
|
|
1532
|
-
this._activeDrag = event;
|
|
1533
|
-
}
|
|
1534
|
-
/**
|
|
1535
|
-
* Called when a drag completes. It may end in cancelation or in the selection
|
|
1536
|
-
* of a new range.
|
|
1537
|
-
*/
|
|
1538
|
-
_dragEnded(event) {
|
|
1539
|
-
if (!this._activeDrag) {
|
|
1540
|
-
return;
|
|
1541
|
-
}
|
|
1542
|
-
if (event.value) {
|
|
1543
|
-
this.userDragDrop.emit(event);
|
|
414
|
+
isYearDisabled(year) {
|
|
415
|
+
const firstDayOfYear = new Date(year, 0, 1);
|
|
416
|
+
const lastDayOfYear = new Date(year, 11, 31);
|
|
417
|
+
if (this.minDate() && this.dateService.compare(lastDayOfYear, this.minDate()) < 0) {
|
|
418
|
+
return true;
|
|
1544
419
|
}
|
|
1545
|
-
this.
|
|
420
|
+
return !!(this.maxDate() && this.dateService.compare(firstDayOfYear, this.maxDate()) > 0);
|
|
1546
421
|
}
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
422
|
+
updateYearRange() {
|
|
423
|
+
const currentYear = this.currentYear();
|
|
424
|
+
this.yearRange.set({
|
|
425
|
+
start: currentYear - 6,
|
|
426
|
+
end: currentYear + 5
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
moveYearRange(offset) {
|
|
430
|
+
const current = this.yearRange();
|
|
431
|
+
this.yearRange.set({
|
|
432
|
+
start: current.start + offset,
|
|
433
|
+
end: current.end + offset
|
|
434
|
+
});
|
|
1553
435
|
}
|
|
1554
436
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: CalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1555
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.1.0", type: CalendarComponent, selector: "upd-calendar", inputs: { startAt: "startAt", startView: "startView", selected: "selected", minDate: "minDate", maxDate: "maxDate", dateFilter: "dateFilter", dateClass: "dateClass", comparisonStart: "comparisonStart", comparisonEnd: "comparisonEnd", startDateAccessibleName: "startDateAccessibleName", endDateAccessibleName: "endDateAccessibleName", isRange: "isRange" }, outputs: { selectedChange: "selectedChange", yearSelected: "yearSelected", monthSelected: "monthSelected", viewChanged: "viewChanged", userSelection: "userSelection", userDragDrop: "userDragDrop" }, viewQueries: [{ propertyName: "monthView", first: true, predicate: CalendarMonthViewComponent, descendants: true }, { propertyName: "yearView", first: true, predicate: CalendarYearViewComponent, descendants: true }, { propertyName: "multiYearView", first: true, predicate: CalendarMultiYearViewComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "@switch (currentView) {\n @case ('month') {\n <upd-calendar-month-view [(activeDate)]=\"activeDate\" [isRange]=\"isRange\" [selected]=\"selected\" [dateFilter]=\"dateFilter\"\n [maxDate]=\"maxDate\" [minDate]=\"minDate\" [dateClass]=\"dateClass\" [comparisonStart]=\"comparisonStart\"\n [comparisonEnd]=\"comparisonEnd\" [startDateAccessibleName]=\"startDateAccessibleName\"\n [endDateAccessibleName]=\"endDateAccessibleName\" (userSelection)=\"_dateSelected($event)\" (dragStarted)=\"_dragStarted($event)\"\n (dragEnded)=\"_dragEnded($event)\" [activeDrag]=\"_activeDrag\">\n </upd-calendar-month-view>\n }\n @case ('year') {\n YEAR!\n <!-- <upd-calendar-year-view-->\n <!-- [(activeDate)]=\"activeDate\"-->\n <!-- [selected]=\"selected\"-->\n <!-- [dateFilter]=\"dateFilter\"-->\n <!-- [maxDate]=\"maxDate\"-->\n <!-- [minDate]=\"minDate\"-->\n <!-- [dateClass]=\"dateClass\"-->\n <!-- (monthSelected)=\"_monthSelectedInYearView($event)\"-->\n <!-- (selectedChange)=\"_goToDateInView($event, 'month')\"></upd-calendar-year-view>-->\n }\n @case ('multi-year') {\n MUUMUMUULTI-YEAR!\n <!-- <upd-calendar-multi-year-view-->\n <!-- [(activeDate)]=\"activeDate\"-->\n <!-- [selected]=\"selected\"-->\n <!-- [dateFilter]=\"dateFilter\"-->\n <!-- [maxDate]=\"maxDate\"-->\n <!-- [minDate]=\"minDate\"-->\n <!-- [dateClass]=\"dateClass\"-->\n <!-- (yearSelected)=\"_yearSelectedInMultiYearView($event)\"-->\n <!-- (selectedChange)=\"_goToDateInView($event, 'year')\"></upd-calendar-multi-year-view>-->\n }\n}\n", styles: [""], dependencies: [{ kind: "component", type: CalendarMonthViewComponent, selector: "upd-calendar-month-view", inputs: ["activeDate", "selected", "minDate", "maxDate", "dateFilter", "dateClass", "comparisonStart", "comparisonEnd", "startDateAccessibleName", "endDateAccessibleName", "firstDayOfWeek", "activeDrag", "isRange"], outputs: ["selectedChange", "userSelection", "dragStarted", "dragEnded", "activeDateChange"] }] }); }
|
|
437
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.1.0", type: CalendarComponent, selector: "upd-calendar", inputs: { selectedDate: { classPropertyName: "selectedDate", publicName: "selectedDate", isSignal: true, isRequired: false, transformFunction: null }, selectedStartDate: { classPropertyName: "selectedStartDate", publicName: "selectedStartDate", isSignal: true, isRequired: false, transformFunction: null }, selectedEndDate: { classPropertyName: "selectedEndDate", publicName: "selectedEndDate", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, disabledDatesFilter: { classPropertyName: "disabledDatesFilter", publicName: "disabledDatesFilter", isSignal: true, isRequired: false, transformFunction: null }, isRange: { classPropertyName: "isRange", publicName: "isRange", isSignal: true, isRequired: false, transformFunction: null }, shouldRemoveExternalBorder: { classPropertyName: "shouldRemoveExternalBorder", publicName: "shouldRemoveExternalBorder", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selected", monthChanged: "monthChanged" }, ngImport: i0, template: "<div class=\"calendar\" [class.calendar-border]=\"!shouldRemoveExternalBorder()\">\n <div class=\"calendar-header\">\n <button type=\"button\" class=\"btn btn-sm btn-ghost-secondary\" (click)=\"onPreviousClick()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"icon\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" stroke-width=\"2\"\n stroke=\"currentColor\" fill=\"none\">\n <path stroke=\"none\" d=\"m0 0h24v24H0z\" fill=\"none\" />\n <path d=\"m15 6-6 6 6 6\" />\n </svg>\n </button>\n\n <button type=\"button\" class=\"btn btn-sm btn-ghost-secondary calendar-title\" (click)=\"onHeaderClick()\">\n @switch (currentView()) {\n @case (CalendarViewEnum.Days) {\n {{ currentMonthName() }}\n }\n @case (CalendarViewEnum.Months) {\n {{ currentYear() }}\n }\n @case (CalendarViewEnum.Years) {\n {{ yearRange().start }} - {{ yearRange().end }}\n }\n }\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"icon ms-1\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" stroke-width=\"2\"\n stroke=\"currentColor\" fill=\"none\">\n <path stroke=\"none\" d=\"m0 0h24v24H0z\" fill=\"none\" />\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n\n <button type=\"button\" class=\"btn btn-sm btn-ghost-secondary\" (click)=\"onNextClick()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"icon\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" stroke-width=\"2\"\n stroke=\"currentColor\" fill=\"none\">\n <path stroke=\"none\" d=\"m0 0h24v24H0z\" fill=\"none\" />\n <path d=\"m9 6 6 6-6 6\" />\n </svg>\n </button>\n </div>\n\n @if (currentView() === CalendarViewEnum.Days) {\n <div class=\"calendar-weekdays\">\n @for (dayName of weekDayNames(); track dayName) {\n <div class=\"calendar-weekday\">{{ dayName }}</div>\n }\n </div>\n\n <div class=\"calendar-days\">\n @for (day of calendarDays(); track day.date.getTime()) {\n <button type=\"button\" class=\"calendar-day\" [class.calendar-day-other-month]=\"!day.isCurrentMonth\"\n [class.calendar-day-today]=\"day.isToday\" [class.calendar-day-selected]=\"day.isSelected\"\n [class.calendar-day-in-range]=\"day.isInRange\" [class.calendar-day-range-start]=\"day.isRangeStart\"\n [class.calendar-day-range-end]=\"day.isRangeEnd\" [disabled]=\"day.isDisabled\" (click)=\"onDateClick(day)\">\n {{ day.date.getDate() }}\n </button>\n }\n </div>\n }\n\n @if (currentView() === CalendarViewEnum.Months) {\n <div class=\"calendar-months\">\n @for (month of calendarMonths(); track month.monthIndex) {\n <button type=\"button\" class=\"calendar-month\" [class.calendar-month-current]=\"month.isCurrentMonth\"\n [class.calendar-month-selected]=\"month.isSelected\" [disabled]=\"month.isDisabled\" (click)=\"onMonthClick(month)\">\n {{ month.name }}\n </button>\n }\n </div>\n }\n\n @if (currentView() === CalendarViewEnum.Years) {\n <div class=\"calendar-years\">\n @for (year of calendarYears(); track year.year) {\n <button type=\"button\" class=\"calendar-year\" [class.calendar-year-current]=\"year.isCurrentYear\"\n [class.calendar-year-selected]=\"year.isSelected\" [disabled]=\"year.isDisabled\" (click)=\"onYearClick(year)\">\n {{ year.year }}\n </button>\n }\n </div>\n }\n</div>\n", styles: [".calendar{background:var(--bs-body-bg);padding:1rem;width:100%;height:100%;border:0!important}.calendar-border{border:1px solid var(--bs-border-color)!important;border-radius:var(--bs-border-radius, .375rem);box-shadow:var(--bs-box-shadow-sm, 0 .125rem .25rem rgba(0, 0, 0, .075))}.calendar-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:1rem}.calendar-header .calendar-title{font-weight:600;flex:1;text-align:center;display:flex;align-items:center;justify-content:center;cursor:pointer}.calendar-header .calendar-title:hover{color:var(--bs-primary)}.calendar-header button{background:transparent;border:none;padding:.25rem;border-radius:var(--bs-border-radius-sm, .25rem);cursor:pointer;color:var(--bs-secondary)}.calendar-header button:hover{background-color:var(--bs-gray-100);color:var(--bs-gray-700)}.calendar-weekdays{display:grid;grid-template-columns:repeat(7,1fr);gap:.25rem;margin-bottom:.5rem}.calendar-weekday{text-align:center;font-size:.75rem;font-weight:600;color:var(--bs-secondary);padding:.25rem;text-transform:uppercase}.calendar-days{display:grid;grid-template-columns:repeat(7,1fr);gap:.125rem}.calendar-day{aspect-ratio:1;border:none;background:transparent;border-radius:var(--bs-border-radius-sm, .25rem);font-size:.875rem;cursor:pointer;transition:all .15s ease-in-out;display:flex;align-items:center;justify-content:center;min-height:32px;font-weight:400;position:relative}.calendar-day:hover:not(:disabled):not(.calendar-day-other-month){background-color:var(--bs-gray-100)}.calendar-day:disabled{cursor:not-allowed}.calendar-day.calendar-day-other-month{color:var(--bs-gray-400, #adb5bd);cursor:default;pointer-events:none}.calendar-day.calendar-day-other-month:hover{background-color:transparent}.calendar-day.calendar-day-today{background-color:var(--bs-primary-bg-subtle, rgba(13, 110, 253, .1));color:var(--bs-primary, #0d6efd);font-weight:600}.calendar-day.calendar-day-today:hover:not(.calendar-day-other-month){background-color:var(--bs-primary-border-subtle, rgba(13, 110, 253, .2))}.calendar-day.calendar-day-selected{background-color:var(--bs-primary, #0d6efd);color:var(--bs-white, white);font-weight:600}.calendar-day.calendar-day-selected:hover:not(.calendar-day-other-month){background-color:var(--bs-primary-dark, #0a58ca)}.calendar-day.calendar-day-in-range{border-radius:0;background-color:var(--bs-secondary-bg-subtle, rgba(108, 117, 125, .1));color:var(--bs-secondary-emphasis, #495057)}.calendar-day.calendar-day-in-range:hover:not(.calendar-day-other-month){background-color:var(--bs-secondary-border-subtle, rgba(108, 117, 125, .2))}.calendar-day.calendar-day-range-start{background-color:var(--bs-primary, #0d6efd);color:var(--bs-white, white);font-weight:600;border-top-right-radius:0;border-bottom-right-radius:0}.calendar-day.calendar-day-range-start:hover:not(.calendar-day-other-month){background-color:var(--bs-primary-dark, #0a58ca)}.calendar-day.calendar-day-range-end{background-color:var(--bs-primary, #0d6efd);color:var(--bs-white, white);font-weight:600;border-top-left-radius:0;border-bottom-left-radius:0}.calendar-day.calendar-day-range-end:hover:not(.calendar-day-other-month){background-color:var(--bs-primary-dark, #0a58ca)}.calendar-day.calendar-day-range-start.calendar-day-range-end{border-radius:var(--bs-border-radius-sm, .25rem)}.calendar-day.calendar-day-other-month.calendar-day-selected{background-color:transparent;color:var(--bs-gray-400, #adb5bd);font-weight:400}.calendar-months{display:grid;grid-template-columns:repeat(3,1fr);gap:.5rem}.calendar-month{padding:.75rem .5rem;border:none;background:transparent;border-radius:var(--bs-border-radius-sm, .25rem);font-size:.875rem;font-weight:500;cursor:pointer;transition:all .15s ease-in-out}.calendar-month:hover:not(:disabled){background-color:var(--bs-gray-100, #f8f9fa)}.calendar-month:disabled{color:var(--bs-gray-400, #adb5bd);cursor:not-allowed}.calendar-month.calendar-month-current{background-color:var(--bs-primary-bg-subtle, rgba(13, 110, 253, .1));color:var(--bs-primary, #0d6efd);font-weight:600}.calendar-month.calendar-month-selected{background-color:var(--bs-primary, #0d6efd);color:var(--bs-white, white);font-weight:600}.calendar-month.calendar-month-selected:hover{background-color:var(--bs-primary-dark, #0a58ca)}.calendar-years{display:grid;grid-template-columns:repeat(3,1fr);gap:.5rem}.calendar-year{padding:.75rem .5rem;border:none;background:transparent;border-radius:var(--bs-border-radius-sm, .25rem);font-size:.875rem;font-weight:500;cursor:pointer;transition:all .15s ease-in-out}.calendar-year:hover:not(:disabled){background-color:var(--bs-gray-100, #f8f9fa)}.calendar-year:disabled{color:var(--bs-gray-400, #adb5bd);cursor:not-allowed}.calendar-year.calendar-year-current{background-color:var(--bs-primary-bg-subtle, rgba(13, 110, 253, .1));color:var(--bs-primary, #0d6efd);font-weight:600}.calendar-year.calendar-year-selected{background-color:var(--bs-primary, #0d6efd);color:var(--bs-white, white);font-weight:600}.calendar-year.calendar-year-selected:hover{background-color:var(--bs-primary-dark, #0a58ca)}.calendar-day-not-selectable{pointer-events:none;opacity:.5}\n"] }); }
|
|
1556
438
|
}
|
|
1557
439
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: CalendarComponent, decorators: [{
|
|
1558
440
|
type: Component,
|
|
1559
|
-
args: [{ selector: 'upd-calendar', template: "
|
|
1560
|
-
}]
|
|
1561
|
-
type: ViewChild,
|
|
1562
|
-
args: [CalendarMonthViewComponent]
|
|
1563
|
-
}], yearView: [{
|
|
1564
|
-
type: ViewChild,
|
|
1565
|
-
args: [CalendarYearViewComponent]
|
|
1566
|
-
}], multiYearView: [{
|
|
1567
|
-
type: ViewChild,
|
|
1568
|
-
args: [CalendarMultiYearViewComponent]
|
|
1569
|
-
}], startAt: [{
|
|
1570
|
-
type: Input
|
|
1571
|
-
}], startView: [{
|
|
1572
|
-
type: Input
|
|
1573
|
-
}], selected: [{
|
|
1574
|
-
type: Input
|
|
1575
|
-
}], minDate: [{
|
|
1576
|
-
type: Input
|
|
1577
|
-
}], maxDate: [{
|
|
1578
|
-
type: Input
|
|
1579
|
-
}], dateFilter: [{
|
|
1580
|
-
type: Input
|
|
1581
|
-
}], dateClass: [{
|
|
1582
|
-
type: Input
|
|
1583
|
-
}], comparisonStart: [{
|
|
1584
|
-
type: Input
|
|
1585
|
-
}], comparisonEnd: [{
|
|
1586
|
-
type: Input
|
|
1587
|
-
}], startDateAccessibleName: [{
|
|
1588
|
-
type: Input
|
|
1589
|
-
}], endDateAccessibleName: [{
|
|
1590
|
-
type: Input
|
|
1591
|
-
}], isRange: [{
|
|
1592
|
-
type: Input
|
|
1593
|
-
}], selectedChange: [{
|
|
1594
|
-
type: Output
|
|
1595
|
-
}], yearSelected: [{
|
|
1596
|
-
type: Output
|
|
1597
|
-
}], monthSelected: [{
|
|
1598
|
-
type: Output
|
|
1599
|
-
}], viewChanged: [{
|
|
1600
|
-
type: Output
|
|
1601
|
-
}], userSelection: [{
|
|
1602
|
-
type: Output
|
|
1603
|
-
}], userDragDrop: [{
|
|
1604
|
-
type: Output
|
|
1605
|
-
}] } });
|
|
441
|
+
args: [{ selector: 'upd-calendar', template: "<div class=\"calendar\" [class.calendar-border]=\"!shouldRemoveExternalBorder()\">\n <div class=\"calendar-header\">\n <button type=\"button\" class=\"btn btn-sm btn-ghost-secondary\" (click)=\"onPreviousClick()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"icon\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" stroke-width=\"2\"\n stroke=\"currentColor\" fill=\"none\">\n <path stroke=\"none\" d=\"m0 0h24v24H0z\" fill=\"none\" />\n <path d=\"m15 6-6 6 6 6\" />\n </svg>\n </button>\n\n <button type=\"button\" class=\"btn btn-sm btn-ghost-secondary calendar-title\" (click)=\"onHeaderClick()\">\n @switch (currentView()) {\n @case (CalendarViewEnum.Days) {\n {{ currentMonthName() }}\n }\n @case (CalendarViewEnum.Months) {\n {{ currentYear() }}\n }\n @case (CalendarViewEnum.Years) {\n {{ yearRange().start }} - {{ yearRange().end }}\n }\n }\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"icon ms-1\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" stroke-width=\"2\"\n stroke=\"currentColor\" fill=\"none\">\n <path stroke=\"none\" d=\"m0 0h24v24H0z\" fill=\"none\" />\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n\n <button type=\"button\" class=\"btn btn-sm btn-ghost-secondary\" (click)=\"onNextClick()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"icon\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" stroke-width=\"2\"\n stroke=\"currentColor\" fill=\"none\">\n <path stroke=\"none\" d=\"m0 0h24v24H0z\" fill=\"none\" />\n <path d=\"m9 6 6 6-6 6\" />\n </svg>\n </button>\n </div>\n\n @if (currentView() === CalendarViewEnum.Days) {\n <div class=\"calendar-weekdays\">\n @for (dayName of weekDayNames(); track dayName) {\n <div class=\"calendar-weekday\">{{ dayName }}</div>\n }\n </div>\n\n <div class=\"calendar-days\">\n @for (day of calendarDays(); track day.date.getTime()) {\n <button type=\"button\" class=\"calendar-day\" [class.calendar-day-other-month]=\"!day.isCurrentMonth\"\n [class.calendar-day-today]=\"day.isToday\" [class.calendar-day-selected]=\"day.isSelected\"\n [class.calendar-day-in-range]=\"day.isInRange\" [class.calendar-day-range-start]=\"day.isRangeStart\"\n [class.calendar-day-range-end]=\"day.isRangeEnd\" [disabled]=\"day.isDisabled\" (click)=\"onDateClick(day)\">\n {{ day.date.getDate() }}\n </button>\n }\n </div>\n }\n\n @if (currentView() === CalendarViewEnum.Months) {\n <div class=\"calendar-months\">\n @for (month of calendarMonths(); track month.monthIndex) {\n <button type=\"button\" class=\"calendar-month\" [class.calendar-month-current]=\"month.isCurrentMonth\"\n [class.calendar-month-selected]=\"month.isSelected\" [disabled]=\"month.isDisabled\" (click)=\"onMonthClick(month)\">\n {{ month.name }}\n </button>\n }\n </div>\n }\n\n @if (currentView() === CalendarViewEnum.Years) {\n <div class=\"calendar-years\">\n @for (year of calendarYears(); track year.year) {\n <button type=\"button\" class=\"calendar-year\" [class.calendar-year-current]=\"year.isCurrentYear\"\n [class.calendar-year-selected]=\"year.isSelected\" [disabled]=\"year.isDisabled\" (click)=\"onYearClick(year)\">\n {{ year.year }}\n </button>\n }\n </div>\n }\n</div>\n", styles: [".calendar{background:var(--bs-body-bg);padding:1rem;width:100%;height:100%;border:0!important}.calendar-border{border:1px solid var(--bs-border-color)!important;border-radius:var(--bs-border-radius, .375rem);box-shadow:var(--bs-box-shadow-sm, 0 .125rem .25rem rgba(0, 0, 0, .075))}.calendar-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:1rem}.calendar-header .calendar-title{font-weight:600;flex:1;text-align:center;display:flex;align-items:center;justify-content:center;cursor:pointer}.calendar-header .calendar-title:hover{color:var(--bs-primary)}.calendar-header button{background:transparent;border:none;padding:.25rem;border-radius:var(--bs-border-radius-sm, .25rem);cursor:pointer;color:var(--bs-secondary)}.calendar-header button:hover{background-color:var(--bs-gray-100);color:var(--bs-gray-700)}.calendar-weekdays{display:grid;grid-template-columns:repeat(7,1fr);gap:.25rem;margin-bottom:.5rem}.calendar-weekday{text-align:center;font-size:.75rem;font-weight:600;color:var(--bs-secondary);padding:.25rem;text-transform:uppercase}.calendar-days{display:grid;grid-template-columns:repeat(7,1fr);gap:.125rem}.calendar-day{aspect-ratio:1;border:none;background:transparent;border-radius:var(--bs-border-radius-sm, .25rem);font-size:.875rem;cursor:pointer;transition:all .15s ease-in-out;display:flex;align-items:center;justify-content:center;min-height:32px;font-weight:400;position:relative}.calendar-day:hover:not(:disabled):not(.calendar-day-other-month){background-color:var(--bs-gray-100)}.calendar-day:disabled{cursor:not-allowed}.calendar-day.calendar-day-other-month{color:var(--bs-gray-400, #adb5bd);cursor:default;pointer-events:none}.calendar-day.calendar-day-other-month:hover{background-color:transparent}.calendar-day.calendar-day-today{background-color:var(--bs-primary-bg-subtle, rgba(13, 110, 253, .1));color:var(--bs-primary, #0d6efd);font-weight:600}.calendar-day.calendar-day-today:hover:not(.calendar-day-other-month){background-color:var(--bs-primary-border-subtle, rgba(13, 110, 253, .2))}.calendar-day.calendar-day-selected{background-color:var(--bs-primary, #0d6efd);color:var(--bs-white, white);font-weight:600}.calendar-day.calendar-day-selected:hover:not(.calendar-day-other-month){background-color:var(--bs-primary-dark, #0a58ca)}.calendar-day.calendar-day-in-range{border-radius:0;background-color:var(--bs-secondary-bg-subtle, rgba(108, 117, 125, .1));color:var(--bs-secondary-emphasis, #495057)}.calendar-day.calendar-day-in-range:hover:not(.calendar-day-other-month){background-color:var(--bs-secondary-border-subtle, rgba(108, 117, 125, .2))}.calendar-day.calendar-day-range-start{background-color:var(--bs-primary, #0d6efd);color:var(--bs-white, white);font-weight:600;border-top-right-radius:0;border-bottom-right-radius:0}.calendar-day.calendar-day-range-start:hover:not(.calendar-day-other-month){background-color:var(--bs-primary-dark, #0a58ca)}.calendar-day.calendar-day-range-end{background-color:var(--bs-primary, #0d6efd);color:var(--bs-white, white);font-weight:600;border-top-left-radius:0;border-bottom-left-radius:0}.calendar-day.calendar-day-range-end:hover:not(.calendar-day-other-month){background-color:var(--bs-primary-dark, #0a58ca)}.calendar-day.calendar-day-range-start.calendar-day-range-end{border-radius:var(--bs-border-radius-sm, .25rem)}.calendar-day.calendar-day-other-month.calendar-day-selected{background-color:transparent;color:var(--bs-gray-400, #adb5bd);font-weight:400}.calendar-months{display:grid;grid-template-columns:repeat(3,1fr);gap:.5rem}.calendar-month{padding:.75rem .5rem;border:none;background:transparent;border-radius:var(--bs-border-radius-sm, .25rem);font-size:.875rem;font-weight:500;cursor:pointer;transition:all .15s ease-in-out}.calendar-month:hover:not(:disabled){background-color:var(--bs-gray-100, #f8f9fa)}.calendar-month:disabled{color:var(--bs-gray-400, #adb5bd);cursor:not-allowed}.calendar-month.calendar-month-current{background-color:var(--bs-primary-bg-subtle, rgba(13, 110, 253, .1));color:var(--bs-primary, #0d6efd);font-weight:600}.calendar-month.calendar-month-selected{background-color:var(--bs-primary, #0d6efd);color:var(--bs-white, white);font-weight:600}.calendar-month.calendar-month-selected:hover{background-color:var(--bs-primary-dark, #0a58ca)}.calendar-years{display:grid;grid-template-columns:repeat(3,1fr);gap:.5rem}.calendar-year{padding:.75rem .5rem;border:none;background:transparent;border-radius:var(--bs-border-radius-sm, .25rem);font-size:.875rem;font-weight:500;cursor:pointer;transition:all .15s ease-in-out}.calendar-year:hover:not(:disabled){background-color:var(--bs-gray-100, #f8f9fa)}.calendar-year:disabled{color:var(--bs-gray-400, #adb5bd);cursor:not-allowed}.calendar-year.calendar-year-current{background-color:var(--bs-primary-bg-subtle, rgba(13, 110, 253, .1));color:var(--bs-primary, #0d6efd);font-weight:600}.calendar-year.calendar-year-selected{background-color:var(--bs-primary, #0d6efd);color:var(--bs-white, white);font-weight:600}.calendar-year.calendar-year-selected:hover{background-color:var(--bs-primary-dark, #0a58ca)}.calendar-day-not-selectable{pointer-events:none;opacity:.5}\n"] }]
|
|
442
|
+
}] });
|
|
1606
443
|
|
|
1607
444
|
var UpDevs$1 = {
|
|
1608
445
|
Calendar: {
|
|
@@ -1652,24 +489,63 @@ var pt$1 = /*#__PURE__*/Object.freeze({
|
|
|
1652
489
|
default: pt
|
|
1653
490
|
});
|
|
1654
491
|
|
|
492
|
+
class CalendarSignalsService {
|
|
493
|
+
constructor() {
|
|
494
|
+
this.minDateSignal = signal(undefined);
|
|
495
|
+
this.maxDateSignal = signal(undefined);
|
|
496
|
+
this.activeDateSignal = signal(new Date());
|
|
497
|
+
this.selectedDateSignal = signal(undefined);
|
|
498
|
+
this.currentViewSignal = signal('month');
|
|
499
|
+
}
|
|
500
|
+
get minDate() {
|
|
501
|
+
return this.minDateSignal.asReadonly();
|
|
502
|
+
}
|
|
503
|
+
set minDate(value) {
|
|
504
|
+
this.minDateSignal.set(value);
|
|
505
|
+
}
|
|
506
|
+
get maxDate() {
|
|
507
|
+
return this.maxDateSignal.asReadonly();
|
|
508
|
+
}
|
|
509
|
+
set maxDate(value) {
|
|
510
|
+
this.maxDateSignal.set(value);
|
|
511
|
+
}
|
|
512
|
+
get activeDate() {
|
|
513
|
+
return this.activeDateSignal.asReadonly();
|
|
514
|
+
}
|
|
515
|
+
set activeDate(value) {
|
|
516
|
+
this.activeDateSignal.set(value);
|
|
517
|
+
}
|
|
518
|
+
get selectedDate() {
|
|
519
|
+
return this.selectedDateSignal.asReadonly();
|
|
520
|
+
}
|
|
521
|
+
set selectedDate(value) {
|
|
522
|
+
this.selectedDateSignal.set(value);
|
|
523
|
+
}
|
|
524
|
+
get currentView() {
|
|
525
|
+
return this.currentViewSignal.asReadonly();
|
|
526
|
+
}
|
|
527
|
+
set currentView(value) {
|
|
528
|
+
this.currentViewSignal.set(value);
|
|
529
|
+
}
|
|
530
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: CalendarSignalsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
531
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: CalendarSignalsService }); }
|
|
532
|
+
}
|
|
533
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: CalendarSignalsService, decorators: [{
|
|
534
|
+
type: Injectable
|
|
535
|
+
}] });
|
|
536
|
+
|
|
1655
537
|
class UpdCalendarModule {
|
|
1656
538
|
constructor(translocoService) {
|
|
1657
539
|
translocoService.setFallbackLangForMissingTranslation({ fallbackLang: 'en' });
|
|
1658
540
|
translocoService.setTranslation(en$1, 'en');
|
|
1659
541
|
translocoService.setTranslation(pt$1, 'pt');
|
|
1660
542
|
}
|
|
1661
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: UpdCalendarModule, deps: [{ token: i1
|
|
1662
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.1.0", ngImport: i0, type: UpdCalendarModule, declarations: [
|
|
1663
|
-
CalendarMultiYearViewComponent,
|
|
1664
|
-
CalendarYearViewComponent,
|
|
1665
|
-
CalendarMonthViewComponent,
|
|
1666
|
-
CalendarBodyComponent,
|
|
1667
|
-
CalendarComponent], imports: [CommonModule,
|
|
543
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: UpdCalendarModule, deps: [{ token: i1.TranslocoService }], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
544
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.1.0", ngImport: i0, type: UpdCalendarModule, declarations: [CalendarComponent], imports: [CommonModule,
|
|
1668
545
|
UpdButtonModule,
|
|
1669
546
|
TranslocoDirective,
|
|
1670
547
|
UpdIconsModule], exports: [CalendarComponent] }); }
|
|
1671
548
|
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: UpdCalendarModule, providers: [
|
|
1672
|
-
CalendarService,
|
|
1673
549
|
CalendarSignalsService,
|
|
1674
550
|
CalendarRangeStrategyService
|
|
1675
551
|
], imports: [CommonModule,
|
|
@@ -1686,27 +562,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImpor
|
|
|
1686
562
|
UpdIconsModule
|
|
1687
563
|
],
|
|
1688
564
|
declarations: [
|
|
1689
|
-
CalendarHeaderComponent,
|
|
1690
|
-
CalendarMultiYearViewComponent,
|
|
1691
|
-
CalendarYearViewComponent,
|
|
1692
|
-
CalendarMonthViewComponent,
|
|
1693
|
-
CalendarBodyComponent,
|
|
1694
565
|
CalendarComponent
|
|
1695
566
|
],
|
|
1696
567
|
exports: [
|
|
1697
568
|
CalendarComponent
|
|
1698
569
|
],
|
|
1699
570
|
providers: [
|
|
1700
|
-
CalendarService,
|
|
1701
571
|
CalendarSignalsService,
|
|
1702
572
|
CalendarRangeStrategyService
|
|
1703
573
|
]
|
|
1704
574
|
}]
|
|
1705
|
-
}], ctorParameters: () => [{ type: i1
|
|
575
|
+
}], ctorParameters: () => [{ type: i1.TranslocoService }] });
|
|
1706
576
|
|
|
1707
577
|
/**
|
|
1708
578
|
* Generated bundle index. Do not edit.
|
|
1709
579
|
*/
|
|
1710
580
|
|
|
1711
|
-
export { CalendarComponent, CalendarRangeStrategyService, DateRangeModel, UpdCalendarModule };
|
|
581
|
+
export { CalendarComponent, CalendarRangeStrategyService, CalendarViewEnum, DateRangeModel, UpdCalendarModule };
|
|
1712
582
|
//# sourceMappingURL=updevs-components-calendar.mjs.map
|