Skip to content

Commit dff0a98

Browse files
committed
Merge branch 'rkaraivanov/toolbar-tweaks' of https://github.com/IgniteUI/igniteui-angular into rkaraivanov/toolbar-tweaks
2 parents 898b855 + 4af2951 commit dff0a98

24 files changed

+295
-86
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
All notable changes for each version of this project will be documented in this file.
44
## 11.0.0
55

6+
### New Features
7+
- `IgxCalendar`
8+
- Is now fully accessible to screen readers.
9+
610
### General
711
- `IgxGrid`, `IgxTreeGrid`, `IgxHierarchicalGrid`
812
- Added a new directive for re-templating the Excel style filtering header icon - `IgxExcelStyleHeaderIconDirective`.

projects/igniteui-angular/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@
8484
"web-animations-js": "^2.3.2"
8585
},
8686
"igxDevDependencies": {
87-
"@igniteui/angular-schematics": "~11.0.700-alpha.0"
87+
"@igniteui/angular-schematics": "~11.0.700-rc.0"
8888
},
8989
"ng-update": {
9090
"migrations": "./migrations/migration-collection.json"

projects/igniteui-angular/src/lib/calendar/calendar-base.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import { DateRangeDescriptor } from '../core/dates';
55
import { Subject } from 'rxjs';
66
import { isDate, mkenum } from '../core/utils';
77
import { CalendarView } from './month-picker-base';
8+
import { CurrentResourceStrings } from '../core/i18n/resources';
9+
import { ICalendarResourceStrings } from '../core/i18n/calendar-resources';
10+
811

912
/**
1013
* Sets the selection type - single, multi or range.
@@ -32,6 +35,25 @@ export interface IViewDateChangeEventArgs {
3235
selector: '[igxCalendarBase]',
3336
})
3437
export class IgxCalendarBaseDirective implements ControlValueAccessor {
38+
/** @hidden @internal */
39+
private _resourceStrings = CurrentResourceStrings.CalendarResStrings;
40+
41+
/**
42+
* An accessor that sets the resource strings.
43+
* By default it uses EN resources.
44+
*/
45+
@Input()
46+
set resourceStrings(value: ICalendarResourceStrings) {
47+
this._resourceStrings = Object.assign({}, this._resourceStrings, value);
48+
}
49+
50+
/**
51+
* An accessor that returns the resource strings.
52+
*/
53+
get resourceStrings(): ICalendarResourceStrings {
54+
return this._resourceStrings;
55+
}
56+
3557
/**
3658
* Gets the start day of the week.
3759
* Can return a numeric or an enum representation of the week day.

projects/igniteui-angular/src/lib/calendar/calendar-helper-utils.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,9 @@ export class HelperTestFunctions {
8383
expect(monthPickers.length).toEqual(viewDates.length);
8484
for (let index = 0; index < viewDates.length; index++) {
8585
const dateParts = viewDates[index].toString().split(' '); // weekday month day year
86-
expect(monthPickers[index].children[0].innerHTML.trim()).toEqual(dateParts[1]);
87-
expect(monthPickers[index].children[1].innerHTML.trim()).toEqual(dateParts[3]);
86+
const monthPickerDates = monthPickers[index].querySelectorAll('.igx-calendar-picker__date');
87+
expect(monthPickerDates[0].innerHTML.trim()).toEqual(dateParts[1]);
88+
expect(monthPickerDates[1].innerHTML.trim()).toEqual(dateParts[3]);
8889
}
8990
}
9091

@@ -100,7 +101,7 @@ export class HelperTestFunctions {
100101

101102
public static getCalendarSubHeader(fixture): HTMLElement {
102103
const element = fixture.nativeElement ? fixture.nativeElement : fixture;
103-
return element.querySelector('div.igx-calendar-picker');
104+
return element.querySelector('.igx-calendar-picker');
104105
}
105106

106107
public static getMonthView(fixture, monthsViewNumber: number) {

projects/igniteui-angular/src/lib/calendar/calendar.component.html

Lines changed: 88 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,49 +4,100 @@
44
</ng-template>
55

66
<ng-template let-result #defaultMonth let-obj>
7-
<span tabindex="0" #monthsBtn (keydown)="onActiveViewYearKB(getViewDate(obj.index), $event, obj.index)" (click)="onActiveViewYear(getViewDate(obj.index), obj.index, $event)"
8-
class="igx-calendar-picker__date">
9-
{{ formattedMonth(getViewDate(obj.index)) }}
10-
</span>
11-
<span tabindex="0" #yearsBtn (keydown)="onActiveViewDecadeKB($event, getViewDate(obj.index), obj.index)" (click)="onActiveViewDecade(getViewDate(obj.index), obj.index)"
12-
class="igx-calendar-picker__date">
13-
{{ formattedYear(getViewDate(obj.index)) }}
14-
</span>
7+
<span *ngIf="monthsViewNumber < 2 || obj.index < 1" class="igx-calendar__aria-off-screen" aria-live="polite">
8+
{{ monthsViewNumber > 1 ? (resourceStrings.igx_calendar_first_picker_of.replace('{0}', monthsViewNumber.toString()) + ' ' + (getViewDate(obj.index) | date: 'LLLL yyyy')) : resourceStrings.igx_calendar_selected_month_is + (getViewDate(obj.index) | date: 'LLLL yyyy')}}
9+
</span>
10+
<span
11+
tabindex="0"
12+
role="button"
13+
[attr.aria-label]="(getViewDate(obj.index) | date: 'LLLL') + ' ' + resourceStrings.igx_calendar_select_month"
14+
#monthsBtn
15+
(keydown)="onActiveViewYearKB(getViewDate(obj.index), $event, obj.index)"
16+
(click)="onActiveViewYear(getViewDate(obj.index), obj.index, $event)"
17+
class="igx-calendar-picker__date">
18+
{{ formattedMonth(getViewDate(obj.index)) }}
19+
</span>
20+
21+
<span
22+
tabindex="0"
23+
role="button"
24+
[attr.aria-label]="(getViewDate(obj.index) | date: 'yyyy') + ' ' + resourceStrings.igx_calendar_select_year"
25+
#yearsBtn
26+
(keydown)="onActiveViewDecadeKB($event, getViewDate(obj.index), obj.index)"
27+
(click)="onActiveViewDecade(getViewDate(obj.index), obj.index)"
28+
class="igx-calendar-picker__date">
29+
{{ formattedYear(getViewDate(obj.index)) }}
30+
</span>
1531
</ng-template>
1632

17-
<div *ngIf="selection === 'single' && hasHeader" class="igx-calendar__header">
18-
<h5 class="igx-calendar__header-year">{{ formattedYear(headerDate) }}</h5>
19-
<h2 class="igx-calendar__header-date">
33+
<header
34+
aria-labelledby="igx-aria-calendar-title-month igx-aria-calendar-title-year"
35+
class="igx-calendar__header"
36+
*ngIf="selection === 'single' && hasHeader">
37+
38+
<h5 id="igx-aria-calendar-title-year" class="igx-calendar__header-year">
39+
{{ formattedYear(headerDate) }}
40+
</h5>
41+
42+
<h2 id="igx-aria-calendar-title-month" class="igx-calendar__header-date">
2043
<ng-container *ngTemplateOutlet="headerTemplate ? headerTemplate : defaultHeader; context: headerContext">
2144
</ng-container>
2245
</h2>
23-
</div>
46+
</header>
2447

25-
<div *ngIf="isDefaultView" class="igx-calendar__body" [@animateView]="activeView" (@animateView.done)="viewRendered($event)" (swiperight)="previousMonth()"
48+
<div *ngIf="isDefaultView" class="igx-calendar__body" [@animateView]="activeView" (@animateView.done)="viewRendered($event)" (swiperight)="previousMonth()"
2649
(swipeleft)="nextMonth()" (pointerdown)="suppressBlur()">
27-
<div class="igx-calendar-picker">
28-
<div tabindex="0" class="igx-calendar-picker__prev" #prevMonthBtn
29-
igxCalendarScrollMonth [startScroll]="startPrevMonthScroll" [stopScroll]="stopMonthScroll" [ngStyle]="{
30-
'min-width.%': 100/(monthsViewNumber*7)
31-
}">
32-
<igx-icon fontSet="material">keyboard_arrow_left</igx-icon>
50+
<section class="igx-calendar-picker">
51+
<span tabindex="0" class="igx-calendar__aria-off-screen">
52+
<ng-container *ngIf="selection === 'multi'">
53+
{{ monthsViewNumber && monthsViewNumber > 1 ? resourceStrings.igx_calendar_multi_selection.replace('{0}', monthsViewNumber.toString()) : resourceStrings.igx_calendar_singular_multi_selection}}
54+
</ng-container>
55+
<ng-container *ngIf="selection === 'range'">
56+
{{ monthsViewNumber && monthsViewNumber > 1 ? resourceStrings.igx_calendar_range_selection.replace('{0}', monthsViewNumber.toString()) : resourceStrings.igx_calendar_singular_range_selection}}
57+
</ng-container>
58+
<ng-container *ngIf="selection === 'single'">
59+
{{ monthsViewNumber && monthsViewNumber > 1 ? resourceStrings.igx_calendar_single_selection.replace('{0}', monthsViewNumber.toString()) : resourceStrings.igx_calendar_singular_single_selection}}
60+
</ng-container>
61+
</span>
62+
<div
63+
tabindex="0"
64+
class="igx-calendar-picker__prev"
65+
role="button"
66+
[attr.aria-label]="resourceStrings.igx_calendar_previous_month + ', ' + (getPrevMonth(viewDate) | date: 'LLLL')"
67+
data-action="prev"
68+
#prevMonthBtn
69+
igxCalendarScrollMonth
70+
[startScroll]="startPrevMonthScroll"
71+
[stopScroll]="stopMonthScroll"
72+
[ngStyle]="{ 'min-width.%': 100/(monthsViewNumber*7)}">
73+
<igx-icon fontSet="material" aria-hidden="true">keyboard_arrow_left</igx-icon>
3374
</div>
34-
<div class="igx-calendar-picker__dates" *ngFor="let view of monthsViewNumber | IgxMonthViewSlots; index as i;" [style.width.%]="100/monthsViewNumber" [attr.data-month]="i | IgxGetViewDate:viewDate:false">
75+
<div class="igx-calendar-picker__dates"
76+
*ngFor="let view of monthsViewNumber | IgxMonthViewSlots; index as i;"
77+
[style.width.%]="100/monthsViewNumber"
78+
[attr.data-month]="i | IgxGetViewDate:viewDate:false">
3579
<ng-container *ngTemplateOutlet="subheaderTemplate ? subheaderTemplate : defaultMonth; context: getContext(i)">
3680
</ng-container>
3781
</div>
38-
<div tabindex="0" class="igx-calendar-picker__next" #nextMonthBtn
39-
igxCalendarScrollMonth [startScroll]="startNextMonthScroll" [stopScroll]="stopMonthScroll" [ngStyle]="{
40-
'min-width.%': 100/(monthsViewNumber*7)
41-
}">
42-
<igx-icon fontSet="material">keyboard_arrow_right</igx-icon>
82+
<div
83+
tabindex="0"
84+
class="igx-calendar-picker__next"
85+
role="button"
86+
[attr.aria-label]="resourceStrings.igx_calendar_next_month + ', ' + (getNextMonth(viewDate, monthsViewNumber) | date: 'LLLL')"
87+
data-action="next"
88+
#nextMonthBtn
89+
igxCalendarScrollMonth
90+
[startScroll]="startNextMonthScroll"
91+
[stopScroll]="stopMonthScroll"
92+
[ngStyle]="{'min-width.%': 100/(monthsViewNumber*7)}">
93+
<igx-icon fontSet="material" aria-hidden="true">keyboard_arrow_right</igx-icon>
4394
</div>
44-
</div>
95+
</section>
4596

46-
<div style="display: flex"
97+
<section style="display: flex"
4798
[@animateChange]="animationAction"
4899
(@animateChange.done)="animationDone($event)">
49-
<igx-days-view *ngFor="let view of monthsViewNumber | IgxMonthViewSlots; index as i;" [changeDaysView]="true" #days
100+
<igx-days-view role="grid" *ngFor="let view of monthsViewNumber | IgxMonthViewSlots; index as i;" [changeDaysView]="true" #days
50101
[selection]="selection"
51102
[locale]="locale"
52103
[value]="value"
@@ -63,18 +114,24 @@ <h2 class="igx-calendar__header-date">
63114
(onDateSelection)="childClicked($event)"
64115
(monthsViewBlur)="resetActiveDate()">
65116
</igx-days-view>
66-
</div>
117+
</section>
67118
</div>
68119

69-
<igx-months-view *ngIf="isYearView" [@animateView]="activeView" #months (@animateView.done)="viewRendered($event)"
120+
<igx-months-view *ngIf="isYearView"
121+
[@animateView]="activeView"
122+
#months
123+
(@animateView.done)="viewRendered($event)"
70124
[date]="viewDate"
71125
[locale]="locale"
72126
[formatView]="formatViews.month"
73127
[monthFormat]="formatOptions.month"
74128
(onSelection)="changeMonth($event)">
75129
</igx-months-view>
76130

77-
<igx-years-view *ngIf="isDecadeView" [@animateView]="activeView" #decade (@animateView.done)="viewRendered($event)"
131+
<igx-years-view *ngIf="isDecadeView"
132+
[@animateView]="activeView"
133+
#decade
134+
(@animateView.done)="viewRendered($event)"
78135
[date]="viewDate"
79136
[locale]="locale"
80137
[formatView]="formatViews.year"

projects/igniteui-angular/src/lib/calendar/calendar.component.ts

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ let NEXT_ID = 0;
8787
templateUrl: 'calendar.component.html'
8888
})
8989
export class IgxCalendarComponent extends IgxMonthPickerBaseDirective implements AfterViewInit, OnDestroy {
90-
9190
/**
9291
* Sets/gets the `id` of the calendar.
9392
*
@@ -191,24 +190,6 @@ export class IgxCalendarComponent extends IgxMonthPickerBaseDirective implements
191190
*/
192191
public callback: (next) => void;
193192

194-
/**
195-
* The default aria role attribute for the component.
196-
*
197-
* @hidden
198-
* @internal
199-
*/
200-
@HostBinding('attr.role')
201-
public role = 'grid';
202-
203-
/**
204-
* The default aria lebelled by attribute for the component.
205-
*
206-
* @hidden
207-
* @internal
208-
*/
209-
@HostBinding('attr.aria-labelledby')
210-
public ariaLabelledBy = 'calendar';
211-
212193
/**
213194
* The default css class applied to the component.
214195
*
@@ -997,4 +978,20 @@ export class IgxCalendarComponent extends IgxMonthPickerBaseDirective implements
997978
return this.monthViews.toArray()[index];
998979
}
999980
}
981+
982+
/**
983+
* @hidden
984+
* @internal
985+
*/
986+
public getPrevMonth(date): Date {
987+
return this.calendarModel.getPrevMonth(date);
988+
}
989+
990+
/**
991+
* @hidden
992+
* @internal
993+
*/
994+
public getNextMonth(date, viewIndex): Date {
995+
return this.calendarModel.getDateByView(date, 'Month', viewIndex);
996+
}
1000997
}

projects/igniteui-angular/src/lib/calendar/calendar.directives.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ export class IgxCalendarYearDirective {
4848
return this.isCurrentYear;
4949
}
5050

51+
@HostBinding('attr.role')
52+
public get role(): string {
53+
return this.isCurrentYear ? 'spinbutton' : null;
54+
}
55+
56+
@HostBinding('attr.aria-valuenow')
57+
public get valuenow(): number {
58+
return this.isCurrentYear ? this.date.getFullYear() : null;
59+
}
60+
5161
@HostBinding('attr.tabindex')
5262
public get tabIndex(): number {
5363
return this.isCurrentYear ? 0 : -1;

projects/igniteui-angular/src/lib/calendar/calendar.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,10 @@ export class Calendar {
338338
return this.timedelta(date, interval, -activeViewIdx);
339339
}
340340

341+
public getDateByView(date: Date, interval: string, activeViewIdx: number) {
342+
return this.timedelta(date, interval, activeViewIdx);
343+
}
344+
341345
public getNextMonth(date: Date) {
342346
return this.timedelta(date, TimeDeltaInterval.Month, 1);
343347
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
<span class="igx-calendar__date-content">
1+
<span aria-hidden="true" class="igx-calendar__date-content">
22
<ng-content></ng-content>
33
</span>

projects/igniteui-angular/src/lib/calendar/days-view/day-item.component.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ export class IgxDayItemComponent {
9494
public get isToday(): boolean {
9595
const today = new Date(Date.now());
9696
const date = this.date.date;
97+
98+
if (date.getDate() === today.getDate()) {
99+
this.nativeElement.setAttribute('aria-current', 'date');
100+
}
101+
97102
return (date.getFullYear() === today.getFullYear() &&
98103
date.getMonth() === today.getMonth() &&
99104
date.getDate() === today.getDate()

0 commit comments

Comments
 (0)