Skip to content

Commit 113b0ba

Browse files
fix(date-picker): KB nav and calendar focus handling (#14937)
* test(date-picker): update KB nav and interaction tests to check focus state * fix(date-picker): move focus to calendar wrapper on open * fix(calendar): select on click instead of mousedown * fix(calendar): drop stopPropagation calls on kb nav events * fix(date-range-picker): move focus to calendar wrapper on open * fix(quick-filter): chip edit with date/time pickers * fix(date-pickers): return focus to input on dropdown escape --------- Co-authored-by: Stamen Stoychev <[email protected]>
1 parent 7b6c74f commit 113b0ba

15 files changed

+261
-136
lines changed

projects/igniteui-angular/src/lib/calendar/calendar-multi-view.component.spec.ts

Lines changed: 47 additions & 33 deletions
Large diffs are not rendered by default.

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

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,7 @@ describe("IgxCalendar - ", () => {
742742
// Select 14th
743743
const dateElement = weekDays[3].nativeElement.firstChild;
744744

745-
dateElement.dispatchEvent(new Event("mousedown"));
745+
dateElement.click();
746746
fixture.detectChanges();
747747

748748
expect(calendar.selected.emit).toHaveBeenCalled();
@@ -770,9 +770,7 @@ describe("IgxCalendar - ", () => {
770770
);
771771
const target = parentDates[parentDates.length - 1];
772772

773-
target.nativeElement.firstChild.dispatchEvent(
774-
new Event("mousedown"),
775-
);
773+
target.nativeElement.firstChild.click();
776774
fixture.detectChanges();
777775

778776
expect(
@@ -800,9 +798,7 @@ describe("IgxCalendar - ", () => {
800798
By.css(HelperTestFunctions.INACTIVE_DAYS_CSSCLASS),
801799
)[0];
802800

803-
target.nativeElement.firstChild.dispatchEvent(
804-
new Event("mousedown"),
805-
);
801+
target.nativeElement.firstChild.click();
806802
fixture.detectChanges();
807803

808804
expect(
@@ -882,7 +878,7 @@ describe("IgxCalendar - ", () => {
882878
).toEqual(0);
883879

884880
for (const day of weekDays) {
885-
day.nativeElement.firstChild.dispatchEvent(new Event('mousedown'));
881+
day.nativeElement.firstChild.click();
886882
fixture.detectChanges();
887883
}
888884

@@ -895,7 +891,7 @@ describe("IgxCalendar - ", () => {
895891
});
896892

897893
// Deselect last day
898-
weekDays.at(-1).nativeElement.firstChild.dispatchEvent(new Event('mousedown'));
894+
weekDays.at(-1).nativeElement.firstChild.click();
899895
fixture.detectChanges();
900896

901897
expect((calendar.value as Date[]).length).toEqual(6);
@@ -976,7 +972,7 @@ describe("IgxCalendar - ", () => {
976972
const firstDay = new Date(2017, 5, 11);
977973

978974
// Start range selection...
979-
weekDays[0].nativeElement.firstChild.dispatchEvent(new Event('mousedown'));
975+
weekDays[0].nativeElement.firstChild.click();
980976
fixture.detectChanges();
981977

982978
expect(
@@ -991,7 +987,7 @@ describe("IgxCalendar - ", () => {
991987
HelperTestFunctions.verifyDateSelected(weekDays[0]);
992988

993989
// ...and cancel it
994-
weekDays[0].nativeElement.firstChild.dispatchEvent(new Event('mousedown'));
990+
weekDays[0].nativeElement.firstChild.click();
995991
fixture.detectChanges();
996992

997993
expect(
@@ -1001,11 +997,11 @@ describe("IgxCalendar - ", () => {
1001997
HelperTestFunctions.verifyDateNotSelected(weekDays[0]);
1002998

1003999
// Start range selection...
1004-
weekDays.at(0).nativeElement.firstChild.dispatchEvent(new Event('mousedown'));
1000+
weekDays.at(0).nativeElement.firstChild.click();
10051001
fixture.detectChanges();
10061002

10071003
// ...and complete it
1008-
weekDays.at(-1).nativeElement.firstChild.dispatchEvent(new Event('mousedown'));
1004+
weekDays.at(-1).nativeElement.firstChild.click();
10091005
fixture.detectChanges();
10101006

10111007

@@ -1454,15 +1450,15 @@ describe("IgxCalendar - ", () => {
14541450
(d) =>
14551451
getDate(d).getTime() === new Date(2017, 5, 5).getTime(),
14561452
)[0];
1457-
UIInteractions.simulateMouseEvent('mousedown', fromDate.nativeElement.firstChild);
1453+
UIInteractions.simulateClickAndSelectEvent(fromDate.nativeElement.firstChild);
14581454
fixture.detectChanges();
14591455

14601456
const toDate = calendar.daysView.dates.filter(
14611457
(d) =>
14621458
getDate(d).getTime() ===
14631459
new Date(2017, 5, 20).getTime(),
14641460
)[0];
1465-
UIInteractions.simulateMouseEvent('mousedown', toDate.nativeElement.firstChild);
1461+
UIInteractions.simulateClickAndSelectEvent(toDate.nativeElement.firstChild);
14661462
fixture.detectChanges();
14671463

14681464
// Check selection
@@ -2147,8 +2143,8 @@ describe("IgxCalendar - ", () => {
21472143
let calendarValue: Date[];
21482144

21492145
// range selection from June 13th to June 15th
2150-
UIInteractions.simulateMouseDownEvent(june13th.nativeElement.firstChild);
2151-
UIInteractions.simulateMouseDownEvent(june15th.nativeElement.firstChild);
2146+
UIInteractions.simulateClickAndSelectEvent(june13th.nativeElement.firstChild);
2147+
UIInteractions.simulateClickAndSelectEvent(june15th.nativeElement.firstChild);
21522148
fixture.detectChanges();
21532149

21542150
calendarValue = calendar.value as Date[];
@@ -2161,7 +2157,7 @@ describe("IgxCalendar - ", () => {
21612157
).toMatch(new Date(2017, 5, 15).toDateString());
21622158

21632159
// extend the range to June 17th (June 13th - June 17th)
2164-
UIInteractions.simulateMouseDownEvent(june17th.nativeElement.firstChild, true);
2160+
UIInteractions.simulateClickAndSelectEvent(june17th.nativeElement.firstChild, true);
21652161
fixture.detectChanges();
21662162

21672163
calendarValue = calendar.value as Date[];
@@ -2171,7 +2167,7 @@ describe("IgxCalendar - ", () => {
21712167
).toMatch(new Date(2017, 5, 17).toDateString());
21722168

21732169
// extend the range to June 11th (June 11th - June 17th)
2174-
UIInteractions.simulateMouseDownEvent(june11th.nativeElement.firstChild, true);
2170+
UIInteractions.simulateClickAndSelectEvent(june11th.nativeElement.firstChild, true);
21752171
fixture.detectChanges();
21762172

21772173
calendarValue = calendar.value as Date[];
@@ -2196,8 +2192,8 @@ describe("IgxCalendar - ", () => {
21962192
let calendarValue: Date[];
21972193

21982194
// range selection from June 13th to June 17th
2199-
UIInteractions.simulateMouseDownEvent(june13th.nativeElement.firstChild);
2200-
UIInteractions.simulateMouseDownEvent(june17th.nativeElement.firstChild);
2195+
UIInteractions.simulateClickAndSelectEvent(june13th.nativeElement.firstChild);
2196+
UIInteractions.simulateClickAndSelectEvent(june17th.nativeElement.firstChild);
22012197
fixture.detectChanges();
22022198

22032199
calendarValue = calendar.value as Date[];
@@ -2210,7 +2206,7 @@ describe("IgxCalendar - ", () => {
22102206
).toMatch(new Date(2017, 5, 17).toDateString());
22112207

22122208
// shorten the range to June 15th (June 13th - June 15th)
2213-
UIInteractions.simulateMouseDownEvent(june15th.nativeElement.firstChild, true);
2209+
UIInteractions.simulateClickAndSelectEvent(june15th.nativeElement.firstChild, true);
22142210
fixture.detectChanges();
22152211

22162212
calendarValue = calendar.value as Date[];
@@ -2220,7 +2216,7 @@ describe("IgxCalendar - ", () => {
22202216
).toMatch(new Date(2017, 5, 15).toDateString());
22212217

22222218
// extend the range to June 11th (June 11th - June 15th)
2223-
UIInteractions.simulateMouseDownEvent(june11th.nativeElement.firstChild, true);
2219+
UIInteractions.simulateClickAndSelectEvent(june11th.nativeElement.firstChild, true);
22242220
fixture.detectChanges();
22252221

22262222
calendarValue = calendar.value as Date[];
@@ -2233,7 +2229,7 @@ describe("IgxCalendar - ", () => {
22332229
).toMatch(new Date(2017, 5, 15).toDateString());
22342230

22352231
// shorten the range to June 13th (June 13th - June 15th)
2236-
UIInteractions.simulateMouseDownEvent(june13th.nativeElement.firstChild, true);
2232+
UIInteractions.simulateClickAndSelectEvent(june13th.nativeElement.firstChild, true);
22372233
fixture.detectChanges();
22382234

22392235
calendarValue = calendar.value as Date[];
@@ -2256,13 +2252,13 @@ describe("IgxCalendar - ", () => {
22562252
const june17th = days[16];
22572253

22582254
// select June 13th and June 15th
2259-
UIInteractions.simulateMouseDownEvent(june13th.nativeElement.firstChild);
2260-
UIInteractions.simulateMouseDownEvent(june15th.nativeElement.firstChild);
2255+
UIInteractions.simulateClickAndSelectEvent(june13th.nativeElement.firstChild);
2256+
UIInteractions.simulateClickAndSelectEvent(june15th.nativeElement.firstChild);
22612257
fixture.detectChanges();
22622258
expect((calendar.value as Date[]).length).toEqual(2);
22632259

22642260
// select all dates from June 15th to June 17th
2265-
UIInteractions.simulateMouseDownEvent(june17th.nativeElement.firstChild, true);
2261+
UIInteractions.simulateClickAndSelectEvent(june17th.nativeElement.firstChild, true);
22662262
fixture.detectChanges();
22672263
expect((calendar.value as Date[]).length).toEqual(4);
22682264

@@ -2278,7 +2274,7 @@ describe("IgxCalendar - ", () => {
22782274
);
22792275

22802276
// select all dates from June 17th (last selected) to June 11th
2281-
UIInteractions.simulateMouseDownEvent(june11th.nativeElement.firstChild, true);
2277+
UIInteractions.simulateClickAndSelectEvent(june11th.nativeElement.firstChild, true);
22822278
fixture.detectChanges();
22832279
expect((calendar.value as Date[]).length).toEqual(7);
22842280

@@ -2320,17 +2316,17 @@ describe("IgxCalendar - ", () => {
23202316
expect((calendar.value as Date[]).length).toEqual(7);
23212317

23222318
// deselect all dates from June 11th (last clicked) to June 13th
2323-
UIInteractions.simulateMouseDownEvent(june11th.nativeElement.firstChild);
2324-
UIInteractions.simulateMouseDownEvent(june13th.nativeElement.firstChild, true);
2319+
UIInteractions.simulateClickAndSelectEvent(june11th.nativeElement.firstChild);
2320+
UIInteractions.simulateClickAndSelectEvent(june13th.nativeElement.firstChild, true);
23252321
fixture.detectChanges();
23262322
expect((calendar.value as Date[]).length).toEqual(5);
23272323
expect(JSON.stringify(calendar.value as Date[])).toEqual(
23282324
JSON.stringify(dates.slice(2)),
23292325
);
23302326

23312327
// deselect all dates from June 17th (last clicked) to June 15th
2332-
UIInteractions.simulateMouseDownEvent(june17th.nativeElement.firstChild);
2333-
UIInteractions.simulateMouseDownEvent(june15th.nativeElement.firstChild, true);
2328+
UIInteractions.simulateClickAndSelectEvent(june17th.nativeElement.firstChild);
2329+
UIInteractions.simulateClickAndSelectEvent(june15th.nativeElement.firstChild, true);
23342330
fixture.detectChanges();
23352331
expect((calendar.value as Date[]).length).toEqual(3);
23362332
expect(JSON.stringify(calendar.value as Date[])).toEqual(

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

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -518,24 +518,19 @@ export class IgxCalendarComponent extends IgxCalendarBaseDirective implements Af
518518
});
519519
}
520520

521-
private onWrapperFocus(event: FocusEvent) {
522-
event.stopPropagation();
523-
521+
private onWrapperFocus(_event: FocusEvent) {
524522
this.showActiveDay = true;
525523
this.monthViews.forEach(view => view.changePreviewRange(this.activeDate));
526524
}
527525

528-
private onWrapperBlur(event: FocusEvent) {
529-
event.stopPropagation();
530-
526+
private onWrapperBlur(_event: FocusEvent) {
531527
this.showActiveDay = false;
532528
this.monthViews.forEach(view => view.clearPreviewRange());
533529
this._onTouchedCallback();
534530
}
535531

536532
private handleArrowKeydown(event: KeyboardEvent, delta: number) {
537533
event.preventDefault();
538-
event.stopPropagation();
539534

540535
const date = getClosestActiveDate(
541536
CalendarDay.from(this.activeDate),
@@ -556,7 +551,6 @@ export class IgxCalendarComponent extends IgxCalendarBaseDirective implements Af
556551

557552
private handlePageUpDown(event: KeyboardEvent, delta: number) {
558553
event.preventDefault();
559-
event.stopPropagation();
560554

561555
const dir = delta > 0 ? ScrollDirection.NEXT : ScrollDirection.PREV;
562556

@@ -638,8 +632,6 @@ export class IgxCalendarComponent extends IgxCalendarBaseDirective implements Af
638632
}
639633

640634
private onEnter(event: KeyboardEvent) {
641-
event.stopPropagation();
642-
643635
if (this.activeView === IgxCalendarView.Month) {
644636
this.handleDateSelection(this.activeDate);
645637
this.cdr.detectChanges();
@@ -657,8 +649,6 @@ export class IgxCalendarComponent extends IgxCalendarBaseDirective implements Af
657649
}
658650

659651
private onHome(event: KeyboardEvent) {
660-
event.stopPropagation();
661-
662652
if (this.activeView === IgxCalendarView.Month) {
663653
const dates = this.monthViews.toArray()
664654
.flatMap((view) => view.dates.toArray())
@@ -678,8 +668,6 @@ export class IgxCalendarComponent extends IgxCalendarBaseDirective implements Af
678668
}
679669

680670
private onEnd(event: KeyboardEvent) {
681-
event.stopPropagation();
682-
683671
if (this.activeView === IgxCalendarView.Month) {
684672
const dates = this.monthViews.toArray()
685673
.flatMap((view) => view.dates.toArray())

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
[hideLeadingDays]="hideLeadingDays"
7474
[hideTrailingDays]="hideTrailingDays"
7575
[attr.tabindex]="-1"
76-
(mouseDown)="handleDateClick(item)"
76+
(click)="handleDateClick(item)"
7777
(mouseEnter)="changePreviewRange(day.native)"
7878
(mouseLeave)="clearPreviewRange()"
7979
>

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ describe("Days View Component", () => {
310310
),
311311
);
312312

313-
UIInteractions.simulateMouseDownEvent(day.nativeElement.firstChild);
313+
UIInteractions.simulateClickAndSelectEvent(day.nativeElement.firstChild);
314314
fixture.detectChanges();
315315

316316
expect(instance.dateSelected.emit).toHaveBeenCalledWith(
@@ -331,7 +331,7 @@ describe("Days View Component", () => {
331331
By.css(".igx-days-view__date--inactive"),
332332
);
333333

334-
UIInteractions.simulateMouseDownEvent(
334+
UIInteractions.simulateClickAndSelectEvent(
335335
days.at(0).nativeElement.firstChild,
336336
);
337337
fixture.detectChanges();
@@ -346,7 +346,7 @@ describe("Days View Component", () => {
346346
By.css(".igx-days-view__date--inactive"),
347347
);
348348

349-
UIInteractions.simulateMouseDownEvent(
349+
UIInteractions.simulateClickAndSelectEvent(
350350
days.at(-1).nativeElement.firstChild,
351351
);
352352
fixture.detectChanges();

projects/igniteui-angular/src/lib/date-common/picker-base.directive.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ export abstract class PickerBaseDirective extends DisplayDensityBase implements
256256
protected _minValue: Date | string;
257257
protected _maxValue: Date | string;
258258
protected _weekStart: WEEKDAYS | number;
259+
protected abstract get toggleContainer(): HTMLElement | undefined;
259260

260261
/**
261262
* Gets the picker's pop-up state.
@@ -274,6 +275,18 @@ export abstract class PickerBaseDirective extends DisplayDensityBase implements
274275
return this.mode === PickerInteractionMode.DropDown;
275276
}
276277

278+
/**
279+
* Returns if there's focus within the picker's element OR popup container
280+
* @hidden @internal
281+
*/
282+
public get isFocused(): boolean {
283+
const document = this.element.nativeElement?.getRootNode() as Document | ShadowRoot;
284+
if (!document?.activeElement) return false;
285+
286+
return this.element.nativeElement.contains(document.activeElement)
287+
|| !this.collapsed && this.toggleContainer.contains(document.activeElement);
288+
}
289+
277290
protected _destroy$ = new Subject<void>();
278291

279292
// D.P. EventEmitter<string | Date | DateRange | null> throws on strict checks for more restrictive overrides

0 commit comments

Comments
 (0)