Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(datepicker): add keyboard support to calendar #3655

Merged
merged 11 commits into from
Mar 24, 2017
3 changes: 2 additions & 1 deletion src/lib/datepicker/_datepicker-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@
}
}

:not(.mat-calendar-table-disabled):hover {
:not(.mat-calendar-table-disabled):hover,
.cdk-keyboard-focused .mat-calendar-table-active {
& > .mat-calendar-table-cell-content:not(.mat-calendar-table-selected) {
background-color: mat-color($background, hover);
}
Expand Down
7 changes: 4 additions & 3 deletions src/lib/datepicker/calendar-table.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@
</tr>

<!-- Create the first row separately so we can include a special spacer cell. -->
<tr *ngFor="let row of rows; let i = index">
<td *ngIf="i === 0 && _firstRowOffset"
<tr *ngFor="let row of rows; let rowIndex = index">
<td *ngIf="rowIndex === 0 && _firstRowOffset"
class="mat-calendar-table-label"
[attr.colspan]="_firstRowOffset">
{{_firstRowOffset >= labelMinRequiredCells ? label : ''}}
</td>
<td *ngFor="let item of row"
<td *ngFor="let item of row; let colIndex = index"
class="mat-calendar-table-cell"
[class.mat-calendar-table-disabled]="!item.enabled"
[class.mat-calendar-table-active]="_isActiveCell(rowIndex, colIndex)"
(click)="_cellClicked(item)">
<div class="mat-calendar-table-cell-content"
[class.mat-calendar-table-selected]="selectedValue === item.value"
Expand Down
6 changes: 6 additions & 0 deletions src/lib/datepicker/calendar-table.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ describe('MdCalendarTable', () => {
expect(todayElement.classList)
.toContain('mat-calendar-table-selected', 'today should be selected');
});

it('should mark active date', () => {
expect((cellEls[10] as HTMLElement).innerText.trim()).toBe('11');
expect(cellEls[10].classList).toContain('mat-calendar-table-active');
});
});

describe('calendar table with disabled cells', () => {
Expand Down Expand Up @@ -129,6 +134,7 @@ describe('MdCalendarTable', () => {
[selectedValue]="selectedValue"
[labelMinRequiredCells]="labelMinRequiredCells"
[numCols]="numCols"
[activeCell]="10"
(selectedValueChange)="onSelect($event)">
</md-calendar-table>`,
})
Expand Down
18 changes: 16 additions & 2 deletions src/lib/datepicker/calendar-table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,33 @@ export class MdCalendarTable {
/** Whether to allow selection of disabled cells. */
@Input() allowDisabledSelection = false;

/** The cell number of the active cell in the table. */
@Input() activeCell = 0;

/** Emits when a new value is selected. */
@Output() selectedValueChange = new EventEmitter<number>();

_cellClicked(cell: MdCalendarCell) {
_cellClicked(cell: MdCalendarCell): void {
if (!this.allowDisabledSelection && !cell.enabled) {
return;
}
this.selectedValueChange.emit(cell.value);
}

/** The number of blank cells to put at the beginning for the first row. */
get _firstRowOffset() {
get _firstRowOffset(): number {
return this.rows && this.rows.length && this.rows[0].length ?
this.numCols - this.rows[0].length : 0;
}

_isActiveCell(rowIndex: number, colIndex: number): boolean {
let cellNumber = rowIndex * this.numCols + colIndex;

// Account for the fact that the first row may not have as many cells.
if (rowIndex) {
cellNumber -= this._firstRowOffset;
}

return cellNumber == this.activeCell;
}
}
7 changes: 4 additions & 3 deletions src/lib/datepicker/calendar.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,19 @@
</table>
</div>

<div class="mat-calendar-body">
<div class="mat-calendar-body" tabindex="0" (keydown)="_handleCalendarBodyKeydown($event)"
cdkMonitorSubtreeFocus>
<md-month-view
*ngIf="_monthView"
[date]="_currentPeriod"
[activeDate]="_activeDate"
[selected]="selected"
[dateFilter]="_dateFilterForViews"
(selectedChange)="_dateSelected($event)">
</md-month-view>

<md-year-view
*ngIf="!_monthView"
[date]="_currentPeriod"
[activeDate]="_activeDate"
[selected]="selected"
[dateFilter]="_dateFilterForViews"
(selectedChange)="_monthSelected($event)">
Expand Down
Loading