Skip to content

Commit 542bb6b

Browse files
committed
refactor(material/datepicker): convert internal calendar state to signals
Converts some of the internal calendar state to signals to test the waters on how breaking it would be.
1 parent 3665b43 commit 542bb6b

File tree

7 files changed

+115
-102
lines changed

7 files changed

+115
-102
lines changed

goldens/material/datepicker/index.api.md

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -667,8 +667,8 @@ export class MatMonthView<D> implements AfterContentInit, OnChanges, OnDestroy {
667667
// (undocumented)
668668
readonly _changeDetectorRef: ChangeDetectorRef;
669669
comparisonEnd: D | null;
670-
_comparisonRangeEnd: number | null;
671-
_comparisonRangeStart: number | null;
670+
_comparisonRangeEnd: i0.WritableSignal<number | null>;
671+
_comparisonRangeStart: i0.WritableSignal<number | null>;
672672
comparisonStart: D | null;
673673
// (undocumented)
674674
_dateAdapter: DateAdapter<D, any>;
@@ -679,43 +679,43 @@ export class MatMonthView<D> implements AfterContentInit, OnChanges, OnDestroy {
679679
protected _dragEnded(event: MatCalendarUserEvent<D | null>): void;
680680
readonly dragStarted: EventEmitter<MatCalendarUserEvent<D>>;
681681
endDateAccessibleName: string | null;
682-
_firstWeekOffset: number;
682+
_firstWeekOffset: i0.WritableSignal<number>;
683683
_focusActiveCell(movePreview?: boolean): void;
684684
_focusActiveCellAfterViewChecked(): void;
685685
_handleCalendarBodyKeydown(event: KeyboardEvent): void;
686686
_handleCalendarBodyKeyup(event: KeyboardEvent): void;
687687
_init(): void;
688-
_isRange: boolean;
688+
_isRange: i0.WritableSignal<boolean>;
689689
_matCalendarBody: MatCalendarBody;
690690
get maxDate(): D | null;
691691
set maxDate(value: D | null);
692692
get minDate(): D | null;
693693
set minDate(value: D | null);
694-
_monthLabel: string;
694+
_monthLabel: i0.WritableSignal<string>;
695695
// (undocumented)
696696
ngAfterContentInit(): void;
697697
// (undocumented)
698698
ngOnChanges(changes: SimpleChanges): void;
699699
// (undocumented)
700700
ngOnDestroy(): void;
701701
_previewChanged({ event, value: cell }: MatCalendarUserEvent<MatCalendarCell<D> | null>): void;
702-
_previewEnd: number | null;
703-
_previewStart: number | null;
704-
_rangeEnd: number | null;
705-
_rangeStart: number | null;
702+
_previewEnd: i0.WritableSignal<number | null>;
703+
_previewStart: i0.WritableSignal<number | null>;
704+
_rangeEnd: i0.WritableSignal<number | null>;
705+
_rangeStart: i0.WritableSignal<number | null>;
706706
get selected(): DateRange<D> | D | null;
707707
set selected(value: DateRange<D> | D | null);
708708
readonly selectedChange: EventEmitter<D | null>;
709709
startDateAccessibleName: string | null;
710-
_todayDate: number | null;
710+
_todayDate: i0.WritableSignal<number | null>;
711711
_updateActiveDate(event: MatCalendarUserEvent<number>): void;
712712
readonly _userSelection: EventEmitter<MatCalendarUserEvent<D | null>>;
713-
_weekdays: {
713+
_weekdays: i0.WritableSignal<{
714714
long: string;
715715
narrow: string;
716716
id: number;
717-
}[];
718-
_weeks: MatCalendarCell[][];
717+
}[]>;
718+
_weeks: i0.WritableSignal<MatCalendarCell<any>[][]>;
719719
// (undocumented)
720720
static ɵcmp: i0.ɵɵComponentDeclaration<MatMonthView<any>, "mat-month-view", ["matMonthView"], { "activeDate": { "alias": "activeDate"; "required": false; }; "selected": { "alias": "selected"; "required": false; }; "minDate": { "alias": "minDate"; "required": false; }; "maxDate": { "alias": "maxDate"; "required": false; }; "dateFilter": { "alias": "dateFilter"; "required": false; }; "dateClass": { "alias": "dateClass"; "required": false; }; "comparisonStart": { "alias": "comparisonStart"; "required": false; }; "comparisonEnd": { "alias": "comparisonEnd"; "required": false; }; "startDateAccessibleName": { "alias": "startDateAccessibleName"; "required": false; }; "endDateAccessibleName": { "alias": "endDateAccessibleName"; "required": false; }; "activeDrag": { "alias": "activeDrag"; "required": false; }; }, { "selectedChange": "selectedChange"; "_userSelection": "_userSelection"; "dragStarted": "dragStarted"; "dragEnded": "dragEnded"; "activeDateChange": "activeDateChange"; }, never, never, true, never>;
721721
// (undocumented)
@@ -751,10 +751,10 @@ export class MatMultiYearView<D> implements AfterContentInit, OnDestroy {
751751
get selected(): DateRange<D> | D | null;
752752
set selected(value: DateRange<D> | D | null);
753753
readonly selectedChange: EventEmitter<D>;
754-
_selectedYear: number | null;
755-
_todayYear: number;
754+
_selectedYear: i0.WritableSignal<number | null>;
755+
_todayYear: i0.WritableSignal<number>;
756756
_updateActiveDate(event: MatCalendarUserEvent<number>): void;
757-
_years: MatCalendarCell[][];
757+
_years: i0.WritableSignal<MatCalendarCell<any>[][]>;
758758
readonly yearSelected: EventEmitter<D>;
759759
_yearSelected(event: MatCalendarUserEvent<number>): void;
760760
// (undocumented)
@@ -831,7 +831,7 @@ export class MatYearView<D> implements AfterContentInit, OnDestroy {
831831
set maxDate(value: D | null);
832832
get minDate(): D | null;
833833
set minDate(value: D | null);
834-
_months: MatCalendarCell[][];
834+
_months: i0.WritableSignal<MatCalendarCell<any>[][]>;
835835
readonly monthSelected: EventEmitter<D>;
836836
_monthSelected(event: MatCalendarUserEvent<number>): void;
837837
// (undocumented)
@@ -841,10 +841,10 @@ export class MatYearView<D> implements AfterContentInit, OnDestroy {
841841
get selected(): DateRange<D> | D | null;
842842
set selected(value: DateRange<D> | D | null);
843843
readonly selectedChange: EventEmitter<D>;
844-
_selectedMonth: number | null;
845-
_todayMonth: number | null;
844+
_selectedMonth: i0.WritableSignal<number | null>;
845+
_todayMonth: i0.WritableSignal<number | null>;
846846
_updateActiveDate(event: MatCalendarUserEvent<number>): void;
847-
_yearLabel: string;
847+
_yearLabel: i0.WritableSignal<string>;
848848
// (undocumented)
849849
static ɵcmp: i0.ɵɵComponentDeclaration<MatYearView<any>, "mat-year-view", ["matYearView"], { "activeDate": { "alias": "activeDate"; "required": false; }; "selected": { "alias": "selected"; "required": false; }; "minDate": { "alias": "minDate"; "required": false; }; "maxDate": { "alias": "maxDate"; "required": false; }; "dateFilter": { "alias": "dateFilter"; "required": false; }; "dateClass": { "alias": "dateClass"; "required": false; }; }, { "selectedChange": "selectedChange"; "monthSelected": "monthSelected"; "activeDateChange": "activeDateChange"; }, never, never, true, never>;
850850
// (undocumented)

src/material/datepicker/month-view.html

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<table class="mat-calendar-table" role="grid">
22
<thead class="mat-calendar-table-header">
33
<tr>
4-
@for (day of _weekdays; track day.id) {
4+
@for (day of _weekdays(); track day.id) {
55
<th scope="col">
66
<span class="cdk-visually-hidden">{{day.long}}</span>
77
<span aria-hidden="true">{{day.narrow}}</span>
@@ -11,16 +11,16 @@
1111
<tr aria-hidden="true"><th class="mat-calendar-table-header-divider" colspan="7"></th></tr>
1212
</thead>
1313
<tbody mat-calendar-body
14-
[label]="_monthLabel"
15-
[rows]="_weeks"
16-
[todayValue]="_todayDate!"
17-
[startValue]="_rangeStart!"
18-
[endValue]="_rangeEnd!"
19-
[comparisonStart]="_comparisonRangeStart"
20-
[comparisonEnd]="_comparisonRangeEnd"
21-
[previewStart]="_previewStart"
22-
[previewEnd]="_previewEnd"
23-
[isRange]="_isRange"
14+
[label]="_monthLabel()"
15+
[rows]="_weeks()"
16+
[todayValue]="_todayDate()!"
17+
[startValue]="_rangeStart()!"
18+
[endValue]="_rangeEnd()!"
19+
[comparisonStart]="_comparisonRangeStart()"
20+
[comparisonEnd]="_comparisonRangeEnd()"
21+
[previewStart]="_previewStart()"
22+
[previewEnd]="_previewEnd()"
23+
[isRange]="_isRange()"
2424
[labelMinRequiredCells]="3"
2525
[activeCell]="_dateAdapter.getDate(activeDate) - 1"
2626
[startDateAccessibleName]="startDateAccessibleName"

src/material/datepicker/month-view.ts

Lines changed: 46 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
SimpleChanges,
3535
OnChanges,
3636
inject,
37+
signal,
3738
} from '@angular/core';
3839
import {DateAdapter, MAT_DATE_FORMATS, MatDateFormats} from '../core';
3940
import {Directionality} from '@angular/cdk/bidi';
@@ -183,40 +184,40 @@ export class MatMonthView<D> implements AfterContentInit, OnChanges, OnDestroy {
183184
@ViewChild(MatCalendarBody) _matCalendarBody: MatCalendarBody;
184185

185186
/** The label for this month (e.g. "January 2017"). */
186-
_monthLabel: string;
187+
_monthLabel = signal('');
187188

188189
/** Grid of calendar cells representing the dates of the month. */
189-
_weeks: MatCalendarCell[][];
190+
_weeks = signal<MatCalendarCell[][]>([]);
190191

191192
/** The number of blank cells in the first row before the 1st of the month. */
192-
_firstWeekOffset: number;
193+
_firstWeekOffset = signal(0);
193194

194195
/** Start value of the currently-shown date range. */
195-
_rangeStart: number | null;
196+
_rangeStart = signal<number | null>(null);
196197

197198
/** End value of the currently-shown date range. */
198-
_rangeEnd: number | null;
199+
_rangeEnd = signal<number | null>(null);
199200

200201
/** Start value of the currently-shown comparison date range. */
201-
_comparisonRangeStart: number | null;
202+
_comparisonRangeStart = signal<number | null>(null);
202203

203204
/** End value of the currently-shown comparison date range. */
204-
_comparisonRangeEnd: number | null;
205+
_comparisonRangeEnd = signal<number | null>(null);
205206

206207
/** Start of the preview range. */
207-
_previewStart: number | null;
208+
_previewStart = signal<number | null>(null);
208209

209210
/** End of the preview range. */
210-
_previewEnd: number | null;
211+
_previewEnd = signal<number | null>(null);
211212

212213
/** Whether the user is currently selecting a range of dates. */
213-
_isRange: boolean;
214+
_isRange = signal(false);
214215

215216
/** The date of the month that today falls on. Null if today is in another month. */
216-
_todayDate: number | null;
217+
_todayDate = signal<number | null>(null);
217218

218219
/** The names of the weekdays. */
219-
_weekdays: {long: string; narrow: string; id: number}[];
220+
_weekdays = signal<{long: string; narrow: string; id: number}[]>([]);
220221

221222
constructor(...args: unknown[]);
222223

@@ -359,7 +360,7 @@ export class MatMonthView<D> implements AfterContentInit, OnChanges, OnDestroy {
359360
return;
360361
case ESCAPE:
361362
// Abort the current range selection if the user presses escape mid-selection.
362-
if (this._previewEnd != null && !hasModifierKey(event)) {
363+
if (this._previewEnd() != null && !hasModifierKey(event)) {
363364
this._clearPreview();
364365
// If a drag is in progress, cancel the drag without changing the
365366
// current selection.
@@ -402,23 +403,26 @@ export class MatMonthView<D> implements AfterContentInit, OnChanges, OnDestroy {
402403
/** Initializes this month view. */
403404
_init() {
404405
this._setRanges(this.selected);
405-
this._todayDate = this._getCellCompareValue(this._dateAdapter.today());
406-
this._monthLabel = this._dateFormats.display.monthLabel
407-
? this._dateAdapter.format(this.activeDate, this._dateFormats.display.monthLabel)
408-
: this._dateAdapter
409-
.getMonthNames('short')
410-
[this._dateAdapter.getMonth(this.activeDate)].toLocaleUpperCase();
406+
this._todayDate.set(this._getCellCompareValue(this._dateAdapter.today()));
407+
this._monthLabel.set(
408+
this._dateFormats.display.monthLabel
409+
? this._dateAdapter.format(this.activeDate, this._dateFormats.display.monthLabel)
410+
: this._dateAdapter
411+
.getMonthNames('short')
412+
[this._dateAdapter.getMonth(this.activeDate)].toLocaleUpperCase(),
413+
);
411414

412415
let firstOfMonth = this._dateAdapter.createDate(
413416
this._dateAdapter.getYear(this.activeDate),
414417
this._dateAdapter.getMonth(this.activeDate),
415418
1,
416419
);
417-
this._firstWeekOffset =
420+
this._firstWeekOffset.set(
418421
(DAYS_PER_WEEK +
419422
this._dateAdapter.getDayOfWeek(firstOfMonth) -
420423
this._dateAdapter.getFirstDayOfWeek()) %
421-
DAYS_PER_WEEK;
424+
DAYS_PER_WEEK,
425+
);
422426

423427
this._initWeekdays();
424428
this._createWeekCells();
@@ -446,8 +450,8 @@ export class MatMonthView<D> implements AfterContentInit, OnChanges, OnDestroy {
446450
this.selected as DateRange<D>,
447451
event,
448452
);
449-
this._previewStart = this._getCellCompareValue(previewRange.start);
450-
this._previewEnd = this._getCellCompareValue(previewRange.end);
453+
this._previewStart.set(this._getCellCompareValue(previewRange.start));
454+
this._previewEnd.set(this._getCellCompareValue(previewRange.end));
451455

452456
if (this.activeDrag && value) {
453457
const dragRange = this._rangeStrategy.createDrag?.(
@@ -458,8 +462,8 @@ export class MatMonthView<D> implements AfterContentInit, OnChanges, OnDestroy {
458462
);
459463

460464
if (dragRange) {
461-
this._previewStart = this._getCellCompareValue(dragRange.start);
462-
this._previewEnd = this._getCellCompareValue(dragRange.end);
465+
this._previewStart.set(this._getCellCompareValue(dragRange.start));
466+
this._previewEnd.set(this._getCellCompareValue(dragRange.end));
463467
}
464468
}
465469
}
@@ -506,20 +510,20 @@ export class MatMonthView<D> implements AfterContentInit, OnChanges, OnDestroy {
506510
const longWeekdays = this._dateAdapter.getDayOfWeekNames('long');
507511

508512
// Rotate the labels for days of the week based on the configured first day of the week.
509-
let weekdays = longWeekdays.map((long, i) => {
513+
const weekdays = longWeekdays.map((long, i) => {
510514
return {long, narrow: narrowWeekdays[i], id: uniqueIdCounter++};
511515
});
512-
this._weekdays = weekdays.slice(firstDayOfWeek).concat(weekdays.slice(0, firstDayOfWeek));
516+
this._weekdays.set(weekdays.slice(firstDayOfWeek).concat(weekdays.slice(0, firstDayOfWeek)));
513517
}
514518

515519
/** Creates MatCalendarCells for the dates in this month. */
516520
private _createWeekCells() {
517521
const daysInMonth = this._dateAdapter.getNumDaysInMonth(this.activeDate);
518522
const dateNames = this._dateAdapter.getDateNames();
519-
this._weeks = [[]];
520-
for (let i = 0, cell = this._firstWeekOffset; i < daysInMonth; i++, cell++) {
523+
const weeks: MatCalendarCell[][] = [[]];
524+
for (let i = 0, cell = this._firstWeekOffset(); i < daysInMonth; i++, cell++) {
521525
if (cell == DAYS_PER_WEEK) {
522-
this._weeks.push([]);
526+
weeks.push([]);
523527
cell = 0;
524528
}
525529
const date = this._dateAdapter.createDate(
@@ -531,7 +535,7 @@ export class MatMonthView<D> implements AfterContentInit, OnChanges, OnDestroy {
531535
const ariaLabel = this._dateAdapter.format(date, this._dateFormats.display.dateA11yLabel);
532536
const cellClasses = this.dateClass ? this.dateClass(date, 'month') : undefined;
533537

534-
this._weeks[this._weeks.length - 1].push(
538+
weeks[weeks.length - 1].push(
535539
new MatCalendarCell<D>(
536540
i + 1,
537541
dateNames[i],
@@ -543,6 +547,7 @@ export class MatMonthView<D> implements AfterContentInit, OnChanges, OnDestroy {
543547
),
544548
);
545549
}
550+
this._weeks.set(weeks);
546551
}
547552

548553
/** Date filter for the month */
@@ -597,16 +602,17 @@ export class MatMonthView<D> implements AfterContentInit, OnChanges, OnDestroy {
597602
/** Sets the current range based on a model value. */
598603
private _setRanges(selectedValue: DateRange<D> | D | null) {
599604
if (selectedValue instanceof DateRange) {
600-
this._rangeStart = this._getCellCompareValue(selectedValue.start);
601-
this._rangeEnd = this._getCellCompareValue(selectedValue.end);
602-
this._isRange = true;
605+
this._rangeStart.set(this._getCellCompareValue(selectedValue.start));
606+
this._rangeEnd.set(this._getCellCompareValue(selectedValue.end));
607+
this._isRange.set(true);
603608
} else {
604-
this._rangeStart = this._rangeEnd = this._getCellCompareValue(selectedValue);
605-
this._isRange = false;
609+
this._rangeStart.set(this._getCellCompareValue(selectedValue));
610+
this._rangeEnd.set(this._rangeStart());
611+
this._isRange.set(false);
606612
}
607613

608-
this._comparisonRangeStart = this._getCellCompareValue(this.comparisonStart);
609-
this._comparisonRangeEnd = this._getCellCompareValue(this.comparisonEnd);
614+
this._comparisonRangeStart.set(this._getCellCompareValue(this.comparisonStart));
615+
this._comparisonRangeEnd.set(this._getCellCompareValue(this.comparisonEnd));
610616
}
611617

612618
/** Gets whether a date can be selected in the month view. */
@@ -616,6 +622,7 @@ export class MatMonthView<D> implements AfterContentInit, OnChanges, OnDestroy {
616622

617623
/** Clears out preview state. */
618624
private _clearPreview() {
619-
this._previewStart = this._previewEnd = null;
625+
this._previewStart.set(null);
626+
this._previewEnd.set(null);
620627
}
621628
}

src/material/datepicker/multi-year-view.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
<tr><th class="mat-calendar-table-header-divider" colspan="4"></th></tr>
44
</thead>
55
<tbody mat-calendar-body
6-
[rows]="_years"
7-
[todayValue]="_todayYear"
8-
[startValue]="_selectedYear!"
9-
[endValue]="_selectedYear!"
6+
[rows]="_years()"
7+
[todayValue]="_todayYear()"
8+
[startValue]="_selectedYear()!"
9+
[endValue]="_selectedYear()!"
1010
[numCols]="4"
1111
[cellAspectRatio]="4 / 7"
1212
[activeCell]="_getActiveCell()"

0 commit comments

Comments
 (0)